diff --git a/.fvmrc b/.fvmrc index 94d87f3405..de1495ac7b 100644 --- a/.fvmrc +++ b/.fvmrc @@ -1,3 +1,3 @@ { - "flutter": "3.41.7" + "flutter": "3.44.4" } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0abc7379ee..1f016b6e52 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,10 +26,6 @@ on: - '.fvmrc' workflow_dispatch: -permissions: - id-token: write - contents: write - concurrency: group: ci-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true @@ -47,25 +43,29 @@ jobs: python_tests: name: Python ${{ matrix.python-version }} tests runs-on: ubuntu-latest + permissions: + contents: read strategy: fail-fast: false matrix: python-version: [ "3.10", "3.11", "3.12", "3.13", "3.14" ] steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: python-version: ${{ matrix.python-version }} + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Run tests shell: bash working-directory: ${{ env.SDK_PYTHON }} run: | - uv run --no-dev --group test pytest packages/flet/tests - uv run --no-dev --group test pytest packages/flet-cli/tests + uv run --no-dev --group test pytest packages/*/tests - name: Run docs-coverage if: matrix.python-version == '3.12' @@ -86,7 +86,7 @@ jobs: - name: Upload docs-coverage logs if: matrix.python-version == '3.12' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: docs-coverage path: sdk/python/docstr_coverage.log @@ -97,20 +97,27 @@ jobs: docs_build: name: Build Documentation runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: 20 + node-version: 24 + package-manager-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Enable Corepack run: corepack enable - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Build website run: | @@ -125,6 +132,7 @@ jobs: name: Build Flet Flutter package runs-on: ubuntu-latest permissions: + contents: read id-token: write # Required for authentication using OIDC outputs: PKG_VER: ${{ steps.versions.outputs.PKG_VER }} @@ -132,26 +140,29 @@ jobs: PYPI_VER: ${{ steps.versions.outputs.PYPI_VER }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 0 # fetch all history fetch-tags: true # ensure tags are available + persist-credentials: false - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Compute versions id: versions run: source "${SCRIPTS}/update_build_version.sh" - name: Setup Dart (OIDC for pub.dev) - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 + uses: dart-lang/setup-dart@65eb853c7ba17dde3be364c3d2858773e7144260 # v1.7.2 - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + uses: kuhnroyal/flutter-fvm-config-action/setup@c378498f1d1962d33039c3989411093ef8a17b2c # v3.3 with: path: '.fvmrc' - cache: true + cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Run tests shell: bash @@ -176,14 +187,20 @@ jobs: name: Package templates runs-on: ubuntu-latest needs: build_flet_package + permissions: + contents: read env: PKG_VER: ${{ needs.build_flet_package.outputs.PKG_VER }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Patch build template flet version shell: bash @@ -208,7 +225,7 @@ jobs: zip -r "$GITHUB_WORKSPACE/flet-app-templates.zip" app/ - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: template-artifacts path: | @@ -220,26 +237,32 @@ jobs: # ============================= build_windows: name: Build Flet Client for Windows - runs-on: windows-latest + runs-on: windows-2025-vs2026 needs: - python_tests - build_flet_package + permissions: + contents: read env: PKG_VER: ${{ needs.build_flet_package.outputs.PKG_VER }} BUILD_NUM: ${{ needs.build_flet_package.outputs.BUILD_NUM }} PYPI_VER: ${{ needs.build_flet_package.outputs.PYPI_VER }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + uses: kuhnroyal/flutter-fvm-config-action/setup@c378498f1d1962d33039c3989411093ef8a17b2c # v3.3 with: path: '.fvmrc' - cache: true + cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Build Flutter Windows client env: @@ -263,7 +286,7 @@ jobs: 7z a "${ROOT}/client/flet-windows.zip" "flet" - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: windows-artifacts if-no-files-found: error @@ -279,22 +302,28 @@ jobs: needs: - python_tests - build_flet_package + permissions: + contents: read env: PKG_VER: ${{ needs.build_flet_package.outputs.PKG_VER }} BUILD_NUM: ${{ needs.build_flet_package.outputs.BUILD_NUM }} PYPI_VER: ${{ needs.build_flet_package.outputs.PYPI_VER }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + uses: kuhnroyal/flutter-fvm-config-action/setup@c378498f1d1962d33039c3989411093ef8a17b2c # v3.3 with: path: '.fvmrc' - cache: true + cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Build Flutter macOS client shell: bash @@ -304,7 +333,7 @@ jobs: tar -czvf flet-macos.tar.gz -C build/macos/Build/Products/Release Flet.app - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: macos-artifacts if-no-files-found: error @@ -322,6 +351,8 @@ jobs: needs: - python_tests - build_flet_package + permissions: + contents: read strategy: matrix: include: @@ -443,23 +474,27 @@ jobs: apt-get install -y git curl unzip xz-utils zip ca-certificates jq tzdata - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Get Flutter version from ".fvmrc" - uses: kuhnroyal/flutter-fvm-config-action/config@v3 + uses: kuhnroyal/flutter-fvm-config-action/config@c378498f1d1962d33039c3989411093ef8a17b2c # v3.3 id: fvm-config-action with: path: '.fvmrc' - name: Setup Flutter - uses: subosito/flutter-action@v2 + uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0 with: flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} # https://github.com/subosito/flutter-action/issues/345#issuecomment-2657332687 - cache: true + cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Mark git safe directories shell: bash @@ -476,7 +511,7 @@ jobs: sed -i.bak '/apt.postgresql.org/s/^/# /' /etc/apt/sources.list fi apt-get update --allow-releaseinfo-change - LINUX_DEPS="$(uv run --project sdk/python/packages/flet python -c 'from flet.utils.linux_deps import linux_dependencies; print(" ".join(linux_dependencies))')" + LINUX_DEPS="$(uv run --project sdk/python/packages/flet-cli flet --version --json | jq -r '.linux_dependencies | join(" ")')" apt-get install -y $LINUX_DEPS - name: Build Flutter Linux clients @@ -537,7 +572,7 @@ jobs: build_flutter "flet-desktop" - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: linux-${{ matrix.distro_id }}-${{ matrix.arch }}-artifacts if-no-files-found: error @@ -553,20 +588,26 @@ jobs: needs: - python_tests - build_flet_package + permissions: + contents: read env: PYPI_VER: ${{ needs.build_flet_package.outputs.PYPI_VER }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + uses: kuhnroyal/flutter-fvm-config-action/setup@c378498f1d1962d33039c3989411093ef8a17b2c # v3.3 with: path: '.fvmrc' - cache: true + cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Patch Python and Flutter versions shell: bash @@ -579,7 +620,7 @@ jobs: shell: bash working-directory: ${{ env.SDK_PYTHON }} run: | - PYODIDE_VERSION="$( uv run python -c 'import flet.version; print(flet.version.pyodide_version)' )" + PYODIDE_VERSION="$( uv run python -c "from flet_cli.utils.python_versions import resolve_python_version; print(resolve_python_version(None).pyodide)" )" echo "PYODIDE_VERSION=$PYODIDE_VERSION" >> "$GITHUB_ENV" echo "Pyodide version: $PYODIDE_VERSION" @@ -587,10 +628,6 @@ jobs: shell: bash working-directory: client run: | - # Compute Pyodide URLs - PYODIDE_URL="https://github.com/pyodide/pyodide/releases/download/${PYODIDE_VERSION}/pyodide-core-${PYODIDE_VERSION}.tar.bz2" - PYODIDE_CDN_URL="https://cdn.jsdelivr.net/pyodide/v${PYODIDE_VERSION}/full" - FLET_WEB="${SDK_PYTHON}/packages/flet-web/src/flet_web" flutter build web --wasm @@ -601,13 +638,9 @@ jobs: FLUTTER_JS_DIR="$(dirname "$(command -v flutter)")/cache/flutter_web_sdk/flutter_js" cp "$FLUTTER_JS_DIR/flutter.js.map" "${FLET_WEB}/web" - # Download the Pyodide tarball and extract its contents into the web build folder - curl -L "$PYODIDE_URL" | tar -xj -C "${FLET_WEB}/web" - - # Download the prebuilt pyodide wheels - for wheel in "packaging-24.2-py3-none-any.whl" "micropip-0.8.0-py3-none-any.whl"; do - curl -L "${PYODIDE_CDN_URL}/${wheel}" -o "${FLET_WEB}/web/pyodide/${wheel}" - done + # Download the Pyodide runtime (plus the micropip/packaging wheels + # resolved from pyodide-lock.json) into the web build folder + uv run --project "${SDK_PYTHON}" python -c "from pathlib import Path; from flet_cli.utils.pyodide import ensure_pyodide; ensure_pyodide('${PYODIDE_VERSION}', Path('${FLET_WEB}/web/pyodide'))" # Archive the web client into a gzipped tarball tar -czvf "flet-web.tar.gz" -C "build/web" . @@ -622,7 +655,7 @@ jobs: uv build --package flet-web --sdist - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: web-artifacts if-no-files-found: error @@ -640,24 +673,29 @@ jobs: needs: - python_tests - build_flet_package + permissions: + contents: read env: PYPI_VER: ${{ needs.build_flet_package.outputs.PYPI_VER }} PKG_VER: ${{ needs.build_flet_package.outputs.PKG_VER }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + uses: kuhnroyal/flutter-fvm-config-action/setup@c378498f1d1962d33039c3989411093ef8a17b2c # v3.3 with: path: '.fvmrc' - cache: true + cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Analyze and Build Flutter & Python packages shell: bash @@ -704,7 +742,7 @@ jobs: done - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: flet-python-extensions if-no-files-found: error @@ -718,6 +756,8 @@ jobs: build_flet_cli_desktop: name: Build flet, flet-cli and flet-desktop Python packages runs-on: ubuntu-latest + permissions: + contents: read env: PYPI_VER: ${{ needs.build_flet_package.outputs.PYPI_VER }} needs: @@ -725,10 +765,14 @@ jobs: - build_flet_package steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Build Python packages shell: bash @@ -741,13 +785,56 @@ jobs: uv build --package flet-desktop - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: flet-cli-desktop-python-distribution path: | sdk/python/dist/*.whl sdk/python/dist/*.tar.gz + # ============== + # ============== + # Build flet-mcp + # ============== + build_flet_mcp: + name: Build flet-mcp Python package + runs-on: ubuntu-latest + env: + PYPI_VER: ${{ needs.build_flet_package.outputs.PYPI_VER }} + needs: + - python_tests + - build_flet_package + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Build MCP data + working-directory: ${{ env.SDK_PYTHON }} + run: | + uv run --group mcp-build flet mcp build \ + --examples examples \ + --output packages/flet-mcp/src/flet_mcp/data/ + + - name: Build Python package + working-directory: ${{ env.SDK_PYTHON }} + run: | + source "$SCRIPTS/common.sh" + patch_python_package_versions + patch_toml_versions "packages/flet-mcp/pyproject.toml" "$PYPI_VER" + uv build --package flet-mcp + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: flet-mcp-python-distribution + if-no-files-found: error + path: | + sdk/python/dist/*.whl + sdk/python/dist/*.tar.gz + # ============== # GitHub Release # ============== @@ -765,25 +852,30 @@ jobs: - build_templates - build_flet_extensions - build_flet_cli_desktop + - build_flet_mcp if: ${{ startsWith(github.ref, 'refs/tags/') }} + permissions: + contents: write steps: - name: Detect pre-release id: prerelease + env: + REF_NAME: ${{ github.ref_name }} run: | - if [[ "${{ github.ref_name }}" == *".dev"* ]]; then + if [[ "$REF_NAME" == *".dev"* ]]; then echo "is_prerelease=true" >> $GITHUB_OUTPUT else echo "is_prerelease=false" >> $GITHUB_OUTPUT fi - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: dist merge-multiple: true - name: Create/Update GitHub Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: @@ -808,15 +900,18 @@ jobs: if: startsWith(github.ref, 'refs/tags/') needs: - release + permissions: + id-token: write steps: - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 with: ignore-empty-workdir: true cache-dependency-glob: "" + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: dist merge-multiple: true @@ -848,6 +943,7 @@ jobs: flet_secure_storage \ flet_spinkit \ flet_video \ - flet_webview; do + flet_webview \ + flet_mcp; do uv publish dist/**/${pkg}-* done diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index eb1b594afd..ef60517074 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -3,24 +3,32 @@ name: Build docs on: workflow_dispatch: +permissions: + contents: read + jobs: build: name: Build Documentation runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: 20 + node-version: 24 + package-manager-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Enable Corepack run: corepack enable - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Build website run: | diff --git a/.github/workflows/flet-build-image.yml b/.github/workflows/flet-build-image.yml index f64a3f13ba..2b5052530b 100644 --- a/.github/workflows/flet-build-image.yml +++ b/.github/workflows/flet-build-image.yml @@ -11,10 +11,6 @@ on: type: boolean default: true -permissions: - contents: read - packages: write - env: IMAGE: ghcr.io/${{ github.repository_owner }}/flet-build @@ -22,17 +18,23 @@ jobs: resolve_version: name: Resolve Flutter version runs-on: ubuntu-latest + permissions: + contents: read outputs: flutter_version: ${{ steps.v.outputs.value }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Resolve version id: v + env: + FLUTTER_VERSION_INPUT: ${{ inputs.flutter_version }} run: | - if [ -n "${{ inputs.flutter_version }}" ]; then - v="${{ inputs.flutter_version }}" + if [ -n "$FLUTTER_VERSION_INPUT" ]; then + v="$FLUTTER_VERSION_INPUT" else v="$(jq -r .flutter .fvmrc)" fi @@ -51,11 +53,16 @@ jobs: - platform: linux/arm64 runner: ubuntu-24.04-arm runs-on: ${{ matrix.runner }} + permissions: + contents: read + packages: write env: FLUTTER_VERSION: ${{ needs.resolve_version.outputs.flutter_version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Compute platform pair id: pair @@ -64,10 +71,10 @@ jobs: echo "value=${p//\//-}" >> "$GITHUB_OUTPUT" - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 - name: Log in to GHCR - uses: docker/login-action@v3 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -75,7 +82,7 @@ jobs: - name: Build & push by digest id: build - uses: docker/build-push-action@v6 + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: context: docker/flet-build file: docker/flet-build/Dockerfile @@ -88,13 +95,15 @@ jobs: provenance: false - name: Export digest + env: + BUILD_DIGEST: ${{ steps.build.outputs.digest }} run: | mkdir -p /tmp/digests - digest="${{ steps.build.outputs.digest }}" + digest="$BUILD_DIGEST" touch "/tmp/digests/${digest#sha256:}" - name: Upload digest - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: flet-build-digests-${{ steps.pair.outputs.value }} path: /tmp/digests/* @@ -107,21 +116,23 @@ jobs: - resolve_version - build runs-on: ubuntu-latest + permissions: + packages: write env: FLUTTER_VERSION: ${{ needs.resolve_version.outputs.flutter_version }} steps: - name: Download digests - uses: actions/download-artifact@v4 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: /tmp/digests pattern: flet-build-digests-* merge-multiple: true - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 - name: Log in to GHCR - uses: docker/login-action@v3 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -139,8 +150,10 @@ jobs: - name: Create & push manifest working-directory: /tmp/digests + env: + TAG_FLAGS: ${{ steps.tags.outputs.flags }} run: | - docker buildx imagetools create ${{ steps.tags.outputs.flags }} \ + docker buildx imagetools create $TAG_FLAGS \ $(printf "${IMAGE}@sha256:%s " *) - name: Inspect image diff --git a/.github/workflows/flet-build-test-matrix.yml b/.github/workflows/flet-build-test-matrix.yml new file mode 100644 index 0000000000..8a5951789c --- /dev/null +++ b/.github/workflows/flet-build-test-matrix.yml @@ -0,0 +1,193 @@ +name: Flet Build Test (matrix) + +# Reusable workflow: runs the 14-target `flet build` matrix against a single +# bundled CPython release. Invoked from `flet-build-test.yml`, which calls it +# once per supported Python version so the UI groups jobs by version. + +on: + workflow_call: + inputs: + python_version: + description: "Bundled CPython short version (e.g. 3.13)." + type: string + required: true + extra_build_args: + description: "Extra CLI args appended to `flet build`." + type: string + default: "" + +env: + ROOT: "${{ github.workspace }}" + SDK_PYTHON: "${{ github.workspace }}/sdk/python" + SCRIPTS: "${{ github.workspace }}/.github/scripts" + UV_PYTHON: 3.12 + PYTHONUTF8: 1 + + # https://flet.dev/docs/reference/environment-variables + FLET_CLI_NO_RICH_OUTPUT: 1 + + FLET_BUILD_EXTRA_ARGS: ${{ inputs.extra_build_args }} + +jobs: + build: + name: Build (${{ matrix.name }}) + runs-on: ${{ matrix.runner }} + permissions: + contents: read + strategy: + fail-fast: false + matrix: + include: + # -------- Desktop -------- + - name: linux + runner: ubuntu-latest + build_cmd: "flet build linux" + artifact_name: linux-build-artifact + artifact_path: build/linux + needs_linux_deps: true + + - name: macos + runner: macos-26 + build_cmd: "flet build macos" + artifact_name: macos-build-artifact + artifact_path: build/macos + needs_linux_deps: false + + - name: windows + runner: windows-2025-vs2026 + build_cmd: "flet build windows" + artifact_name: windows-build-artifact + artifact_path: build/windows + needs_linux_deps: false + + # -------- Android -------- + - name: aab-ubuntu + runner: ubuntu-latest + build_cmd: "flet build aab" + artifact_name: aab-build-ubuntu-artifact + artifact_path: build/aab + needs_linux_deps: false + + - name: aab-macos + runner: macos-26 + build_cmd: "flet build aab" + artifact_name: aab-build-macos-artifact + artifact_path: build/aab + needs_linux_deps: false + + - name: aab-windows + runner: windows-2025-vs2026 + build_cmd: "flet build aab" + artifact_name: aab-build-windows-artifact + artifact_path: build/aab + needs_linux_deps: false + + - name: apk-ubuntu + runner: ubuntu-latest + build_cmd: "flet build apk" + artifact_name: apk-build-ubuntu-artifact + artifact_path: build/apk + needs_linux_deps: false + + - name: apk-macos + runner: macos-26 + build_cmd: "flet build apk" + artifact_name: apk-build-macos-artifact + artifact_path: build/apk + needs_linux_deps: false + + - name: apk-windows + runner: windows-2025-vs2026 + build_cmd: "flet build apk" + artifact_name: apk-build-windows-artifact + artifact_path: build/apk + needs_linux_deps: false + + # -------- iOS -------- + - name: ipa + runner: macos-26 + build_cmd: "flet build ipa" + artifact_name: ipa-build-artifact + artifact_path: build/ipa + needs_linux_deps: false + + - name: ios-simulator + runner: macos-26 + build_cmd: "flet build ios-simulator" + artifact_name: ios-simulator-build-artifact + artifact_path: build/ios-simulator + needs_linux_deps: false + + # -------- Web -------- + - name: web-ubuntu + runner: ubuntu-latest + build_cmd: "flet build web" + artifact_name: web-build-ubuntu-artifact + artifact_path: build/web + needs_linux_deps: false + + - name: web-macos + runner: macos-26 + build_cmd: "flet build web" + artifact_name: web-build-macos-artifact + artifact_path: build/web + needs_linux_deps: false + + - name: web-windows + runner: windows-2025-vs2026 + build_cmd: "flet build web" + artifact_name: web-build-windows-artifact + artifact_path: build/web + needs_linux_deps: false + + steps: + - name: Checkout repository + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + fetch-depth: 0 + fetch-tags: true + persist-credentials: false + + - name: Setup uv + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} + + - name: Patch versions + shell: bash + run: | + source "${SCRIPTS}/update_build_version.sh" + source "${SCRIPTS}/common.sh" + patch_python_package_versions + + - name: Install Linux dependencies + if: matrix.needs_linux_deps + shell: bash + run: | + sudo apt update --allow-releaseinfo-change + LINUX_DEPS="$(uv run --project sdk/python/packages/flet-cli flet --version --json | jq -r '.linux_dependencies | join(" ")')" + sudo apt-get install -y --no-install-recommends $LINUX_DEPS + sudo apt-get clean + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@c378498f1d1962d33039c3989411093ef8a17b2c # v3.3 + with: + path: '.fvmrc' + cache: ${{ !startsWith(github.ref, 'refs/tags/') }} + + - name: Build app + shell: bash + working-directory: sdk/python/examples/apps/flet_build_test + env: + PYTHON_VERSION: ${{ inputs.python_version }} + run: | + echo "FLET_BUILD_EXTRA_ARGS='${FLET_BUILD_EXTRA_ARGS}'" + uv run ${{ matrix.build_cmd }} --python-version "$PYTHON_VERSION" --yes --verbose --build-number ${{ github.run_number }} $FLET_BUILD_EXTRA_ARGS + + - name: Upload Artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: ${{ matrix.artifact_name }}-py${{ inputs.python_version }} + path: sdk/python/examples/apps/flet_build_test/${{ matrix.artifact_path }} + if-no-files-found: error + overwrite: false diff --git a/.github/workflows/flet-build-test.yml b/.github/workflows/flet-build-test.yml index b241c29e62..0bad46b1b9 100644 --- a/.github/workflows/flet-build-test.yml +++ b/.github/workflows/flet-build-test.yml @@ -2,10 +2,13 @@ name: Flet Build Test on: push: + tags-ignore: + - '**' branches-ignore: - main paths: - '.github/workflows/flet-build-test.yml' + - '.github/workflows/flet-build-test-matrix.yml' - '.fvmrc' - 'client/**' - 'sdk/python/packages/**' @@ -14,6 +17,7 @@ on: pull_request: paths: - '.github/workflows/flet-build-test.yml' + - '.github/workflows/flet-build-test-matrix.yml' - '.fvmrc' - 'client/**' - 'sdk/python/packages/**' @@ -21,6 +25,17 @@ on: - 'sdk/python/examples/apps/flet_build_test/**' workflow_dispatch: inputs: + python_version: + description: "Bundled Python version to test" + type: choice + required: true + default: all + options: + - all + - "3.12" + - "3.13" + - "3.14" + extra_build_args: description: "Extra CLI args appended to `flet build` command (ex: --template-ref 0.1.0)" required: false @@ -35,6 +50,9 @@ concurrency: group: ci-${{ github.workflow }}-${{ github.event.pull_request.head.ref || github.ref_name }} cancel-in-progress: true +permissions: + contents: read + env: ROOT: "${{ github.workspace }}" SDK_PYTHON: "${{ github.workspace }}/sdk/python" @@ -46,169 +64,43 @@ env: FLET_CLI_NO_RICH_OUTPUT: 1 # Extra args passed via workflow_dispatch (empty for push/PR) - FLET_BUILD_EXTRA_ARGS: ${{ github.event_name == 'workflow_dispatch' && inputs.extra_build_args || '' }} FLET_PACK_EXTRA_ARGS: ${{ github.event_name == 'workflow_dispatch' && inputs.extra_pack_args || '' }} jobs: - build: - name: Build (${{ matrix.name }}) - runs-on: ${{ matrix.runner }} - strategy: - fail-fast: false - matrix: - include: - # -------- Desktop -------- - - name: linux - runner: ubuntu-latest - build_cmd: "flet build linux" - artifact_name: linux-build-artifact - artifact_path: build/linux - needs_linux_deps: true - - - name: macos - runner: macos-26 - build_cmd: "flet build macos" - artifact_name: macos-build-artifact - artifact_path: build/macos - needs_linux_deps: false - - - name: windows - runner: windows-latest - build_cmd: "flet build windows" - artifact_name: windows-build-artifact - artifact_path: build/windows - needs_linux_deps: false - - # -------- Android -------- - - name: aab-ubuntu - runner: ubuntu-latest - build_cmd: "flet build aab" - artifact_name: aab-build-ubuntu-artifact - artifact_path: build/aab - needs_linux_deps: false - - - name: aab-macos - runner: macos-26 - build_cmd: "flet build aab" - artifact_name: aab-build-macos-artifact - artifact_path: build/aab - needs_linux_deps: false - - - name: aab-windows - runner: windows-latest - build_cmd: "flet build aab" - artifact_name: aab-build-windows-artifact - artifact_path: build/aab - needs_linux_deps: false - - - name: apk-ubuntu - runner: ubuntu-latest - build_cmd: "flet build apk" - artifact_name: apk-build-ubuntu-artifact - artifact_path: build/apk - needs_linux_deps: false - - - name: apk-macos - runner: macos-26 - build_cmd: "flet build apk" - artifact_name: apk-build-macos-artifact - artifact_path: build/apk - needs_linux_deps: false - - - name: apk-windows - runner: windows-latest - build_cmd: "flet build apk" - artifact_name: apk-build-windows-artifact - artifact_path: build/apk - needs_linux_deps: false - - # -------- iOS -------- - - name: ipa - runner: macos-26 - build_cmd: "flet build ipa" - artifact_name: ipa-build-artifact - artifact_path: build/ipa - needs_linux_deps: false - - - name: ios-simulator - runner: macos-26 - build_cmd: "flet build ios-simulator" - artifact_name: ios-simulator-build-artifact - artifact_path: build/ios-simulator - needs_linux_deps: false - - # -------- Web -------- - - name: web-ubuntu - runner: ubuntu-latest - build_cmd: "flet build web" - artifact_name: web-build-ubuntu-artifact - artifact_path: build/web - needs_linux_deps: false - - - name: web-macos - runner: macos-26 - build_cmd: "flet build web" - artifact_name: web-build-macos-artifact - artifact_path: build/web - needs_linux_deps: false - - - name: web-windows - runner: windows-latest - build_cmd: "flet build web" - artifact_name: web-build-windows-artifact - artifact_path: build/web - needs_linux_deps: false - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - fetch-tags: true - - - name: Setup uv - uses: astral-sh/setup-uv@v6 - - - name: Patch versions - shell: bash - run: | - source "${SCRIPTS}/update_build_version.sh" - source "${SCRIPTS}/common.sh" - patch_python_package_versions - - - name: Install Linux dependencies - if: matrix.needs_linux_deps - shell: bash - run: | - sudo apt update --allow-releaseinfo-change - LINUX_DEPS="$(uv run --project sdk/python/packages/flet python -c 'from flet.utils.linux_deps import linux_dependencies; print(" ".join(linux_dependencies))')" - sudo apt-get install -y --no-install-recommends $LINUX_DEPS - sudo apt-get clean - - - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 - with: - path: '.fvmrc' - cache: true - - - name: Build app - shell: bash - working-directory: sdk/python/examples/apps/flet_build_test - run: | - echo "FLET_BUILD_EXTRA_ARGS='${FLET_BUILD_EXTRA_ARGS}'" - uv run ${{ matrix.build_cmd }} --yes --verbose --build-number ${{ github.run_number }} $FLET_BUILD_EXTRA_ARGS - - - name: Upload Artifact - uses: actions/upload-artifact@v5.0.0 - with: - name: ${{ matrix.artifact_name }} - path: sdk/python/examples/apps/flet_build_test/${{ matrix.artifact_path }} - if-no-files-found: error - overwrite: false + # The build matrix is split into one reusable-workflow call per supported + # bundled CPython release. This makes the Actions UI group jobs by Python + # version (each call renders as its own "Matrix: build" card) and lets + # `workflow_dispatch` target a single version via the `python_version` + # input. push/pull_request runs always fire all three. + build-3-12: + if: github.event_name != 'workflow_dispatch' || inputs.python_version == 'all' || inputs.python_version == '3.12' + name: Python 3.12 + uses: ./.github/workflows/flet-build-test-matrix.yml + with: + python_version: "3.12" + extra_build_args: ${{ github.event_name == 'workflow_dispatch' && inputs.extra_build_args || '' }} + + build-3-13: + if: github.event_name != 'workflow_dispatch' || inputs.python_version == 'all' || inputs.python_version == '3.13' + name: Python 3.13 + uses: ./.github/workflows/flet-build-test-matrix.yml + with: + python_version: "3.13" + extra_build_args: ${{ github.event_name == 'workflow_dispatch' && inputs.extra_build_args || '' }} + + build-3-14: + if: github.event_name != 'workflow_dispatch' || inputs.python_version == 'all' || inputs.python_version == '3.14' + name: Python 3.14 + uses: ./.github/workflows/flet-build-test-matrix.yml + with: + python_version: "3.14" + extra_build_args: ${{ github.event_name == 'workflow_dispatch' && inputs.extra_build_args || '' }} pack: name: Pack (${{ matrix.name }}) runs-on: ${{ matrix.runner }} + permissions: + contents: read env: FLET_DESKTOP_FLAVOR: full strategy: @@ -222,23 +114,26 @@ jobs: runner: macos-26 - name: windows - runner: windows-latest + runner: windows-2025-vs2026 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + uses: kuhnroyal/flutter-fvm-config-action/setup@c378498f1d1962d33039c3989411093ef8a17b2c # v3.3 with: path: '.fvmrc' - cache: true + cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Patch versions shell: bash @@ -252,7 +147,7 @@ jobs: shell: bash run: | sudo apt update --allow-releaseinfo-change - LINUX_DEPS="$(uv run --project sdk/python/packages/flet python -c 'from flet.utils.linux_deps import linux_dependencies; print(" ".join(linux_dependencies))')" + LINUX_DEPS="$(uv run --project sdk/python/packages/flet-cli flet --version --json | jq -r '.linux_dependencies | join(" ")')" sudo apt-get install -y --no-install-recommends $LINUX_DEPS sudo apt-get clean @@ -300,7 +195,7 @@ jobs: uv run --with pyinstaller flet pack src/main.py --yes --name flet-pack-test --distpath dist $FLET_PACK_EXTRA_ARGS - name: Upload Artifact - uses: actions/upload-artifact@v5.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: ${{ matrix.name }}-pack-artifact path: sdk/python/examples/apps/flet_build_test/dist diff --git a/.github/workflows/flet-test.yml b/.github/workflows/flet-test.yml new file mode 100644 index 0000000000..a55c0b3b0c --- /dev/null +++ b/.github/workflows/flet-test.yml @@ -0,0 +1,215 @@ +name: Flet Test (on-device) + +# Runs `flet test` end-to-end on every target: provisions a per-platform test +# host (build pipeline in test_mode), launches the built Counter app with embedded +# Python, and drives it over the socket tester channel. Unlike +# macos-integration-tests.yml (host-mode screenshots) and flet-build-test.yml +# (compile only), this actually runs the app on the device/emulator/simulator. + +on: + push: + tags-ignore: + - '**' + branches-ignore: + - main + paths: + - '.github/workflows/flet-test.yml' + - '.fvmrc' + - 'packages/flet/**' + - 'packages/flet_integration_test/**' + - 'sdk/python/packages/flet/**' + - 'sdk/python/packages/flet-cli/**' + - 'sdk/python/examples/apps/flet_test_counter/**' + pull_request: + paths: + - '.github/workflows/flet-test.yml' + - '.fvmrc' + - 'packages/flet/**' + - 'packages/flet_integration_test/**' + - 'sdk/python/packages/flet/**' + - 'sdk/python/packages/flet-cli/**' + - 'sdk/python/examples/apps/flet_test_counter/**' + workflow_dispatch: + +# Ensure only one run per branch (PR or push), cancel older ones +concurrency: + group: flet-test-${{ github.workflow }}-${{ github.event.pull_request.head.ref || github.ref_name }} + cancel-in-progress: true + +env: + ROOT: "${{ github.workspace }}" + SDK_PYTHON: "${{ github.workspace }}/sdk/python" + SCRIPTS: "${{ github.workspace }}/.github/scripts" + APP_DIR: "sdk/python/examples/apps/flet_test_counter" + + # Host venv (runs flet-cli + pytest). The *embedded* app runtime is built + # against the matrix python version via `--python-version`; the host stays on + # 3.13 for stable test-dependency wheels (numpy/pillow/scikit-image). + UV_PYTHON: "3.13" + PYTHONUTF8: 1 + + # https://flet.dev/docs/reference/environment-variables + FLET_CLI_NO_RICH_OUTPUT: 1 + # Use the Flutter the setup action puts on PATH, not fvm. + FLET_TEST_DISABLE_FVM: 1 + +jobs: + flet-test: + name: ${{ matrix.platform }} (py${{ matrix.python_version }}) + runs-on: ${{ matrix.runner }} + # The embedded runtime is built against the matrix python version; the test + # also asserts the running app reports it (EXPECTED_PYTHON_VERSION). + env: + PYTHON_VERSION: ${{ matrix.python_version }} + EXPECTED_PYTHON_VERSION: ${{ matrix.python_version }} + # Cap the job so a wedged emulator/simulator (which can hang the on-device + # test indefinitely) auto-cancels instead of burning a full runner slot. + timeout-minutes: 40 + strategy: + fail-fast: false + matrix: + python_version: ["3.12", "3.13", "3.14"] + platform: [macos, ios, windows, linux, linux-arm64, android] + include: + - platform: macos + runner: macos-26 + test_cmd: uv run flet test macos --python-version ${PYTHON_VERSION} --yes -v + + - platform: ios + runner: macos-26 + test_cmd: uv run flet test ios -d "$IOS_UDID" --python-version ${PYTHON_VERSION} --yes -v + + - platform: windows + runner: windows-2025-vs2026 + test_cmd: uv run flet test windows --python-version ${PYTHON_VERSION} --yes -v + + - platform: linux + runner: ubuntu-latest + test_cmd: xvfb-run -a uv run flet test linux --python-version ${PYTHON_VERSION} --yes -v + + # arm64 Linux: no kuhnroyal/Flutter action (Flutter ships no prebuilt + # arm64 Linux SDK) — `flet test` installs Flutter itself via a git + # clone of the SDK, exercising flet-cli's arm64 Linux install path. + - platform: linux-arm64 + runner: ubuntu-24.04-arm + test_cmd: xvfb-run -a uv run flet test linux --python-version ${PYTHON_VERSION} --yes -v + + - platform: android + runner: ubuntu-latest + # Run command lives in the emulator-runner step below. + test_cmd: "" + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Setup uv + uses: astral-sh/setup-uv@v8.2.0 + + - name: Patch versions + shell: bash + run: | + source "${SCRIPTS}/update_build_version.sh" + source "${SCRIPTS}/common.sh" + patch_python_package_versions + + # arm64 Linux gets no prebuilt Flutter SDK — `flet test` installs it. + - name: Setup Flutter + if: matrix.platform != 'linux-arm64' + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Show tool versions + shell: bash + run: | + uv --version + uv run --project sdk/python/packages/flet-cli python --version + flutter --version || echo "Flutter not on PATH yet (flet test will install it)." + + # -------- Linux: build deps + virtual display (x64 and arm64) -------- + - name: Install Linux dependencies + if: startsWith(matrix.platform, 'linux') + shell: bash + run: | + sudo apt-get update --allow-releaseinfo-change + LINUX_DEPS="$(uv run --project sdk/python/packages/flet-cli flet --version --json | jq -r '.linux_dependencies | join(" ")')" + # xvfb has no GPU; the Flutter GTK app needs Mesa's software GL + # (llvmpipe) or it crashes on GL context creation (exit 79). + sudo apt-get install -y --no-install-recommends \ + $LINUX_DEPS xvfb libgl1-mesa-dri + sudo apt-get clean + + # -------- iOS: boot a simulator, capture its UDID -------- + - name: Boot iOS simulator + if: matrix.platform == 'ios' + shell: bash + run: | + UDID=$(xcrun simctl list devices available -j \ + | jq -r '[.devices[][] | select(.name | startswith("iPhone"))][0].udid') + if [ -z "$UDID" ] || [ "$UDID" = "null" ]; then + echo "No available iPhone simulator found" >&2 + xcrun simctl list devices available + exit 1 + fi + echo "Using iOS simulator $UDID" + xcrun simctl boot "$UDID" || true + xcrun simctl bootstatus "$UDID" -b + echo "IOS_UDID=$UDID" >> "$GITHUB_ENV" + + # -------- Android: enable KVM for a fast emulator -------- + - name: Enable KVM + if: matrix.platform == 'android' + shell: bash + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' \ + | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + # -------- Run: desktop + iOS (non-Android) -------- + - name: Run flet test (${{ matrix.platform }}) + if: matrix.platform != 'android' + shell: bash + working-directory: ${{ env.APP_DIR }} + # Force Mesa software GL on Linux (xvfb has no GPU); harmless elsewhere. + env: + LIBGL_ALWAYS_SOFTWARE: "true" + GALLIUM_DRIVER: llvmpipe + run: ${{ matrix.test_cmd }} + + # -------- Run: Android (inside the emulator) -------- + - name: Run flet test (android) + if: matrix.platform == 'android' + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 35 + arch: x86_64 + target: google_apis + force-avd-creation: true + disable-animations: true + emulator-options: -no-snapshot -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim + working-directory: ${{ env.APP_DIR }} + # Single folded line => one shell, so the test command is the last + # statement and ITS exit code is the job's (no false green). A trap + # writes a filtered device log (embedded Python + native crashes only, + # everything else silenced) to a file on exit — uploaded as an + # artifact below instead of flooding the console. + script: >- + adb logcat -G 16M || true ; + adb logcat -c || true ; + trap 'adb logcat -d -v time flet.python:V python:V AndroidRuntime:E DEBUG:F libc:F "*:S" > "$RUNNER_TEMP/android-logcat.txt" 2>&1 || true' EXIT ; + uv run flet test android -d emulator-5554 --python-version ${PYTHON_VERSION} --yes -v + + # Upload the device log as an artifact (don't stream it to the console). + - name: Upload android logcat + if: always() && matrix.platform == 'android' + uses: actions/upload-artifact@v4 + with: + name: android-logcat + path: ${{ runner.temp }}/android-logcat.txt + if-no-files-found: ignore diff --git a/.github/workflows/macos-integration-tests.yml b/.github/workflows/macos-integration-tests.yml index 396e5f1be5..a825c5f2d3 100644 --- a/.github/workflows/macos-integration-tests.yml +++ b/.github/workflows/macos-integration-tests.yml @@ -2,6 +2,8 @@ name: macOS Integration Tests on: push: + tags-ignore: + - '**' branches-ignore: - main paths: @@ -35,6 +37,8 @@ env: jobs: test-macos: runs-on: macos-26 + permissions: + contents: read strategy: fail-fast: false matrix: @@ -55,16 +59,20 @@ jobs: name: ${{ matrix.suite }} Integration Tests steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false - name: Setup uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + enable-cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Setup Flutter - uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + uses: kuhnroyal/flutter-fvm-config-action/setup@c378498f1d1962d33039c3989411093ef8a17b2c # v3.3 with: path: '.fvmrc' - cache: true + cache: ${{ !startsWith(github.ref, 'refs/tags/') }} - name: Show tool versions run: | @@ -91,7 +99,7 @@ jobs: - name: Upload artifact if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: integration-test-failures-macos-${{ env.SAFE_SUITE }} path: sdk/python/packages/flet/integration_tests/${{ matrix.suite }}/**/*_actual.png diff --git a/.github/workflows/release-pr-changelog.yml b/.github/workflows/release-pr-changelog.yml index f3b6d4aea8..084bde013f 100644 --- a/.github/workflows/release-pr-changelog.yml +++ b/.github/workflows/release-pr-changelog.yml @@ -18,11 +18,14 @@ jobs: changelog_record: name: Require changelog record runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 0 + persist-credentials: false - name: Verify root changelog update shell: bash diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 0000000000..e9ba32c042 --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,28 @@ +name: zizmor - GitHub Actions Security Analysis + +on: + push: + pull_request: + +permissions: {} + +jobs: + zizmor: + name: Run zizmor + runs-on: ubuntu-latest + permissions: + security-events: write + contents: read + steps: + - name: Checkout + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false + + - name: Run zizmor + uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6 + with: + # Fork PRs get a read-only token (no security-events: write), so the + # SARIF upload would fail. Skip it for forks — they still get inline + # annotations; pushes and same-repo PRs upload to code scanning. + advanced-security: ${{ github.event.pull_request.head.repo.fork != true }} diff --git a/.gitignore b/.gitignore index 21e338bbec..6795b1796a 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,6 @@ vendor/ /client/android/app/.cxx client/devtools_options.yaml /.claude/worktrees + +# Actual screenshots written by failed golden comparisons in integration tests +*_actual.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ecd16f4d6..3ac38efc16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,65 @@ +## 0.86.0 + +### New features + +* Add support for **Python `multiprocessing` in packaged Flet desktop apps** built with `flet build macos`, `flet build windows`, and `flet build linux`. `multiprocessing` APIs such as `Process`, `ProcessPoolExecutor`, the `spawn`/`forkserver` start methods, and the resource tracker now work in packaged desktop apps. Previously, worker processes re-executed `sys.executable`, which pointed to the app binary itself, causing each worker to launch another GUI app instance and hang. Flet desktop runners now detect CPython multiprocessing child command lines before Flutter starts and divert them to a headless embedded Python interpreter via `dart_bridge` 1.5.0+. The Python bootstrap also runs the app module as the real `sys.modules["__main__"]` with `python -m` semantics, so top-level worker functions in `main.py` can be pickled correctly. When using `multiprocessing`, your app must follow normal Python multiprocessing rules: guard `ft.run(...)` with `if __name__ == "__main__":`, define worker functions at module top level, and do not access Flet UI objects from worker processes. See the new [Multiprocessing](https://docs.flet.dev/cookbook/multiprocessing) cookbook page. Mobile platforms remain unsupported because iOS and Android do not allow apps to spawn arbitrary child processes ([#4283](https://github.com/flet-dev/flet/issues/4283), [#6577](https://github.com/flet-dev/flet/pull/6662)) by @ndonkoHenri. +* Multi-version bundled CPython support in `flet build` and `flet publish`. Pick the runtime your app ships with via the new `--python-version` flag (3.12 / 3.13 / 3.14), or let it be derived from `[project].requires-python` in your `pyproject.toml`; defaults to the latest supported stable (currently 3.14). The matching CPython-standalone build, Pyodide release (0.27.7 / 0.29.4 / 314.0.1), and Emscripten wheel platform tag are all resolved from `flet-dev/python-build`'s date-keyed manifest. Adding a future pre-release CPython line (e.g. 3.15 beta) is a one-row append with `prerelease=True` — opt-in only via an explicit `--python-version 3.15` or `requires-python = "==3.15.*"`, never the auto-resolved default. Requires `serious_python` >= 4.0.0, now pinned in the `flet build` template. See the new [Choosing a Python version](https://flet.dev/docs/publish#choosing-a-python-version) docs section ([#6577](https://github.com/flet-dev/flet/pull/6577)) by @FeodorFitsner. +* Add `ft.DataChannel`: dedicated byte channels for widgets that move bulk binary data (image frames, audio buffers, ML tensors) between Dart and Python, bypassing the MsgPack control protocol. The Dart side opens a channel via `FletBackend.of(context).openDataChannel()` and announces it to Python by firing a `data_channel_open` control event with `{channel_name, channel_id}`; the Python side declares `on_data_channel_open: Optional[ft.EventHandler[ft.DataChannelOpenEvent]]` and captures the channel via `self.get_data_channel(e.channel_id)`. Backed by a dedicated `PythonBridge` per channel in embedded native mode (4–7 GiB/s on M2 Pro) and by the default `ProtocolMuxedDataChannelFactory` in dev / web modes (raw-byte frames muxed over the active Flet protocol transport with a 1-byte type discriminator). Pyodide gets zero-copy outbound sends via `postMessage` Transferable ArrayBuffer. First consumer: `flet-charts` `MatplotlibChartCanvas`, migrated from `_invoke_method` PNG dispatch to a 1-byte-opcode data channel by @FeodorFitsner. +* **In-process Python transport (`dart_bridge` FFI).** `package:flet` gains a third protocol transport alongside the UDS / TCP socket servers: it can run Flet's MsgPack protocol over an in-process `dart_bridge` byte channel via a `FletApp(channelBuilder: …)` seam (the `flet` package stays Python-independent — it doesn't depend on `serious_python` or know about `PythonBridge`; the embedder wires the channel). `serious_python` >= 3.0.0 uses this seam to embed the Python interpreter **in-process** instead of talking to it over a localhost socket, and the `flet build` template migrates from sockets to the FFI transport. On Android, where the OS may keep the process alive across a back-button quit and restart only the Dart VM, the transport rebinds to the new VM's `dart_bridge` ports on a session-restart signal (`libdart_bridge` >= 1.3.0) — the Python process and its in-memory state are preserved and the Flet session is rebuilt from `REGISTER_CLIENT` by @FeodorFitsner. +* Add `flet clean` command that deletes the `build` directory of a Flet app — the Flutter bootstrap project, cached artifacts, and generated output — in a single step ([#6233](https://github.com/flet-dev/flet/issues/6233)) by @ndonkoHenri. +* Add `compression_quality` to `FilePicker.pick_files()` for selecting the image compression quality used by supported platforms ([#6573](https://github.com/flet-dev/flet/pull/6573)) by @ndonkoHenri. +* Add `ConsentManager` to `flet-ads` for gathering user consent (e.g. GDPR/EEA) via Google's User Messaging Platform (UMP) before requesting ads ([#6569](https://github.com/flet-dev/flet/issues/6569), [#6615](https://github.com/flet-dev/flet/pull/6615)) by @ndonkoHenri. +* Add `ft.RawImage`: a high-bandwidth pixel-frame display control for Pillow output, NumPy arrays, camera frames and procedural graphics. Frames stream over a dedicated `ft.DataChannel` instead of the control protocol: raw premultiplied RGBA straight to a GPU texture on local transports (desktop, `flet run`, Pyodide), automatic PNG fallback on remote `flet-web` sessions. The awaitable `render(pil_or_numpy)` / `render_rgba(w, h, bytes)` / `render_encoded(png_jpeg_webp_bytes)` methods resolve when the client has displayed the frame, so a plain `while True: await ri.render(...)` loop self-paces to display speed. Premultiplied-alpha conversion runs in Pillow's C loops with an opaque fast-path; Pillow and NumPy remain optional. The last frame is retained and replayed on remount, mirroring `Image.src`. Ships with five gallery examples (photo viewer, plasma, Pillow paint, Mandelbrot explorer, Game of Life) and a [docs page](https://flet.dev/docs/controls/rawimage) with `RawImage` vs `Image` guidance ([#6674](https://github.com/flet-dev/flet/pull/6674)) by @FeodorFitsner. + +### Improvements + +* **Swift Package Manager for iOS/macOS builds (on by default).** `flet build` / `flet debug` now integrate the embedded Python runtime via SPM instead of CocoaPods (CocoaPods goes read-only in December 2026). Flet **auto-falls back to CocoaPods** when the app depends on a package that isn't SPM-ready — currently `flet-video` (media_kit) — since Flutter then builds the whole app with CocoaPods. Force CocoaPods for other non-SPM packages with `--no-swift-package-manager` (or `swift_package_manager = false` under `[tool.flet]`). Flet does **not** change Flutter's global SPM configuration; the setting only selects how `serious_python` stages the runtime to match. When SPM is used (it has no `pod install` hook), `flet build` sets `SERIOUS_PYTHON_DARWIN_SPM` so `serious_python`'s `package` step stages the runtime (Python/dart_bridge xcframeworks, the iOS native extensions, and the stdlib/site-packages/app resources) into the plugin's `Package.swift` layout on the host before `flutter build`, and exports the `SP_NATIVE_SET` cache-bust key into the build. Requires the SPM-capable `serious_python` release. +* **Smaller Android apps with no native-packaging config.** `flet build apk`/`aab` consume serious_python's new Android packaging: Python extension modules load **memory-mapped directly from the APK** (no extraction to disk), and pure Python ships in stored asset zips read via `zipimport`, so the standard library is no longer duplicated per ABI. Apps no longer need `useLegacyPackaging` / `keepDebugSymbols` — the `flet build` Android template drops them; just use `minSdk 23+`. New `--android-extract-packages` flag and `[tool.flet.android].extract_packages` ship "path-hungry" packages — those that read bundled data via `__file__` / `pkg_resources` instead of `importlib.resources` — extracted to disk instead of inside the zip (most packages, including `certifi`, are zip-safe and need no entry). Requires `serious_python` with the native-mmap packaging (dart_bridge 1.4.0). +* Pyodide is no longer pre-baked into the `flet build` template. Each `flet build web` / `flet publish` run downloads the matching `pyodide-core-.tar.bz2` (plus the runtime `micropip` and `packaging` wheels) into a per-version cache at `~/.flet/pyodide//` and copies the files into the build output. Subsequent builds reuse the cache; the older `0.27.5` bundle previously shipped in the cookiecutter template is gone ([#6577](https://github.com/flet-dev/flet/pull/6577)) by @FeodorFitsner. +* The supported Python / Pyodide / dart_bridge versions are loaded on demand from `flet-dev/python-build`'s date-keyed `manifest.json` (fetched once and cached under `~/.flet/cache`), the single source of truth shared with `serious_python` — replacing flet's hand-mirrored version table. `flet build` forwards only `SERIOUS_PYTHON_VERSION` and lets `serious_python` derive the full version / build date / dart_bridge version from its own committed snapshot. The module exposes `get_supported_python_versions()` / `get_default_python_version()` (the previous `SUPPORTED_PYTHON_VERSIONS` / `DEFAULT_PYTHON_VERSION` constants are removed) ([#6577](https://github.com/flet-dev/flet/pull/6577)) by @FeodorFitsner. +* `flet --version` shows just the Flet and Flutter versions; the static `Pyodide: …` line and the global `flet.version.pyodide_version` export are removed (the supported Python / Pyodide set now lives in python-build's manifest, not the CLI output) ([#6577](https://github.com/flet-dev/flet/pull/6577)) by @FeodorFitsner. +* `flet --version --json` emits a machine-readable document — Flet/Flutter versions and the Linux build dependencies — for CI to read via `jq` instead of importing Flet internals with `python -c`. (The supported Python/Pyodide table is no longer included; it comes from python-build's manifest.) The canonical Linux apt dependency list moved from `flet.utils.linux_deps` (runtime package) to `flet_cli.utils.linux_deps` (build tooling) by @FeodorFitsner. +* `client/web/python.js` and the build template's `python.js` no longer hardcode `defaultPyodideUrl`. `patch_index.py` now injects `flet.pyodideUrl` per build (CDN URL by default, or the local `pyodide/pyodide.js` path under `--no-cdn`) so the runtime URL always tracks the resolved Pyodide release ([#6577](https://github.com/flet-dev/flet/pull/6577)) by @FeodorFitsner. +* Stream-oriented Flet protocol transports (UDS / TCP used by `flet run` dev mode) now use length-prefixed framing instead of streaming `msgpack.Unpacker.feed`. Combined with a new 1-byte type discriminator at the head of every packet (`0x00` = MsgPack control frame, `0x01` = raw DataChannel frame), this unifies framing across all transports (sockets, WebSocket, `dart_bridge` FFI, Pyodide `postMessage`). `StreamingMsgpackDeserializer` is removed from `package:flet`; each inbound packet is one complete MsgPack value, decoded one-shot via `msgpack.deserialize(bytes)` by @FeodorFitsner. +* Bump the bundled Flutter to **3.44.2** (from 3.41.7). The Flet client and the `flet build` template migrate to Flutter 3.44's built-in Kotlin (the Android app no longer applies the Kotlin Gradle plugin itself) and Java 17; the client's Gradle wrapper moves to 8.14 by @FeodorFitsner. +* **Raw RGBA Matplotlib frames on local transports.** `MatplotlibChart` now skips per-frame diffing and PNG encode/decode when the client runs on the same machine: uncompressed RGBA full frames stream straight from Agg's buffer over the chart's `DataChannel` (new `0x04` opcode) and are displayed with a single `decodeImageFromPixels` + swap on the Dart side. A 1600×1000 @ DPR 2 figure (24 MB/frame) over a local socket goes from 7.4 to 18.7 fps, leaving matplotlib's own render as the dominant per-frame cost; remote WebSocket clients keep the compact PNG full+diff pipeline. The format is auto-selected via the new `Connection.local_data_transport` capability flag (set by the socket, `dart_bridge` and Pyodide transports). Also fixes O(n²) length-prefixed packet reassembly in the Dart socket transport — multi-MB frames arrive in dozens of chunks and previously re-flattened the accumulation buffer on every chunk ([#6673](https://github.com/flet-dev/flet/pull/6673)) by @FeodorFitsner. +* `flet build web` and `flet publish` now default the web renderer to `canvaskit` instead of `auto`. With `auto`, Chromium selects the dart2wasm/skwasm renderer, whose JS↔Dart typed-data boundary costs make byte-streaming Pyodide apps (matplotlib frames, `RawImage`) ~6–7x slower per frame; pass `--renderer auto` or set `[tool.flet.web].renderer` to restore the old behavior. Also fixes `tool.flet.web.renderer` being ignored by `flet publish` (shadowed by an argparse default) ([#6673](https://github.com/flet-dev/flet/pull/6673)) by @FeodorFitsner. +* **Faster mobile cold start: `import flet` is now lazy.** The `flet` package previously executed its full ~270-module public API eagerly on `import flet`; it now resolves public names on first access via a module-level `__getattr__` (PEP 562), so an app loads only the modules it actually uses. On a mid-range Android device this cut `import flet` from ~2.0s to ~0.15s. The eager subsystem clusters that `Page` pulled in (auth, components/hooks, Cupertino controls) are deferred too. Type checkers, IDEs, and `from flet import *` are unaffected ([#6597](https://github.com/flet-dev/flet/pull/6597)) by @FeodorFitsner. + +### Breaking changes + +* **App files now ship unpacked in a read-only bundle, and the storage directories were reworked** (requires `serious_python` >= 4.0.0, now pinned in the `flet build` template). Your Python sources ship **unpacked inside the app bundle** next to the stdlib/site-packages (no first-launch `app.zip` extraction) on macOS/iOS/Windows/Linux; on Android they ship as a *stored* `app.zip` asset unpacked once on first launch; web is unchanged. The app directory is now **read-only**, so the Python program's **working directory** moved to a writable, app-private data dir. `FLET_APP_STORAGE_DATA` now maps to the OS *application support* dir (a `data` subdir) instead of the user's Documents folder and is the cwd; `FLET_APP_STORAGE_TEMP` now points to the OS temp dir (was the cache dir) and a new `FLET_APP_STORAGE_CACHE` exposes the cache dir. `flet run` sets the dev cwd to a hidden, git-ignored `/.flet/storage/data`. Relative **reads** of bundled files (`open("seed.json")`) must move to `__file__`/`importlib.resources` or `assets/`. See the [app files unpacked / storage dirs](/docs/updates/breaking-changes/v0-86-0/app-files-unpacked-read-only-bundle) guide by @FeodorFitsner. +* `flet build` and `flet publish` now bundle CPython 3.14 by default (previously 3.12, implicit via the old single-version `serious_python`). Existing apps that depend on native wheels without 3.14 binaries should pin explicitly with `--python-version 3.12` (CLI), `requires-python = ">=3.12,<3.13"` (pyproject), or `SERIOUS_PYTHON_VERSION=3.12` in the build environment ([#6577](https://github.com/flet-dev/flet/pull/6577)) by @FeodorFitsner. +* Android builds now include only the ABIs the bundled Python supports, sourced per-version from python-build's manifest (`pythons..android_abis`) rather than hardcoded in flet. As of python-build `20260630`, `armeabi-v7a` (32-bit ARM) is published for **3.12, 3.13 and 3.14**, so all three build it by default; an explicit `--arch ` is validated against the selected Python's supported set and fails with a clear error otherwise ([#6578](https://github.com/flet-dev/flet/pull/6578)) by @ndonkoHenri. +* `flet build` / `flet publish` now **compile your app and packages to `.pyc` by default** (previously off). This removes per-launch bytecode recompilation — a significant cold-start win, especially on mobile where pure Python is imported from a stored zip (`zipimport`) and can't cache bytecode back to disk, so every module would otherwise recompile from source on each launch. The CLI flags gain `--no-compile-app` / `--no-compile-packages` (via `argparse.BooleanOptionalAction`; the existing `--compile-app` / `--compile-packages` still work), and `[tool.flet.compile].app` / `.packages` now default to `true`. Pass `--no-compile-*` or set them to `false` to restore the old behavior (faster iterative builds, or keeping `.py` source in the bundle). Compiled web builds were verified to load in Pyodide (bundled CPython and Pyodide share the same minor version). See the [compile-on-by-default](/docs/updates/breaking-changes/v0-86-0/compile-on-by-default) guide ([#6598](https://github.com/flet-dev/flet/pull/6598)) by @FeodorFitsner. +* Flet protocol wire format on stream-oriented transports (UDS / TCP) is incompatible with pre-0.86 servers and clients. Every packet now starts with a 4-byte little-endian length prefix and a 1-byte type discriminator (`0x00` = MsgPack control frame, `0x01` = raw DataChannel frame). WebSocket / `postMessage` / `dart_bridge` transports keep native message boundaries and only gain the type byte. The Flet CLI dev server and the in-process Python runtime are upgraded in lockstep — running `flet run` with mismatched `flet` versions across CLI and runtime is no longer supported. See the [DataChannel protocol framing upgrade](/docs/updates/breaking-changes/v0-86-0/data-channel-protocol-upgrade) guide. The `MatplotlibChartCanvas` widget transports its full / diff / clear frames via a `DataChannel` rather than `_invoke_method` arguments — visually identical, but custom code that subclassed it and overrode the apply methods may need updating by @FeodorFitsner. + +### Deprecations + +* Deprecate the `--clear-cache` flag of `flet build` and `flet debug`; use the new `flet clean` command instead. The flag remains functional but now emits a deprecation warning, and is scheduled for removal in `0.89.0` ([#6233](https://github.com/flet-dev/flet/issues/6233)) by @ndonkoHenri. + +### Bug fixes + +* Fix a debug-mode `'!_dirty': is not true` assertion (`EXCEPTION CAUGHT BY WIDGETS LIBRARY` in `_BootOverlay`) thrown by apps built or debugged from the `flet build` template when the app becomes ready. With the default `boot_screen.fade_out_duration` of 0 the overlay's zero-duration `AnimatedOpacity` completed synchronously, firing `onEnd` — and its `setState` — in the middle of the overlay's own rebuild. The overlay is now removed in a single state update when no fade is configured; non-zero fade durations still animate as before. Debug-mode only: the assertion is compiled out of release builds ([#6666](https://github.com/flet-dev/flet/pull/6666)) by @FeodorFitsner. +* Fix `flet build` failing on Windows when a dependency is pulled in via `[tool.flet.].dev_packages` (or any local-path install): the rewritten ` @ file://` URL now uses `Path.as_uri()`, producing the correct `file:///D:/...` three-slash form instead of `file://D:\...`, which pip on Windows parsed as a UNC path and aborted with `OSError: [Errno 2] No such file or directory: '\\\\D:\\a\\...'` ([#6577](https://github.com/flet-dev/flet/pull/6577)) by @FeodorFitsner. +* Fix `flet build web --python-version 3.13` failing to match any Pyodide-built native wheel. The 3.13 row in the Python version registry was set to Pyodide platform tag `pyodide-2025.0-wasm32`, but Pyodide actually publishes 0.29 wheels under `pyemscripten_2025_0_wasm32` (the `pyodide_` → `pyemscripten_` prefix transition happened at 0.28/0.29, not at 314.0). Corrected to `pyemscripten-2025.0-wasm32` so pip's wheel selection picks up the correct tags by @FeodorFitsner. +* `flet build` now cleans the build directory when the bundled Python version changes between builds, preventing stale compiled bytecode from the previous version crashing the app at runtime with `ImportError: bad magic number` by @FeodorFitsner. +* Fix locating Flet controls by their user-assigned `key` in tests. `ValueKey(control.key)` was constructed as `ValueKey`, and Flutter's runtimeType-strict `ValueKey.==` never matches that against the `ValueKey` the rendered widget carries — so `find.byKey(Key('foo'))` (flutter_test) and `find_by_key('foo')` (Flet tester) located 0 widgets. The `ValueKey` is now built with the value's concrete type (String → `ValueKey`, int → `ValueKey`, …) on both the Dart and Python sides by @FeodorFitsner. +* Fix `flet build apk` / `flet build aab` with `--arch` packaging native libraries for *all* Android ABIs instead of only the requested ones. The requested architectures are now forwarded to Flutter as `--target-platform` (so `--split-per-abi` builds only the requested splits), unrequested ABI directories are excluded from the artifact via `packaging.jniLibs.excludes`, Android `--arch` values are validated against the bundled Python's supported ABIs, multiple `--arch` values now correctly reach `serious_python` (comma-joined), and stale artifacts from previous builds are no longer copied into the output directory ([#6567](https://github.com/flet-dev/flet/issues/6567), [#6578](https://github.com/flet-dev/flet/pull/6578)) by @ndonkoHenri. +* Fix repeated `--arch`, `--source-packages` and `--permissions` flags in `flet build` keeping only the values of the last occurrence (`action="extend"` on each) ([#6578](https://github.com/flet-dev/flet/pull/6578)) by @ndonkoHenri. +* Fix `flet build apk` failing at `mergeDebugNativeLibs` with `N files found with path 'lib//libc++_shared.so'` when an app combines `serious_python_android` with another Flutter plugin that also bundles the NDK C++ runtime ([#6570](https://github.com/flet-dev/flet/issues/6570), [#6571](https://github.com/flet-dev/flet/pull/6571)) by @ndonkoHenri. +* Specify `handler` signatures in `subscribe` and `subscribe_topic` methods of `PubSubClient` for better type checking ([#6549](https://github.com/flet-dev/flet/pull/6564)) by @Iaw4tch +* Fix `FilePicker.pick_files()` on web for slow network shares or slow machines: pass `cancel_upload_on_window_blur=False` to prevent valid file selections from being reported as cancelled when the browser window loses focus during file picking ([#771](https://github.com/flet-dev/flet/issues/771), [#6573](https://github.com/flet-dev/flet/pull/6573)) by @ndonkoHenri. +* Support `PagePlatform.ANDROID_TV` in `Page.get_device_info()` retrieval ([#6604](https://github.com/flet-dev/flet/pull/6604)) by @bl1nch. +* Fix `ProgressRing.year_2023` being ignored, so the control correctly switches between the latest and 2023 Material Design appearances ([#6614](https://github.com/flet-dev/flet/issues/6614)) by @ndonkoHenri. +* `flet build ipa` / `ios` apps that ship ctypes packages with plain `.dylib` shared libraries (e.g. `llama-cpp-python`) now load them on the **iOS simulator** instead of failing at launch with a `dlopen` platform mismatch (`have 'iOS', need 'iOS-simulator'`); the iOS runtime also now bundles the `_multiprocessing` extension (importable, not spawnable). Bumps the pinned bundle to `serious_python` 4.2.1 / python-build `20260701` ([serious_python#223](https://github.com/flet-dev/serious-python/pull/223)) by @ndonkoHenri, @FeodorFitsner. +* Improve performance of checking added/removed controls in Session.patch_control from O(N²) to O(N) ([#6651](https://github.com/flet-dev/flet/pull/6651)) by @davidlawson. +* Fix stateful controls inside `ResponsiveRow` (video players, WebViews, scroll positions) losing their state whenever a window resize crossed a breakpoint and the layout switched between a single row and wrapping ([#6661](https://github.com/flet-dev/flet/issues/6661), [#6663](https://github.com/flet-dev/flet/pull/6663)) by @FeodorFitsner. + +### Documentation + +* Improve `FilePicker.save_file()` documentation: on desktop, passing `src_bytes` writes those bytes to the selected file ([#6573](https://github.com/flet-dev/flet/pull/6573)) by @ndonkoHenri. + ## 0.85.3 ### Improvements diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 63cd7b2f47..5d931423c7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -256,14 +256,9 @@ For patches to the current stable release, branch directly from `main`, fix, ope * Keep the `## {version}` section in `packages/flet/CHANGELOG.md` in sync with the root `CHANGELOG.md` before tagging the release. * Ensure every merged PR on `release/v{version}` added a new record to the active root `CHANGELOG.md` section. -* Open terminal in `client` directory and run `fvm flutter clean; fvm flutter pub get`. -* Increment version in `packages/flet/pubspec.yaml`. -* Review and update `CHANGELOG.md` for the release version. -* Update version in `packages/flet/pubspec.yaml` to the release version if not already done. -* Run `fvm flutter build macos`, `fvm flutter build linux`, `fvm flutter build windows`, `fvm flutter build web --wasm` to ensure everything compiles. -* Run `uv run pytest` in `sdk/python` to ensure all tests pass. -* If any test fails, fix the issue before proceeding. -* Once all checks pass, commit the final changes (version bumps, changelog updates) to the release branch. +* Open terminal in `client` directory and run `flutter pub get` to update Flet dependency versions in `client/pubspec.lock`. +* Templates are in `sdk/python/templates/` and automatically packaged as zip artifacts with the GitHub Release. No manual branch creation in external repos is needed. +* The supported Python / Pyodide versions are loaded on demand from [python-build's](https://github.com/flet-dev/python-build) date-keyed `manifest.json`; flet pins one release via `PYTHON_BUILD_RELEASE_DATE` in `sdk/python/packages/flet-cli/src/flet_cli/utils/python_versions.py`. When bumping it, keep it aligned with serious_python's `pythonReleaseDate` (both should track the same python-build release). ## New macOS environment for Flet developer diff --git a/client/android/app/build.gradle.kts b/client/android/app/build.gradle.kts index 41100f0452..855a314b73 100644 --- a/client/android/app/build.gradle.kts +++ b/client/android/app/build.gradle.kts @@ -1,22 +1,19 @@ plugins { id("com.android.application") - id("kotlin-android") - // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + // Kotlin is provided by the Flutter Gradle Plugin (Built-in Kotlin), so the + // app no longer applies the Kotlin Gradle Plugin itself. + // The Flutter Gradle Plugin must be applied after the Android Gradle plugin. id("dev.flutter.flutter-gradle-plugin") } android { namespace = "com.appveyor.flet_client" compileSdk = flutter.compileSdkVersion - ndkVersion = "27.0.12077973" + ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 - } - - kotlinOptions { - jvmTarget = JavaVersion.VERSION_11.toString() + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } defaultConfig { @@ -37,6 +34,12 @@ android { } } +kotlin { + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 + } +} + flutter { source = "../.." } diff --git a/client/android/gradle.properties b/client/android/gradle.properties index f018a61817..82c211905a 100644 --- a/client/android/gradle.properties +++ b/client/android/gradle.properties @@ -1,3 +1,5 @@ org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true +android.builtInKotlin=true +android.newDsl=true diff --git a/client/android/gradle/wrapper/gradle-wrapper.properties b/client/android/gradle/wrapper/gradle-wrapper.properties index 02767eb1ca..e4ef43fb98 100644 --- a/client/android/gradle/wrapper/gradle-wrapper.properties +++ b/client/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip diff --git a/client/android/settings.gradle.kts b/client/android/settings.gradle.kts index 38573a4d5b..fba4abce7b 100644 --- a/client/android/settings.gradle.kts +++ b/client/android/settings.gradle.kts @@ -18,8 +18,9 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.12.1" apply false - id("org.jetbrains.kotlin.android") version "2.1.0" apply false + id("com.android.application") version "8.11.1" apply false + // Plugin applies kotlin-android for us (Built-in Kotlin) — uses this KGP version. + id("org.jetbrains.kotlin.android") version "2.2.20" apply false } include(":app") diff --git a/client/integration_test/app_test.dart b/client/integration_test/app_test.dart index 9659913c55..252ec74407 100644 --- a/client/integration_test/app_test.dart +++ b/client/integration_test/app_test.dart @@ -1,45 +1,7 @@ -import 'dart:io'; - +import 'package:flet_integration_test/flet_integration_test.dart'; import 'package:flet_client/main.dart' as app; -import 'package:flutter/foundation.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:integration_test/integration_test.dart'; - -import 'flutter_tester.dart'; - -void main() { - var binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - - group('end-to-end test', () { - testWidgets('test app', (tester) async { - var dir = Directory.current.path; - debugPrint("Current dir: $dir"); - - app.tester = FlutterWidgetTester(tester, binding); - - List args = []; - const fletTestAppUrl = String.fromEnvironment("FLET_TEST_APP_URL"); - if (fletTestAppUrl != "") { - args.add(fletTestAppUrl); - } - - const fletTestPidFile = String.fromEnvironment("FLET_TEST_PID_FILE_PATH"); - if (fletTestPidFile != "") { - args.add(fletTestPidFile); - } - - const fletTestAssetsDir = String.fromEnvironment("FLET_TEST_ASSETS_DIR"); - if (fletTestAssetsDir != "") { - args.add(fletTestAssetsDir); - } - - app.main(args); - await Future.delayed(const Duration(milliseconds: 500)); - await app.tester?.pump(duration: const Duration(seconds: 1)); - await app.tester - ?.pumpAndSettle(duration: const Duration(milliseconds: 100)); - await app.tester?.waitForTeardown(); - }); - }); -} +void main() => runFletHostTest( + appMain: app.main, + assignTester: (t) => app.tester = t, + ); diff --git a/client/ios/Flutter/AppFrameworkInfo.plist b/client/ios/Flutter/AppFrameworkInfo.plist index 1dc6cf7652..391a902b2b 100644 --- a/client/ios/Flutter/AppFrameworkInfo.plist +++ b/client/ios/Flutter/AppFrameworkInfo.plist @@ -20,7 +20,5 @@ ???? CFBundleVersion 1.0 - MinimumOSVersion - 13.0 diff --git a/client/ios/Podfile.lock b/client/ios/Podfile.lock index 217a9b152a..42177a4e1d 100644 --- a/client/ios/Podfile.lock +++ b/client/ios/Podfile.lock @@ -1,227 +1,28 @@ PODS: - - audioplayers_darwin (0.0.1): - - Flutter - - FlutterMacOS - - battery_plus (1.0.0): - - Flutter - - camera_avfoundation (0.0.1): - - Flutter - - connectivity_plus (0.0.1): - - Flutter - - device_info_plus (0.0.1): - - Flutter - - DKImagePickerController/Core (4.3.9): - - DKImagePickerController/ImageDataManager - - DKImagePickerController/Resource - - DKImagePickerController/ImageDataManager (4.3.9) - - DKImagePickerController/PhotoGallery (4.3.9): - - DKImagePickerController/Core - - DKPhotoGallery - - DKImagePickerController/Resource (4.3.9) - - DKPhotoGallery (0.0.19): - - DKPhotoGallery/Core (= 0.0.19) - - DKPhotoGallery/Model (= 0.0.19) - - DKPhotoGallery/Preview (= 0.0.19) - - DKPhotoGallery/Resource (= 0.0.19) - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Core (0.0.19): - - DKPhotoGallery/Model - - DKPhotoGallery/Preview - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Model (0.0.19): - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Preview (0.0.19): - - DKPhotoGallery/Model - - DKPhotoGallery/Resource - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Resource (0.0.19): - - SDWebImage - - SwiftyGif - - file_picker (0.0.1): - - DKImagePickerController/PhotoGallery - - Flutter - Flutter (1.0.0) - - flutter_secure_storage_darwin (10.0.0): - - Flutter - - FlutterMacOS - - geolocator_apple (1.2.0): - - Flutter - - FlutterMacOS - - Google-Mobile-Ads-SDK (12.14.0): - - GoogleUserMessagingPlatform (>= 1.1) - - google_mobile_ads (7.0.0): - - Flutter - - Google-Mobile-Ads-SDK (~> 12.14.0) - - webview_flutter_wkwebview - - GoogleUserMessagingPlatform (3.1.0) - - integration_test (0.0.1): - - Flutter - media_kit_libs_ios_video (1.0.4): - Flutter - media_kit_video (0.0.1): - Flutter - - package_info_plus (0.4.5): - - Flutter - - pasteboard (0.0.1): - - Flutter - - permission_handler_apple (9.3.0): - - Flutter - - record_ios (1.2.0): - - Flutter - - rive_native (0.0.1): - - Flutter - - screen_brightness_ios (0.1.0): - - Flutter - - SDWebImage (5.20.0): - - SDWebImage/Core (= 5.20.0) - - SDWebImage/Core (5.20.0) - - sensors_plus (0.0.1): - - Flutter - - share_plus (0.0.1): - - Flutter - - shared_preferences_foundation (0.0.1): - - Flutter - - FlutterMacOS - - SwiftyGif (5.4.5) - - torch_light (0.0.1): - - Flutter - - url_launcher_ios (0.0.1): - - Flutter - - wakelock_plus (0.0.1): - - Flutter - - webview_flutter_wkwebview (0.0.1): - - Flutter - - FlutterMacOS DEPENDENCIES: - - audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/darwin`) - - battery_plus (from `.symlinks/plugins/battery_plus/ios`) - - camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`) - - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - - file_picker (from `.symlinks/plugins/file_picker/ios`) - Flutter (from `Flutter`) - - flutter_secure_storage_darwin (from `.symlinks/plugins/flutter_secure_storage_darwin/darwin`) - - geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`) - - google_mobile_ads (from `.symlinks/plugins/google_mobile_ads/ios`) - - integration_test (from `.symlinks/plugins/integration_test/ios`) - media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`) - media_kit_video (from `.symlinks/plugins/media_kit_video/ios`) - - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - - pasteboard (from `.symlinks/plugins/pasteboard/ios`) - - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - - record_ios (from `.symlinks/plugins/record_ios/ios`) - - rive_native (from `.symlinks/plugins/rive_native/ios`) - - screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`) - - sensors_plus (from `.symlinks/plugins/sensors_plus/ios`) - - share_plus (from `.symlinks/plugins/share_plus/ios`) - - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - - torch_light (from `.symlinks/plugins/torch_light/ios`) - - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) - - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`) - -SPEC REPOS: - trunk: - - DKImagePickerController - - DKPhotoGallery - - Google-Mobile-Ads-SDK - - GoogleUserMessagingPlatform - - SDWebImage - - SwiftyGif EXTERNAL SOURCES: - audioplayers_darwin: - :path: ".symlinks/plugins/audioplayers_darwin/darwin" - battery_plus: - :path: ".symlinks/plugins/battery_plus/ios" - camera_avfoundation: - :path: ".symlinks/plugins/camera_avfoundation/ios" - connectivity_plus: - :path: ".symlinks/plugins/connectivity_plus/ios" - device_info_plus: - :path: ".symlinks/plugins/device_info_plus/ios" - file_picker: - :path: ".symlinks/plugins/file_picker/ios" Flutter: :path: Flutter - flutter_secure_storage_darwin: - :path: ".symlinks/plugins/flutter_secure_storage_darwin/darwin" - geolocator_apple: - :path: ".symlinks/plugins/geolocator_apple/darwin" - google_mobile_ads: - :path: ".symlinks/plugins/google_mobile_ads/ios" - integration_test: - :path: ".symlinks/plugins/integration_test/ios" media_kit_libs_ios_video: :path: ".symlinks/plugins/media_kit_libs_ios_video/ios" media_kit_video: :path: ".symlinks/plugins/media_kit_video/ios" - package_info_plus: - :path: ".symlinks/plugins/package_info_plus/ios" - pasteboard: - :path: ".symlinks/plugins/pasteboard/ios" - permission_handler_apple: - :path: ".symlinks/plugins/permission_handler_apple/ios" - record_ios: - :path: ".symlinks/plugins/record_ios/ios" - rive_native: - :path: ".symlinks/plugins/rive_native/ios" - screen_brightness_ios: - :path: ".symlinks/plugins/screen_brightness_ios/ios" - sensors_plus: - :path: ".symlinks/plugins/sensors_plus/ios" - share_plus: - :path: ".symlinks/plugins/share_plus/ios" - shared_preferences_foundation: - :path: ".symlinks/plugins/shared_preferences_foundation/darwin" - torch_light: - :path: ".symlinks/plugins/torch_light/ios" - url_launcher_ios: - :path: ".symlinks/plugins/url_launcher_ios/ios" - wakelock_plus: - :path: ".symlinks/plugins/wakelock_plus/ios" - webview_flutter_wkwebview: - :path: ".symlinks/plugins/webview_flutter_wkwebview/darwin" SPEC CHECKSUMS: - audioplayers_darwin: 4f9ca89d92d3d21cec7ec580e78ca888e5fb68bd - battery_plus: b42253f6d2dde71712f8c36fef456d99121c5977 - camera_avfoundation: 5675ca25298b6f81fa0a325188e7df62cc217741 - connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd - device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe - DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c - DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 - file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 - flutter_secure_storage_darwin: acdb3f316ed05a3e68f856e0353b133eec373a23 - geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e - Google-Mobile-Ads-SDK: 4534fd2dfcd3f705c5485a6633c5188d03d4eed2 - google_mobile_ads: df3008bafbe1f2ad6862f87334e560d2f047f902 - GoogleUserMessagingPlatform: befe603da6501006420c206222acd449bba45a9c - integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854 media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474 - package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 - pasteboard: 49088aeb6119d51f976a421db60d8e1ab079b63c - permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d - record_ios: 412daca2350b228e698fffcd08f1f94ceb1e3844 - rive_native: c9ed76ccf380f38205edcb8f552121aac8ec39da - screen_brightness_ios: 9953fd7da5bd480f1a93990daeec2eb42d4f3b52 - SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8 - sensors_plus: 6a11ed0c2e1d0bd0b20b4029d3bad27d96e0c65b - share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a - shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb - SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 - torch_light: d093d579a221a59ef8a6b8c0eca20d52f7178087 - url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b - wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556 - webview_flutter_wkwebview: 8ebf4fded22593026f7dbff1fbff31ea98573c8d PODFILE CHECKSUM: 462a5b249f9f1900cbd87af7b6af48272dc2df5a -COCOAPODS: 1.16.2 +COCOAPODS: 1.14.3 diff --git a/client/ios/Runner.xcodeproj/project.pbxproj b/client/ios/Runner.xcodeproj/project.pbxproj index 00bb254787..db4f1feee4 100644 --- a/client/ios/Runner.xcodeproj/project.pbxproj +++ b/client/ios/Runner.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; @@ -38,6 +39,7 @@ 52A5ECC94C6725A2D888E9C8 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; @@ -54,6 +56,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, CD5B0CEB6304D70EE10E9B99 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -74,6 +77,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, @@ -139,13 +143,15 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 58A4996EE779406784CD4C79 /* [CP] Embed Pods Frameworks */, - 66843B3D06C83DEA7E765D27 /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = Runner; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; @@ -174,6 +180,9 @@ Base, ); mainGroup = 97C146E51CF9000F007C117D; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; @@ -253,23 +262,6 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 66843B3D06C83DEA7E765D27 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -576,6 +568,20 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; } diff --git a/client/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/client/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000000..0f864937fe --- /dev/null +++ b/client/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,77 @@ +{ + "pins" : [ + { + "identity" : "dkcamera", + "kind" : "remoteSourceControl", + "location" : "https://github.com/zhangao0086/DKCamera", + "state" : { + "branch" : "master", + "revision" : "5c691d11014b910aff69f960475d70e65d9dcc96" + } + }, + { + "identity" : "dkimagepickercontroller", + "kind" : "remoteSourceControl", + "location" : "https://github.com/zhangao0086/DKImagePickerController", + "state" : { + "branch" : "4.3.9", + "revision" : "0bdfeacefa308545adde07bef86e349186335915" + } + }, + { + "identity" : "dkphotogallery", + "kind" : "remoteSourceControl", + "location" : "https://github.com/zhangao0086/DKPhotoGallery", + "state" : { + "branch" : "master", + "revision" : "311c1bc7a94f1538f82773a79c84374b12a2ef3d" + } + }, + { + "identity" : "sdwebimage", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SDWebImage/SDWebImage", + "state" : { + "revision" : "2de3a496eaf6df9a1312862adcfd54acd73c39c0", + "version" : "5.21.7" + } + }, + { + "identity" : "swift-package-manager-google-mobile-ads", + "kind" : "remoteSourceControl", + "location" : "https://github.com/googleads/swift-package-manager-google-mobile-ads", + "state" : { + "revision" : "7651abff585dc8dacd1744222d5f03bdd2a8532a", + "version" : "13.6.0" + } + }, + { + "identity" : "swift-package-manager-google-user-messaging-platform", + "kind" : "remoteSourceControl", + "location" : "https://github.com/googleads/swift-package-manager-google-user-messaging-platform.git", + "state" : { + "revision" : "13b248eaa73b7826f0efb1bcf455e251d65ecb1b", + "version" : "3.1.0" + } + }, + { + "identity" : "swiftygif", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kirualex/SwiftyGif.git", + "state" : { + "revision" : "4430cbc148baa3907651d40562d96325426f409a", + "version" : "5.4.5" + } + }, + { + "identity" : "tocropviewcontroller", + "kind" : "remoteSourceControl", + "location" : "https://github.com/TimOliver/TOCropViewController", + "state" : { + "revision" : "d4a6d8100f4b886fdbc8ae399bf144ff3e9afb7e", + "version" : "2.8.0" + } + } + ], + "version" : 2 +} diff --git a/client/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/client/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 9c12df59c6..5db441f58a 100644 --- a/client/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/client/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -5,6 +5,24 @@ + + + + + + + + + + Bool { - GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } + + func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { + GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) + } } diff --git a/client/ios/Runner/Info.plist b/client/ios/Runner/Info.plist index 3b661dcd07..e813d8bc18 100644 --- a/client/ios/Runner/Info.plist +++ b/client/ios/Runner/Info.plist @@ -1,81 +1,89 @@ + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Flet + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + flet + CFBundlePackageType + APPL + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + GADApplicationIdentifier + ca-app-pub-3940256099942544~1458002511 + ITSAppUsesNonExemptEncryption + + LSRequiresIPhoneOS + + NSAppTransportSecurity - CADisableMinimumFrameDurationOnPhone + NSAllowsArbitraryLoads - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Flet - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - flet - CFBundlePackageType - APPL - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - ITSAppUsesNonExemptEncryption + + NSCameraUsageDescription + This app uses the camera to capture photos and video. + NSLocationWhenInUseUsageDescription + This app needs access to location. + NSMicrophoneUsageDescription + This app needs access to microphone. + NSPhotoLibraryUsageDescription + The app needs access to photo library, so that photos can be selected. + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes - - UIApplicationSupportsIndirectInputEvents - - NSAppTransportSecurity + UISceneConfigurations - NSAllowsArbitraryLoads - + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneConfigurationName + flutter + UISceneDelegateClassName + FlutterSceneDelegate + UISceneStoryboardFile + Main + + - - - NSPhotoLibraryUsageDescription - The app needs access to photo library, so that photos can be selected. - - - GADApplicationIdentifier - ca-app-pub-3940256099942544~1458002511 - - - - NSMicrophoneUsageDescription - This app needs access to microphone. - - - - NSLocationWhenInUseUsageDescription - This app needs access to location. - - - NSCameraUsageDescription - This app uses the camera to capture photos and video. + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + diff --git a/client/lib/main.dart b/client/lib/main.dart index 1e5e1b6abb..f171717a08 100644 --- a/client/lib/main.dart +++ b/client/lib/main.dart @@ -82,7 +82,14 @@ void main([List? args]) async { //debugPrint("Uri.base: ${Uri.base}"); if (kDebugMode) { - pageUrl = "http://localhost:8550"; + // The Android emulator reaches the host machine via 10.0.2.2, not + // localhost (which points at the emulator itself). Everywhere else + // (desktop, iOS simulator, web) localhost is correct. + var debugHost = + !kIsWeb && defaultTargetPlatform == TargetPlatform.android + ? "10.0.2.2" + : "localhost"; + pageUrl = "http://$debugHost:8550"; } if (kIsWeb) { @@ -133,8 +140,11 @@ void main([List? args]) async { pageUrl: pageUrl, assetsDir: assetsDir, errorsHandler: errorsHandler, - showAppStartupScreen: true, - appStartupScreenMessage: "Working...", + bootScreenName: "flet", + bootScreenOptions: const { + "spinner_size": 30, + "startup_message": "Working..." + }, appErrorMessage: "The application encountered an error: {message}", extensions: extensions, multiView: isMultiView(), diff --git a/client/linux/flutter/generated_plugin_registrant.cc b/client/linux/flutter/generated_plugin_registrant.cc index 486c5f4f54..49c3757b48 100644 --- a/client/linux/flutter/generated_plugin_registrant.cc +++ b/client/linux/flutter/generated_plugin_registrant.cc @@ -16,7 +16,6 @@ #include #include #include -#include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar = @@ -49,7 +48,4 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) window_manager_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin"); window_manager_plugin_register_with_registrar(window_manager_registrar); - g_autoptr(FlPluginRegistrar) window_to_front_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "WindowToFrontPlugin"); - window_to_front_plugin_register_with_registrar(window_to_front_registrar); } diff --git a/client/linux/flutter/generated_plugins.cmake b/client/linux/flutter/generated_plugins.cmake index 692e9fcd42..b30e4c610a 100644 --- a/client/linux/flutter/generated_plugins.cmake +++ b/client/linux/flutter/generated_plugins.cmake @@ -13,7 +13,6 @@ list(APPEND FLUTTER_PLUGIN_LIST screen_retriever_linux url_launcher_linux window_manager - window_to_front ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/client/linux/my_application.cc b/client/linux/my_application.cc index 7bc5ee4d3d..730d2d6d14 100644 --- a/client/linux/my_application.cc +++ b/client/linux/my_application.cc @@ -59,6 +59,11 @@ static void my_application_activate(GApplication* application) { gtk_widget_show(GTK_WIDGET(view)); gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + // Realize the Flutter view while the top-level window is still hidden; this + // lets Flutter render its first frames and lets integration tests attach + // before Dart decides whether the app window should be shown. + gtk_widget_realize(GTK_WIDGET(view)); + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); gtk_widget_grab_focus(GTK_WIDGET(view)); diff --git a/client/macos/Flutter/GeneratedPluginRegistrant.swift b/client/macos/Flutter/GeneratedPluginRegistrant.swift index 62e3cfcb94..634e2b35b4 100644 --- a/client/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/client/macos/Flutter/GeneratedPluginRegistrant.swift @@ -26,7 +26,6 @@ import url_launcher_macos import wakelock_plus import webview_flutter_wkwebview import window_manager -import window_to_front func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) @@ -50,5 +49,4 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin")) WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) - WindowToFrontPlugin.register(with: registry.registrar(forPlugin: "WindowToFrontPlugin")) } diff --git a/client/macos/Runner.xcodeproj/project.pbxproj b/client/macos/Runner.xcodeproj/project.pbxproj index 7f045dcd00..2cccb3d5db 100644 --- a/client/macos/Runner.xcodeproj/project.pbxproj +++ b/client/macos/Runner.xcodeproj/project.pbxproj @@ -28,6 +28,7 @@ 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; 4C5C567116C0F37A5F3A163A /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB9EEDA013737D623D55462A /* Pods_Runner.framework */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -74,6 +75,7 @@ 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; BB9EEDA013737D623D55462A /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EDAD244E5F1A9F15957004F8 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -81,6 +83,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, 4C5C567116C0F37A5F3A163A /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -132,6 +135,7 @@ 33CEB47122A05771004F2AC0 /* Flutter */ = { isa = PBXGroup; children = ( + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, @@ -175,6 +179,9 @@ /* Begin PBXNativeTarget section */ 33CC10EC2044A3C60003C045 /* Runner */ = { + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( @@ -200,6 +207,9 @@ /* Begin PBXProject section */ 33CC10E52044A3C60003C045 /* Project object */ = { + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, + ); isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; @@ -647,6 +657,18 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 33CC10E52044A3C60003C045 /* Project object */; } diff --git a/client/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/client/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 16d4c22e3f..d1579dfd00 100644 --- a/client/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/client/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -5,6 +5,24 @@ + + + + + + + + + + =3.11.0 <4.0.0" - flutter: ">=3.41.0" + dart: ">=3.12.0 <4.0.0" + flutter: ">=3.44.0" diff --git a/client/pubspec.yaml b/client/pubspec.yaml index b70a83270a..0ba147dc8d 100644 --- a/client/pubspec.yaml +++ b/client/pubspec.yaml @@ -97,11 +97,23 @@ dependencies: dependency_overrides: flet: path: ../packages/flet + screen_retriever: 0.2.1 # this one migrated to SPM, but 0.2.0 is used by some other packages + + screen_brightness: 2.1.7 + # screen_brightness_macos 2.1.3 ("Fix: swift package manager warning") ships a + # Package.swift declaring macOS 10.11, below FlutterFramework's 10.15 floor, + # which breaks Swift Package Manager resolution. Pin the last good impl until + # upstream fixes it: https://github.com/aaassseee/screen_brightness/issues/99 + screen_brightness_macos: 2.1.2 dev_dependencies: flutter_test: sdk: flutter + # Flet integration-test driver (used by integration_test/app_test.dart). + flet_integration_test: + path: ../packages/flet_integration_test + # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your diff --git a/client/web/index.html b/client/web/index.html index 2e622c51af..0e630c5821 100644 --- a/client/web/index.html +++ b/client/web/index.html @@ -30,7 +30,11 @@ assetBase: "/", routeUrlStrategy: "path", canvasKitBaseUrl: "/canvaskit/", - pyodideUrl: "/pyodide/pyodide.js", + // Default fallback only — `patch_index.py` overrides this with the + // resolved per-build URL (CDN or local) at deploy time. The `.mjs` + // suffix is required because python-worker.js is a module worker + // that loads the runtime via dynamic `import()`. See client/web/python.js. + pyodideUrl: "/pyodide/pyodide.mjs", webRenderer: "auto", fontFallbackBaseUrl: "assets/fonts/", // for Noto Emoji, use Google CDN appPackageUrl: "app.tar.gz" diff --git a/client/web/python-worker.js b/client/web/python-worker.js index 40c6083afc..390ea96747 100644 --- a/client/web/python-worker.js +++ b/client/web/python-worker.js @@ -38,7 +38,14 @@ self.sendPythonOutput = function (text, isStderr) { self.initPyodide = async function () { try { - importScripts(self.pyodideUrl); + // Module-worker load path. `importScripts` only exists in classic + // workers — Pyodide >= 0.29 actively refuses to load there ("Classic + // web workers are not supported"). We're a module worker, so the + // runtime ships as `pyodide.mjs` and exposes `loadPyodide` via ESM + // exports. The CDN/jsdelivr fallback URL set by patch_index.py also + // points at the .mjs variant. + const pyodideModule = await import(self.pyodideUrl); + const loadPyodide = pyodideModule.loadPyodide || self.loadPyodide; self.pyodide = await loadPyodide({ stdout: (text) => self.sendPythonOutput(text, false), stderr: (text) => self.sendPythonOutput(text, true), @@ -163,8 +170,15 @@ self.initPyodide = async function () { import msgpack as _msgpack def _send_python_output(text, is_stderr): + # Frame exactly like PyodideConnection.send_message: a 0x00 type + # byte (0x00 = MsgPack Flet protocol frame, 0x01 = raw DataChannel + # frame) in front of the packed [action, body]. Without the prefix + # the Dart side reads msgpack's leading 0x92 as an unknown packet + # type and silently drops the line. bytes([0]) avoids a literal + # NUL escape inside this JS template string. flet_js.receive_callback( - _msgpack.packb( + bytes([0]) + + _msgpack.packb( [7, {"text": text, "is_stderr": bool(is_stderr)}] ) ) @@ -206,7 +220,14 @@ self.initPyodide = async function () { }; self.receiveCallback = (message) => { - self.postMessage(message.toJs()); + // `message` is a Pyodide JsProxy wrapping a Python `bytes`. `toJs()` + // gives us a fresh Uint8Array; transferring its underlying ArrayBuffer + // to the main thread skips the structured-clone copy (~hundreds of KB + // per matplotlib frame). Safe because the Uint8Array is freshly + // materialized here, and the original Python `bytes` is untouched + // (Pyodide keeps its own reference). + const bytes = message.toJs(); + self.postMessage(bytes, [bytes.buffer]); } // Same channel as `receiveCallback`, exposed under `flet_js` so the // Python python_output shim can post pre-encoded msgpack frames. diff --git a/client/web/python.js b/client/web/python.js index 4f785f3a50..1e44e27b2e 100644 --- a/client/web/python.js +++ b/client/web/python.js @@ -1,5 +1,6 @@ -const defaultPyodideUrl = "https://cdn.jsdelivr.net/pyodide/v0.27.7/full/pyodide.js"; - +// Pyodide URL is injected per build by flet-web's patch_index.py +// (sets flet.pyodideUrl). Falls back to the local pyodide/ directory that +// flet build web / flet publish drop next to the page. let _apps = {}; let _documentUrl = document.URL; @@ -12,8 +13,17 @@ globalThis.jsConnect = async function (appId, args, dartOnMessage) { }; console.log(`Starting up Python worker: ${appId}, args: ${args}`); _apps[appId] = app; - app.worker = new Worker((flet.entrypointBaseUrl.endsWith("/") ? - flet.entrypointBaseUrl.slice(0, -1) : flet.entrypointBaseUrl) + "/python-worker.js"); + // Module worker (type: "module") is required by Pyodide >= 0.29 — the + // runtime throws "Classic web workers are not supported" inside any + // worker where `importScripts` is callable. Module workers don't have + // `importScripts`, so the check passes. Older Pyodide lines (0.27.x) + // accept module workers too, so this is forward-compatible across all + // supported Python versions (3.12 → Pyodide 0.27.7, 3.13 → 0.29.4, + // 3.14 → 314.0.0). + app.worker = new Worker( + (flet.entrypointBaseUrl.endsWith("/") ? + flet.entrypointBaseUrl.slice(0, -1) : flet.entrypointBaseUrl) + "/python-worker.js", + { type: "module" }); var error; app.worker.onmessage = (event) => { @@ -31,7 +41,11 @@ globalThis.jsConnect = async function (appId, args, dartOnMessage) { // initialize worker app.worker.postMessage({ - pyodideUrl: flet.noCdn ? flet.pyodideUrl : defaultPyodideUrl, + // `.mjs` is the ES-module variant. python-worker.js (now a module + // worker) loads it via dynamic `import()`. The legacy `.js` + // variant relied on `importScripts`, which doesn't exist in a + // module worker. + pyodideUrl: flet.pyodideUrl || "pyodide/pyodide.mjs", args: args, documentUrl: _documentUrl, appPackageUrl: flet.appPackageUrl, diff --git a/client/windows/flutter/generated_plugin_registrant.cc b/client/windows/flutter/generated_plugin_registrant.cc index 00afa0a858..5042c5c7cf 100644 --- a/client/windows/flutter/generated_plugin_registrant.cc +++ b/client/windows/flutter/generated_plugin_registrant.cc @@ -17,12 +17,11 @@ #include #include #include -#include +#include #include #include #include #include -#include void RegisterPlugins(flutter::PluginRegistry* registry) { AudioplayersWindowsPluginRegisterWithRegistrar( @@ -47,8 +46,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("RecordWindowsPluginCApi")); RiveNativePluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("RiveNativePlugin")); - ScreenBrightnessWindowsPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin")); + ScreenBrightnessWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPluginCApi")); ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi")); SharePlusWindowsPluginCApiRegisterWithRegistrar( @@ -57,6 +56,4 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("UrlLauncherWindows")); WindowManagerPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("WindowManagerPlugin")); - WindowToFrontPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("WindowToFrontPlugin")); } diff --git a/client/windows/flutter/generated_plugins.cmake b/client/windows/flutter/generated_plugins.cmake index c04e69f80e..1aab211945 100644 --- a/client/windows/flutter/generated_plugins.cmake +++ b/client/windows/flutter/generated_plugins.cmake @@ -19,7 +19,6 @@ list(APPEND FLUTTER_PLUGIN_LIST share_plus url_launcher_windows window_manager - window_to_front ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/packages/flet/CHANGELOG.md b/packages/flet/CHANGELOG.md index 6034004ef5..41217b664c 100644 --- a/packages/flet/CHANGELOG.md +++ b/packages/flet/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.86.0 + +_No changes in the `flet` Dart package; version bumped for release coordination with the multi-version bundled CPython support on the Python side ([#6577](https://github.com/flet-dev/flet/pull/6577))._ + ## 0.85.3 ### Bug fixes diff --git a/packages/flet/lib/flet.dart b/packages/flet/lib/flet.dart index 6c0933a2e1..1e2828d6c3 100644 --- a/packages/flet/lib/flet.dart +++ b/packages/flet/lib/flet.dart @@ -14,8 +14,14 @@ export 'src/flet_backend.dart'; export 'src/flet_extension.dart'; export 'src/flet_service.dart'; export 'src/models/asset_source.dart'; +export 'src/models/boot_status.dart'; export 'src/models/control.dart'; export 'src/models/page_size_view_model.dart'; +export 'src/protocol/message.dart'; +export 'src/transport/data_channel.dart'; +export 'src/transport/flet_backend_channel.dart'; +export 'src/transport/flet_msgpack_decoder.dart'; +export 'src/transport/flet_msgpack_encoder.dart'; export 'src/routing/deep_linking_bootstrap.dart'; export 'src/testing/test_finder.dart'; export 'src/testing/tester.dart'; @@ -71,5 +77,7 @@ export 'src/utils/tooltip.dart'; export 'src/utils/transforms.dart'; export 'src/utils/uri.dart'; export 'src/utils/widget_state.dart'; +export 'src/widgets/boot_screen.dart'; export 'src/widgets/error.dart'; +export 'src/widgets/flet_boot_screen.dart'; export 'src/widgets/flet_store_mixin.dart'; diff --git a/packages/flet/lib/src/controls/alert_dialog.dart b/packages/flet/lib/src/controls/alert_dialog.dart index efe6358f52..8110c5a302 100644 --- a/packages/flet/lib/src/controls/alert_dialog.dart +++ b/packages/flet/lib/src/controls/alert_dialog.dart @@ -57,8 +57,7 @@ class _AlertDialogControlState extends State { buttonPadding: control.getPadding("action_button_padding"), shadowColor: control.getColor("shadow_color", context), elevation: control.getDouble("elevation"), - clipBehavior: - parseClip(control.getString("clip_behavior"), Clip.none)!, + clipBehavior: control.getClipBehavior("clip_behavior", Clip.none)!, icon: control.buildIconOrWidget("icon"), iconColor: control.getColor("icon_color", context), scrollable: control.getBool("scrollable", false)!, diff --git a/packages/flet/lib/src/controls/base_controls.dart b/packages/flet/lib/src/controls/base_controls.dart index d95d5c11d6..427aa2521f 100644 --- a/packages/flet/lib/src/controls/base_controls.dart +++ b/packages/flet/lib/src/controls/base_controls.dart @@ -76,7 +76,7 @@ Widget _badge(Widget widget, ThemeData theme, Control control) { } Widget _sizeChangeObserver(Widget widget, Control control) { - if (!control.getBool("on_size_change", false)!) return widget; + if (!control.hasEventHandler("size_change")) return widget; // Opt-in size reporting to avoid extra layout work by default. return SizeChangeObserver( @@ -118,7 +118,7 @@ Widget _opacity(BuildContext context, Widget widget, Control control) { duration: animation.duration, curve: animation.curve, opacity: opacity ?? 1.0, - onEnd: control.getBool("on_animation_end", false)! + onEnd: control.hasEventHandler("animation_end") ? () { control.triggerEvent("animation_end", "opacity"); } @@ -142,7 +142,7 @@ Widget _rotatedControl(BuildContext context, Widget widget, Control control) { tween: Tween(end: rotationDetails?.angle ?? 0), duration: animation.duration, curve: animation.curve, - onEnd: control.getBool("on_animation_end", false)! + onEnd: control.hasEventHandler("animation_end") ? () { control.triggerEvent("animation_end", "rotation"); } @@ -178,7 +178,7 @@ Widget _scaledControl(BuildContext context, Widget widget, Control control) { tween: Tween(end: scaleDetails?.scale ?? 1.0), duration: animation.duration, curve: animation.curve, - onEnd: control.getBool("on_animation_end", false)! + onEnd: control.hasEventHandler("animation_end") ? () { control.triggerEvent("animation_end", "scale"); } @@ -218,7 +218,7 @@ Widget _offsetControl(BuildContext context, Widget widget, Control control) { tween: Tween(end: Offset(offsetDetails.x, offsetDetails.y)), duration: animation.duration, curve: animation.curve, - onEnd: control.getBool("on_animation_end", false)! + onEnd: control.hasEventHandler("animation_end") ? () { control.triggerEvent("animation_end", "offset"); } @@ -296,7 +296,7 @@ Widget _alignedControl(BuildContext context, Widget widget, Control control) { alignment: alignment, duration: animation.duration, curve: animation.curve, - onEnd: control.getBool("on_animation_end", false)! + onEnd: control.hasEventHandler("animation_end") ? () { control.triggerEvent("animation_end", "align"); } @@ -323,7 +323,7 @@ Widget _marginControl(BuildContext context, Widget widget, Control control) { margin: margin, duration: animation.duration, curve: animation.curve, - onEnd: control.getBool("on_animation_end", false)! + onEnd: control.hasEventHandler("animation_end") ? () { control.triggerEvent("animation_end", "margin"); } @@ -441,7 +441,7 @@ class _SizeChangeObserverState extends State { Timer? _timer; void _onSizeChanged(Size size) { - if (!mounted || widget.control.getBool("on_size_change", false) != true) { + if (!mounted || !widget.control.hasEventHandler("size_change")) { return; } @@ -477,7 +477,7 @@ class _SizeChangeObserverState extends State { final remaining = interval - (now - _lastDispatch); final delay = Duration(milliseconds: remaining > 0 ? remaining : 0); _timer = Timer(delay, () { - if (!mounted || !widget.control.getBool("on_size_change", false)!) { + if (!mounted || !widget.control.hasEventHandler("size_change")) { return; } final size = _pendingSize; diff --git a/packages/flet/lib/src/controls/canvas.dart b/packages/flet/lib/src/controls/canvas.dart index 8d6b73c6c9..c602100def 100644 --- a/packages/flet/lib/src/controls/canvas.dart +++ b/packages/flet/lib/src/controls/canvas.dart @@ -343,13 +343,12 @@ class FletCustomPainter extends CustomPainter { void drawColor(Canvas canvas, Control shape) { var color = shape.getColor("color", context, Colors.black)!; - var blendMode = - parseBlendMode(shape.getString("blend_mode"), BlendMode.srcOver)!; + var blendMode = shape.getBlendMode("blend_mode", BlendMode.srcOver)!; canvas.drawColor(color, blendMode); } void drawPoints(Canvas canvas, Control shape) { - var points = parseOffsetList(shape.get("points"))!; + var points = shape.getOffsetList("points")!; var pointMode = ui.PointMode.values.firstWhere( (e) => e.name.toLowerCase() == @@ -456,8 +455,7 @@ class FletCustomPainter extends CustomPainter { final height = shape.getDouble("height"); final img = shape.get("_image") as ui.Image?; - final hashMatch = - img != null && shape.get("_hash") == getImageHash(shape); + final hashMatch = img != null && shape.get("_hash") == getImageHash(shape); // Gapless playback: if we have a cached image, draw it even when the hash // is stale. Without this, src updates leave a blank frame on screen while diff --git a/packages/flet/lib/src/controls/chip.dart b/packages/flet/lib/src/controls/chip.dart index b460cb731c..fd301cb12c 100644 --- a/packages/flet/lib/src/controls/chip.dart +++ b/packages/flet/lib/src/controls/chip.dart @@ -57,9 +57,9 @@ class _ChipControlState extends State { return const ErrorControl("Chip.label must be provided and visible"); } - var onClick = widget.control.getBool("on_click", false)!; - var onDelete = widget.control.getBool("on_delete", false)!; - var onSelect = widget.control.getBool("on_select", false)!; + var onClick = widget.control.hasEventHandler("click"); + var onDelete = widget.control.hasEventHandler("delete"); + var onSelect = widget.control.hasEventHandler("select"); if (onSelect && onClick) { return const ErrorControl( "Chip cannot have both on_select and on_click events specified"); @@ -99,8 +99,7 @@ class _ChipControlState extends State { color: widget.control.getWidgetStateColor("color", Theme.of(context)), pressElevation: widget.control.getDouble("elevation_on_click"), side: widget.control.getBorderSide("border_side", Theme.of(context)), - clipBehavior: - parseClip(widget.control.getString("clip_behavior"), Clip.none)!, + clipBehavior: widget.control.getClipBehavior("clip_behavior", Clip.none)!, visualDensity: widget.control.getVisualDensity("visual_density"), avatarBoxConstraints: widget.control.getBoxConstraints("leading_size_constraints"), diff --git a/packages/flet/lib/src/controls/column.dart b/packages/flet/lib/src/controls/column.dart index 137ac6e800..b5f70ca0cf 100644 --- a/packages/flet/lib/src/controls/column.dart +++ b/packages/flet/lib/src/controls/column.dart @@ -61,7 +61,7 @@ class ColumnControl extends StatelessWidget { child: child, ); - if (control.getBool("on_scroll", false)!) { + if (control.hasEventHandler("scroll")) { child = ScrollNotificationControl(control: control, child: child); } diff --git a/packages/flet/lib/src/controls/container.dart b/packages/flet/lib/src/controls/container.dart index 6044b9cf8d..8700b0c13e 100644 --- a/packages/flet/lib/src/controls/container.dart +++ b/packages/flet/lib/src/controls/container.dart @@ -32,11 +32,11 @@ class ContainerControl extends StatelessWidget with FletStoreMixin { var bgColor = control.getColor("bgcolor", context); var content = control.buildWidget("content"); var ink = control.getBool("ink", false)!; - var onClick = control.getBool("on_click", false)!; - var onTapDown = control.getBool("on_tap_down", false)!; + var onClick = control.hasEventHandler("click"); + var onTapDown = control.hasEventHandler("tap_down"); var url = control.getUrl("url"); - var onLongPress = control.getBool("on_long_press", false)!; - var onHover = control.getBool("on_hover", false)!; + var onLongPress = control.hasEventHandler("long_press"); + var onHover = control.hasEventHandler("hover"); var ignoreInteractions = control.getBool("ignore_interactions", false)!; var animation = control.getAnimation("animate"); var blur = control.getBlur("blur"); @@ -53,7 +53,7 @@ class ContainerControl extends StatelessWidget with FletStoreMixin { var boxDecoration = boxDecorationFromDetails( shape: control.getBoxShape("shape", BoxShape.rectangle)!, color: bgColor, - gradient: parseGradient(control.get("gradient"), Theme.of(context)), + gradient: control.getGradient("gradient", Theme.of(context)), borderRadius: borderRadius, border: control.getBorder("border", Theme.of(context), defaultSideColor: Colors.black), @@ -62,10 +62,10 @@ class ContainerControl extends StatelessWidget with FletStoreMixin { image: decorationImage, ); var boxForegroundDecoration = - parseBoxDecoration(control.get("foreground_decoration"), context); + control.getBoxDecoration("foreground_decoration", context); Widget? container; - var onAnimationEnd = control.getBool("on_animation_end", false)! + var onAnimationEnd = control.hasEventHandler("animation_end") ? () => control.triggerEvent("animation_end", "container") : null; if ((onClick || url != null || onLongPress || onHover || onTapDown) && diff --git a/packages/flet/lib/src/controls/control_widget.dart b/packages/flet/lib/src/controls/control_widget.dart index ae4db35a96..ead9a54c0c 100644 --- a/packages/flet/lib/src/controls/control_widget.dart +++ b/packages/flet/lib/src/controls/control_widget.dart @@ -29,7 +29,19 @@ class ControlWidget extends StatelessWidget { FletBackend.of(context).globalKeys[controlKey.toString()] = key as GlobalKey; } else if (controlKey != null) { - key = ValueKey(controlKey.value); + // Preserve the concrete value type so the resulting ValueKey matches + // what callers construct in tests, e.g. `find.byKey(Key('foo'))` which + // resolves to `ValueKey('foo')`. `ValueKey(controlKey.value)` + // would produce `ValueKey(...)` because `controlKey.value` is + // statically typed `Object`, and ValueKey's `==` is runtimeType-strict + // — `ValueKey` is never equal to `ValueKey`. + key = switch (controlKey.value) { + String v => ValueKey(v), + int v => ValueKey(v), + double v => ValueKey(v), + bool v => ValueKey(v), + _ => ValueKey(controlKey.value), + }; } return control.buildInControlContext((context) { diff --git a/packages/flet/lib/src/controls/cupertino_list_tile.dart b/packages/flet/lib/src/controls/cupertino_list_tile.dart index c2f6d24756..ebab294b70 100644 --- a/packages/flet/lib/src/controls/cupertino_list_tile.dart +++ b/packages/flet/lib/src/controls/cupertino_list_tile.dart @@ -36,7 +36,7 @@ class CupertinoListTileControl extends StatelessWidget { var leadingSize = control.getDouble("leading_size", notched ? 30.0 : 28.0)!; var leadingToTitle = control.getDouble("leading_to_title", notched ? 12.0 : 16.0)!; - var onclick = control.getBool("on_click", false)!; + var onclick = control.hasEventHandler("click"); var toggleInputs = control.getBool("toggle_inputs", false)!; var url = control.getUrl("url"); diff --git a/packages/flet/lib/src/controls/cupertino_textfield.dart b/packages/flet/lib/src/controls/cupertino_textfield.dart index 62bdb0e163..66a3c4e564 100644 --- a/packages/flet/lib/src/controls/cupertino_textfield.dart +++ b/packages/flet/lib/src/controls/cupertino_textfield.dart @@ -164,7 +164,7 @@ class _CupertinoTextFieldControlState extends State { var readOnly = widget.control.getBool("read_only", false)!; var password = widget.control.getBool("password", false)!; - var onChange = widget.control.getBool("on_change", false)!; + var onChange = widget.control.hasEventHandler("change"); var cursorColor = widget.control.getColor("cursor_color", context); var selectionColor = widget.control.getColor("selection_color", context); @@ -357,7 +357,7 @@ class _CupertinoTextFieldControlState extends State { onTap: () => widget.control.triggerEvent("click"), controller: _controller, focusNode: focusNode, - onTapOutside: widget.control.getBool("on_tap_outside", false)! + onTapOutside: widget.control.hasEventHandler("tap_outside") ? (PointerDownEvent? event) { widget.control.triggerEvent("tap_outside"); } diff --git a/packages/flet/lib/src/controls/datatable.dart b/packages/flet/lib/src/controls/datatable.dart index 35a721523e..76fc869b66 100644 --- a/packages/flet/lib/src/controls/datatable.dart +++ b/packages/flet/lib/src/controls/datatable.dart @@ -52,7 +52,7 @@ class DataTableControl extends StatelessWidget { horizontalInside: horizontalLines ?? BorderSide.none, verticalInside: verticalLines ?? BorderSide.none) : null, - clipBehavior: parseClip(control.getString("clip_behavior"), Clip.none)!, + clipBehavior: control.getClipBehavior("clip_behavior", Clip.none)!, checkboxHorizontalMargin: control.getDouble("checkbox_horizontal_margin"), columnSpacing: control.getDouble("column_spacing"), dataRowColor: control.getWidgetStateColor("data_row_color", theme), @@ -68,7 +68,7 @@ class DataTableControl extends StatelessWidget { showCheckboxColumn: control.getBool("show_checkbox_column", false)!, sortAscending: control.getBool("sort_ascending", false)!, sortColumnIndex: control.getInt("sort_column_index"), - onSelectAll: control.getBool("on_select_all", false)! + onSelectAll: control.hasEventHandler("select_all") ? (bool? selected) => control.triggerEvent("select_all", selected) : null, columns: control.children("columns").map((column) { @@ -81,7 +81,7 @@ class DataTableControl extends StatelessWidget { headingRowAlignment: column.getMainAxisAlignment("heading_row_alignment"), mouseCursor: WidgetStateMouseCursor.clickable, - onSort: column.getBool("on_sort", false)! + onSort: column.hasEventHandler("sort") ? (columnIndex, ascending) => column .triggerEvent("sort", {"ci": columnIndex, "asc": ascending}) : null, @@ -94,10 +94,10 @@ class DataTableControl extends StatelessWidget { key: ValueKey(row.id), selected: row.getBool("selected", false)!, color: row.getWidgetStateColor("color", theme), - onSelectChanged: row.getBool("on_select_change", false)! + onSelectChanged: row.hasEventHandler("select_change") ? (selected) => row.triggerEvent("select_change", selected) : null, - onLongPress: row.getBool("on_long_press", false)! + onLongPress: row.hasEventHandler("long_press") ? () => row.triggerEvent("long_press") : null, cells: row.children("cells").map((cell) { @@ -106,19 +106,19 @@ class DataTableControl extends StatelessWidget { cell.buildTextOrWidget("content")!, placeholder: cell.getBool("placeholder", false)!, showEditIcon: cell.getBool("show_edit_icon", false)!, - onDoubleTap: cell.getBool("on_double_tap", false)! + onDoubleTap: cell.hasEventHandler("double_tap") ? () => cell.triggerEvent("double_tap") : null, - onLongPress: cell.getBool("on_long_press", false)! + onLongPress: cell.hasEventHandler("long_press") ? () => cell.triggerEvent("long_press") : null, - onTap: cell.getBool("on_tap", false)! + onTap: cell.hasEventHandler("tap") ? () => cell.triggerEvent("tap") : null, - onTapCancel: cell.getBool("on_tap_cancel", false)! + onTapCancel: cell.hasEventHandler("tap_cancel") ? () => cell.triggerEvent("tap_cancel") : null, - onTapDown: cell.getBool("on_tap_down", false)! + onTapDown: cell.hasEventHandler("tap_down") ? (TapDownDetails details) => cell.triggerEvent("tap_down", details.toMap()) : null, diff --git a/packages/flet/lib/src/controls/dismissible.dart b/packages/flet/lib/src/controls/dismissible.dart index a356f85db5..d377c19d56 100644 --- a/packages/flet/lib/src/controls/dismissible.dart +++ b/packages/flet/lib/src/controls/dismissible.dart @@ -60,14 +60,14 @@ class _DismissibleControlState extends State { "dismiss_direction", DismissDirection.horizontal)!, background: widget.control.buildWidget("background"), secondaryBackground: widget.control.buildWidget("secondary_background"), - onDismissed: widget.control.getBool("on_dismiss", false)! + onDismissed: widget.control.hasEventHandler("dismiss") ? (DismissDirection direction) => widget.control .triggerEvent("dismiss", {"direction": direction.name}) : null, - onResize: widget.control.getBool("on_resize", false)! + onResize: widget.control.hasEventHandler("resize") ? () => widget.control.triggerEvent("resize") : null, - onUpdate: widget.control.getBool("on_update", false)! + onUpdate: widget.control.hasEventHandler("update") ? (DismissUpdateDetails details) { widget.control.triggerEvent( "update", @@ -79,7 +79,7 @@ class _DismissibleControlState extends State { .toMap()); } : null, - confirmDismiss: widget.control.getBool("on_confirm_dismiss", false)! + confirmDismiss: widget.control.hasEventHandler("confirm_dismiss") ? (DismissDirection direction) { var completer = Completer(); widget.control @@ -92,8 +92,8 @@ class _DismissibleControlState extends State { ); } : null, - movementDuration: widget.control - .getDuration("movement_duration", const Duration(milliseconds: 200))!, + movementDuration: widget.control.getDuration( + "movement_duration", const Duration(milliseconds: 200))!, resizeDuration: widget.control .getDuration("resize_duration", const Duration(milliseconds: 300))!, crossAxisEndOffset: diff --git a/packages/flet/lib/src/controls/expansion_panel.dart b/packages/flet/lib/src/controls/expansion_panel.dart index 95be68a093..adccc1710e 100644 --- a/packages/flet/lib/src/controls/expansion_panel.dart +++ b/packages/flet/lib/src/controls/expansion_panel.dart @@ -62,7 +62,7 @@ class ExpansionPanelListControl extends StatelessWidget { child: panelList, ); - if (control.getBool("on_scroll", false)!) { + if (control.hasEventHandler("scroll")) { result = ScrollNotificationControl(control: control, child: result); } diff --git a/packages/flet/lib/src/controls/flet_app_control.dart b/packages/flet/lib/src/controls/flet_app_control.dart index 34fbb0cc4d..b4d16247b2 100644 --- a/packages/flet/lib/src/controls/flet_app_control.dart +++ b/packages/flet/lib/src/controls/flet_app_control.dart @@ -34,10 +34,11 @@ class _FletAppControlState extends State { } var reconnectIntervalMs = widget.control.getInt("reconnect_interval_ms"); var reconnectTimeoutMs = widget.control.getInt("reconnect_timeout_ms"); - var showAppStartupScreen = - widget.control.getBool("show_app_startup_screen"); - var appStartupScreenMessage = - widget.control.getString("app_startup_screen_message"); + var bootScreenName = widget.control.getString("boot_screen_name", "flet")!; + var rawBootScreenOptions = widget.control.get("boot_screen_options"); + var bootScreenOptions = rawBootScreenOptions is Map + ? Map.from(rawBootScreenOptions) + : {}; var appErrorMessage = widget.control.getString("app_error_message"); return LayoutControl( @@ -46,11 +47,11 @@ class _FletAppControlState extends State { controlId: widget.control.id, reconnectIntervalMs: reconnectIntervalMs, reconnectTimeoutMs: reconnectTimeoutMs, - showAppStartupScreen: showAppStartupScreen, - appStartupScreenMessage: appStartupScreenMessage, + bootScreenName: bootScreenName, + bootScreenOptions: bootScreenOptions, appErrorMessage: appErrorMessage, pageUrl: url, - assetsDir: widget.control.getString("assets_dir") ?? "", + assetsDir: widget.control.getString("assets_dir", "")!, errorsHandler: _errorsHandler, extensions: FletBackend.of(context).extensions, args: widget.control.get("args") != null diff --git a/packages/flet/lib/src/controls/floating_action_button.dart b/packages/flet/lib/src/controls/floating_action_button.dart index 3a8eabbae1..9c56bc6f46 100644 --- a/packages/flet/lib/src/controls/floating_action_button.dart +++ b/packages/flet/lib/src/controls/floating_action_button.dart @@ -37,8 +37,7 @@ class FloatingActionButtonControl extends StatelessWidget { var hoverColor = control.getColor("hover_color", context); var focusColor = control.getColor("focus_color", context); var shape = control.getShape("shape", Theme.of(context)); - var clipBehavior = - parseClip(control.getString("clip_behavior"), Clip.none)!; + var clipBehavior = control.getClipBehavior("clip_behavior", Clip.none)!; var autofocus = control.getBool("autofocus", false)!; var mini = control.getBool("mini", false)!; var enableFeedback = control.getBool("enable_feedback"); diff --git a/packages/flet/lib/src/controls/gesture_detector.dart b/packages/flet/lib/src/controls/gesture_detector.dart index 1cee33ab56..4c9d1198c5 100644 --- a/packages/flet/lib/src/controls/gesture_detector.dart +++ b/packages/flet/lib/src/controls/gesture_detector.dart @@ -58,108 +58,99 @@ class _GestureDetectorControlState extends State { var content = widget.control.buildWidget("content"); - var onHover = widget.control.getBool("on_hover", false)!; - var onEnter = widget.control.getBool("on_enter", false)!; - var onExit = widget.control.getBool("on_exit", false)!; - var onTap = widget.control.getBool("on_tap", false)!; - var onTapDown = widget.control.getBool("on_tap_down", false)!; - var onTapUp = widget.control.getBool("on_tap_up", false)!; - var onTapMove = widget.control.getBool("on_tap_move", false)!; - var onTapCancel = widget.control.getBool("on_tap_cancel", false)!; - var onSecondaryTap = widget.control.getBool("on_secondary_tap", false)!; + var onHover = widget.control.hasEventHandler("hover"); + var onEnter = widget.control.hasEventHandler("enter"); + var onExit = widget.control.hasEventHandler("exit"); + var onTap = widget.control.hasEventHandler("tap"); + var onTapDown = widget.control.hasEventHandler("tap_down"); + var onTapUp = widget.control.hasEventHandler("tap_up"); + var onTapMove = widget.control.hasEventHandler("tap_move"); + var onTapCancel = widget.control.hasEventHandler("tap_cancel"); + var onSecondaryTap = widget.control.hasEventHandler("secondary_tap"); var onSecondaryTapDown = - widget.control.getBool("on_secondary_tap_down", false)!; - var onSecondaryTapUp = - widget.control.getBool("on_secondary_tap_up", false)!; + widget.control.hasEventHandler("secondary_tap_down"); + var onSecondaryTapUp = widget.control.hasEventHandler("secondary_tap_up"); var onSecondaryTapCancel = - widget.control.getBool("on_secondary_tap_cancel", false)!; - var onTertiaryTapDown = - widget.control.getBool("on_tertiary_tap_down", false)!; - var onTertiaryTapUp = widget.control.getBool("on_tertiary_tap_up", false)!; + widget.control.hasEventHandler("secondary_tap_cancel"); + var onTertiaryTapDown = widget.control.hasEventHandler("tertiary_tap_down"); + var onTertiaryTapUp = widget.control.hasEventHandler("tertiary_tap_up"); var onTertiaryTapCancel = - widget.control.getBool("on_tertiary_tap_cancel", false)!; - var onDoubleTap = widget.control.getBool("on_double_tap", false)!; - var onDoubleTapDown = widget.control.getBool("on_double_tap_down", false)!; - var onDoubleTapCancel = - widget.control.getBool("on_double_tap_cancel", false)!; - var onLongPressDown = widget.control.getBool("on_long_press_down", false)!; - var onLongPressCancel = - widget.control.getBool("on_long_press_cancel", false)!; - var onLongPress = widget.control.getBool("on_long_press", false)!; - var onLongPressStart = - widget.control.getBool("on_long_press_start", false)!; + widget.control.hasEventHandler("tertiary_tap_cancel"); + var onDoubleTap = widget.control.hasEventHandler("double_tap"); + var onDoubleTapDown = widget.control.hasEventHandler("double_tap_down"); + var onDoubleTapCancel = widget.control.hasEventHandler("double_tap_cancel"); + var onLongPressDown = widget.control.hasEventHandler("long_press_down"); + var onLongPressCancel = widget.control.hasEventHandler("long_press_cancel"); + var onLongPress = widget.control.hasEventHandler("long_press"); + var onLongPressStart = widget.control.hasEventHandler("long_press_start"); var onLongPressMoveUpdate = - widget.control.getBool("on_long_press_move_update", false)!; - var onLongPressUp = widget.control.getBool("on_long_press_up", false)!; - var onLongPressEnd = widget.control.getBool("on_long_press_end", false)!; + widget.control.hasEventHandler("long_press_move_update"); + var onLongPressUp = widget.control.hasEventHandler("long_press_up"); + var onLongPressEnd = widget.control.hasEventHandler("long_press_end"); var onSecondaryLongPressDown = - widget.control.getBool("on_secondary_long_press_down", false)!; + widget.control.hasEventHandler("secondary_long_press_down"); var onSecondaryLongPressCancel = - widget.control.getBool("on_secondary_long_press_cancel", false)!; + widget.control.hasEventHandler("secondary_long_press_cancel"); var onSecondaryLongPress = - widget.control.getBool("on_secondary_long_press", false)!; + widget.control.hasEventHandler("secondary_long_press"); var onSecondaryLongPressStart = - widget.control.getBool("on_secondary_long_press_start", false)!; + widget.control.hasEventHandler("secondary_long_press_start"); var onSecondaryLongPressMoveUpdate = - widget.control.getBool("on_secondary_long_press_move_update", false)!; + widget.control.hasEventHandler("secondary_long_press_move_update"); var onSecondaryLongPressUp = - widget.control.getBool("on_secondary_long_press_up", false)!; + widget.control.hasEventHandler("secondary_long_press_up"); var onSecondaryLongPressEnd = - widget.control.getBool("on_secondary_long_press_end", false)!; + widget.control.hasEventHandler("secondary_long_press_end"); var onTertiaryLongPressDown = - widget.control.getBool("on_tertiary_long_press_down", false)!; + widget.control.hasEventHandler("tertiary_long_press_down"); var onTertiaryLongPressCancel = - widget.control.getBool("on_tertiary_long_press_cancel", false)!; + widget.control.hasEventHandler("tertiary_long_press_cancel"); var onTertiaryLongPress = - widget.control.getBool("on_tertiary_long_press", false)!; + widget.control.hasEventHandler("tertiary_long_press"); var onTertiaryLongPressStart = - widget.control.getBool("on_tertiary_long_press_start", false)!; + widget.control.hasEventHandler("tertiary_long_press_start"); var onTertiaryLongPressMoveUpdate = - widget.control.getBool("on_tertiary_long_press_move_update", false)!; + widget.control.hasEventHandler("tertiary_long_press_move_update"); var onTertiaryLongPressUp = - widget.control.getBool("on_tertiary_long_press_up", false)!; + widget.control.hasEventHandler("tertiary_long_press_up"); var onTertiaryLongPressEnd = - widget.control.getBool("on_tertiary_long_press_end", false)!; + widget.control.hasEventHandler("tertiary_long_press_end"); var onHorizontalDragDown = - widget.control.getBool("on_horizontal_drag_down", false)!; + widget.control.hasEventHandler("horizontal_drag_down"); var onHorizontalDragStart = - widget.control.getBool("on_horizontal_drag_start", false)!; + widget.control.hasEventHandler("horizontal_drag_start"); var onHorizontalDragUpdate = - widget.control.getBool("on_horizontal_drag_update", false)!; + widget.control.hasEventHandler("horizontal_drag_update"); var onHorizontalDragEnd = - widget.control.getBool("on_horizontal_drag_end", false)!; + widget.control.hasEventHandler("horizontal_drag_end"); var onHorizontalDragCancel = - widget.control.getBool("on_horizontal_drag_cancel", false)!; + widget.control.hasEventHandler("horizontal_drag_cancel"); var onVerticalDragDown = - widget.control.getBool("on_vertical_drag_down", false)!; + widget.control.hasEventHandler("vertical_drag_down"); var onVerticalDragStart = - widget.control.getBool("on_vertical_drag_start", false)!; + widget.control.hasEventHandler("vertical_drag_start"); var onVerticalDragUpdate = - widget.control.getBool("on_vertical_drag_update", false)!; - var onVerticalDragEnd = - widget.control.getBool("on_vertical_drag_end", false)!; + widget.control.hasEventHandler("vertical_drag_update"); + var onVerticalDragEnd = widget.control.hasEventHandler("vertical_drag_end"); var onVerticalDragCancel = - widget.control.getBool("on_vertical_drag_cancel", false)!; - var onPanDown = widget.control.getBool("on_pan_down", false)!; - var onPanStart = widget.control.getBool("on_pan_start", false)!; - var onPanUpdate = widget.control.getBool("on_pan_update", false)!; - var onPanEnd = widget.control.getBool("on_pan_end", false)!; - var onPanCancel = widget.control.getBool("on_pan_cancel", false)!; - var onScaleStart = widget.control.getBool("on_scale_start", false)!; - var onScaleUpdate = widget.control.getBool("on_scale_update", false)!; - var onScaleEnd = widget.control.getBool("on_scale_end", false)!; - var onForcePressStart = - widget.control.getBool("on_force_press_start", false)!; - var onForcePressPeak = - widget.control.getBool("on_force_press_peak", false)!; + widget.control.hasEventHandler("vertical_drag_cancel"); + var onPanDown = widget.control.hasEventHandler("pan_down"); + var onPanStart = widget.control.hasEventHandler("pan_start"); + var onPanUpdate = widget.control.hasEventHandler("pan_update"); + var onPanEnd = widget.control.hasEventHandler("pan_end"); + var onPanCancel = widget.control.hasEventHandler("pan_cancel"); + var onScaleStart = widget.control.hasEventHandler("scale_start"); + var onScaleUpdate = widget.control.hasEventHandler("scale_update"); + var onScaleEnd = widget.control.hasEventHandler("scale_end"); + var onForcePressStart = widget.control.hasEventHandler("force_press_start"); + var onForcePressPeak = widget.control.hasEventHandler("force_press_peak"); var onForcePressUpdate = - widget.control.getBool("on_force_press_update", false)!; - var onForcePressEnd = widget.control.getBool("on_force_press_end", false)!; - var onMultiTap = widget.control.getBool("on_multi_tap", false)!; - var onMultiLongPress = - widget.control.getBool("on_multi_long_press", false)!; + widget.control.hasEventHandler("force_press_update"); + var onForcePressEnd = widget.control.hasEventHandler("force_press_end"); + var onMultiTap = widget.control.hasEventHandler("multi_tap"); + var onMultiLongPress = widget.control.hasEventHandler("multi_long_press"); var multiTapTouches = widget.control.getInt("multi_tap_touches", 0)!; - var onScroll = widget.control.getBool("on_scroll", false)!; + var onScroll = widget.control.hasEventHandler("scroll"); Widget? result = content; @@ -651,10 +642,9 @@ class _GestureDetectorControlState extends State { ) : result; - var onRightPanStart = widget.control.getBool("on_right_pan_start", false)!; - var onRightPanUpdate = - widget.control.getBool("on_right_pan_update", false)!; - var onRightPanEnd = widget.control.getBool("on_right_pan_end", false)!; + var onRightPanStart = widget.control.hasEventHandler("right_pan_start"); + var onRightPanUpdate = widget.control.hasEventHandler("right_pan_update"); + var onRightPanEnd = widget.control.hasEventHandler("right_pan_end"); if (onScroll || onRightPanStart || onRightPanUpdate || onRightPanEnd) { result = Listener( @@ -701,8 +691,7 @@ class _GestureDetectorControlState extends State { ); } - var mouseCursor = - parseMouseCursor(widget.control.getString("mouse_cursor")); + var mouseCursor = widget.control.getMouseCursor("mouse_cursor"); result = ((mouseCursor != null) || onHover || onEnter || onExit) ? MouseRegion( cursor: mouseCursor ?? MouseCursor.defer, diff --git a/packages/flet/lib/src/controls/grid_view.dart b/packages/flet/lib/src/controls/grid_view.dart index 481f5732a3..aba620aacb 100644 --- a/packages/flet/lib/src/controls/grid_view.dart +++ b/packages/flet/lib/src/controls/grid_view.dart @@ -134,7 +134,7 @@ class _GridViewControlState extends State { scrollController: _controller, child: child); - if (widget.control.getBool("on_scroll", false)!) { + if (widget.control.hasEventHandler("scroll")) { child = ScrollNotificationControl(control: widget.control, child: child); } diff --git a/packages/flet/lib/src/controls/interactive_viewer.dart b/packages/flet/lib/src/controls/interactive_viewer.dart index 84fa56cd16..916beafe2a 100644 --- a/packages/flet/lib/src/controls/interactive_viewer.dart +++ b/packages/flet/lib/src/controls/interactive_viewer.dart @@ -139,7 +139,7 @@ class _InteractiveViewerControlState extends State .getDouble("interaction_end_friction_coefficient", 0.0000135)!, scaleFactor: widget.control.getDouble("scale_factor", 200)!, clipBehavior: - parseClip(widget.control.getString("clip_behavior"), Clip.hardEdge)!, + widget.control.getClipBehavior("clip_behavior", Clip.hardEdge)!, alignment: widget.control.get("alignment"), boundaryMargin: widget.control.getMargin("boundary_margin", EdgeInsets.zero)!, diff --git a/packages/flet/lib/src/controls/list_tile.dart b/packages/flet/lib/src/controls/list_tile.dart index 629c7be3cc..6aa011e766 100644 --- a/packages/flet/lib/src/controls/list_tile.dart +++ b/packages/flet/lib/src/controls/list_tile.dart @@ -45,7 +45,7 @@ class ListTileControl extends StatelessWidget with FletStoreMixin { var title = control.buildTextOrWidget("title"); var subtitle = control.buildTextOrWidget("subtitle"); var trailing = control.buildIconOrWidget("trailing"); - var onClick = control.getBool("on_click", false)!; + var onClick = control.hasEventHandler("click"); var toggleInputs = control.getBool("toggle_inputs", false)!; var url = control.getUrl("url"); @@ -65,7 +65,7 @@ class ListTileControl extends StatelessWidget with FletStoreMixin { : null; Function()? onLongPress = - control.getBool("on_long_press", false)! && !control.disabled + control.hasEventHandler("long_press") && !control.disabled ? () { control.triggerEvent("long_press"); } diff --git a/packages/flet/lib/src/controls/list_view.dart b/packages/flet/lib/src/controls/list_view.dart index 823515b394..a42f5ff23e 100644 --- a/packages/flet/lib/src/controls/list_view.dart +++ b/packages/flet/lib/src/controls/list_view.dart @@ -50,7 +50,7 @@ class _ListViewControlState extends State { var padding = widget.control.getPadding("padding"); var reverse = widget.control.getBool("reverse", false)!; var clipBehavior = - parseClip(widget.control.getString("clip_behavior"), Clip.hardEdge)!; + widget.control.getClipBehavior("clip_behavior", Clip.hardEdge)!; var scrollDirection = horizontal ? Axis.horizontal : Axis.vertical; var buildControlsOnDemand = widget.control.getBool("build_controls_on_demand", true)!; @@ -173,7 +173,7 @@ class _ListViewControlState extends State { scrollController: _controller, child: child); - if (widget.control.getBool("on_scroll", false)!) { + if (widget.control.hasEventHandler("scroll")) { child = ScrollNotificationControl(control: widget.control, child: child); } diff --git a/packages/flet/lib/src/controls/menu_item_button.dart b/packages/flet/lib/src/controls/menu_item_button.dart index 15892640ac..68620e9f19 100644 --- a/packages/flet/lib/src/controls/menu_item_button.dart +++ b/packages/flet/lib/src/controls/menu_item_button.dart @@ -57,8 +57,8 @@ class _MenuItemButtonControlState extends State { ? const StadiumBorder() : RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))); - bool onClick = widget.control.getBool("on_click", false)!; - bool onHover = widget.control.getBool("on_hover", false)!; + bool onClick = widget.control.hasEventHandler("click"); + bool onHover = widget.control.hasEventHandler("hover"); var menuItem = MenuItemButton( focusNode: _focusNode, diff --git a/packages/flet/lib/src/controls/navigation_rail.dart b/packages/flet/lib/src/controls/navigation_rail.dart index 08d7cc3d25..0b6c9906e6 100644 --- a/packages/flet/lib/src/controls/navigation_rail.dart +++ b/packages/flet/lib/src/controls/navigation_rail.dart @@ -94,7 +94,12 @@ class _NavigationRailControlState extends State destinations: widget.control.children("destinations").map((destinationControl) { destinationControl.notifyParent = true; - var icon = destinationControl.buildIconOrWidget("icon")!; + var icon = destinationControl.buildIconOrWidget("icon", + required: true, + errorWidget: const ErrorControl( + "Error displaying NavigationRailDestination.icon", + description: + "Must be a valid IconData or visible Control"))!; Widget? selectedIcon = destinationControl.buildIconOrWidget("selected_icon"); return NavigationRailDestination( diff --git a/packages/flet/lib/src/controls/page.dart b/packages/flet/lib/src/controls/page.dart index 826535fa43..00addab21f 100644 --- a/packages/flet/lib/src/controls/page.dart +++ b/packages/flet/lib/src/controls/page.dart @@ -37,7 +37,7 @@ import '../utils/theme.dart'; import '../utils/time.dart'; import '../utils/user_fonts.dart'; import '../widgets/animated_transition_page.dart'; -import '../widgets/loading_page.dart'; +import '../widgets/boot_screen.dart'; import '../widgets/page_context.dart'; import '../widgets/page_media.dart'; import 'control_widget.dart'; @@ -285,8 +285,7 @@ class _PageControlState extends State with WidgetsBindingObserver { final pixelRatio = parseDouble( args["pixel_ratio"], MediaQuery.of(ctx).devicePixelRatio)!; final image = await boundary.toImage(pixelRatio: pixelRatio); - final data = - await image.toByteData(format: ui.ImageByteFormat.png); + final data = await image.toByteData(format: ui.ImageByteFormat.png); image.dispose(); if (data == null) return frames; frames.add(data.buffer.asUint8List()); @@ -387,7 +386,7 @@ class _PageControlState extends State with WidgetsBindingObserver { final topView = views.last; final canPop = topView.getBool("can_pop", true) ?? true; - final requiresConfirm = topView.getBool("on_confirm_pop", false) ?? false; + final requiresConfirm = topView.hasEventHandler("confirm_pop"); if (!canPop || requiresConfirm) { return null; } @@ -436,12 +435,12 @@ class _PageControlState extends State with WidgetsBindingObserver { } void _attachKeyboardListenerIfNeeded() { - var onKeyboardEvent = widget.control.getBool("on_keyboard_event", false); + var onKeyboardEvent = widget.control.hasEventHandler("keyboard_event"); if (onKeyboardEvent != _prevOnKeyboardEvent) { - if (onKeyboardEvent == true && !_keyboardHandlerSubscribed) { + if (onKeyboardEvent && !_keyboardHandlerSubscribed) { HardwareKeyboard.instance.addHandler(_handleKeyDown); _keyboardHandlerSubscribed = true; - } else if (onKeyboardEvent == false && _keyboardHandlerSubscribed) { + } else if (!onKeyboardEvent && _keyboardHandlerSubscribed) { HardwareKeyboard.instance.removeHandler(_handleKeyDown); _keyboardHandlerSubscribed = false; } @@ -480,13 +479,6 @@ class _PageControlState extends State with WidgetsBindingObserver { return _buildApp(widget.control, null); } else { // multi-view mode - var appStatus = context - .select((backend) => - (isLoading: backend.isLoading, error: backend.error)); - var appStartupScreenMessage = backend.appStartupScreenMessage ?? ""; - var formattedErrorMessage = - backend.formatAppErrorMessage(appStatus.error); - List views = []; for (var view in _multiViews.entries) { var multiViewControl = widget.control @@ -502,12 +494,12 @@ class _PageControlState extends State with WidgetsBindingObserver { ? ControlWidget(control: viewControl) : Stack(children: [ PageMedia(view: multiViewControl), - LoadingPage( - isLoading: appStatus.isLoading, - message: appStatus.isLoading - ? appStartupScreenMessage - : formattedErrorMessage, - ) + resolveBootScreen( + name: backend.bootScreenName, + options: backend.bootScreenOptions, + extensions: backend.extensions, + status: backend.bootStatus, + ), ]), ); @@ -664,13 +656,6 @@ class _PageControlState extends State with WidgetsBindingObserver { debugPrint("Page navigator build: ${widget.control.id}"); var backend = FletBackend.of(context); - var showAppStartupScreen = backend.showAppStartupScreen ?? false; - var appStartupScreenMessage = backend.appStartupScreenMessage ?? ""; - - var appStatus = - context.select( - (backend) => (isLoading: backend.isLoading, error: backend.error)); - var formattedErrorMessage = backend.formatAppErrorMessage(appStatus.error); var views = widget.control.children("views"); final viewRouteValues = views @@ -694,19 +679,15 @@ class _PageControlState extends State with WidgetsBindingObserver { pages.add(AnimatedTransitionPage( fadeTransition: true, duration: Duration.zero, - child: showAppStartupScreen - ? Stack(children: [ - const PageMedia(), - LoadingPage( - isLoading: appStatus.isLoading, - message: appStatus.isLoading - ? appStartupScreenMessage - : formattedErrorMessage, - ) - ]) - : const Scaffold( - body: PageMedia(), - ))); + child: Stack(children: [ + const PageMedia(), + resolveBootScreen( + name: backend.bootScreenName, + options: backend.bootScreenOptions, + extensions: backend.extensions, + status: backend.bootStatus, + ), + ]))); } else { String viewRoutes = effectiveViews .map((v) => v.getString("route", v.id.toString())) diff --git a/packages/flet/lib/src/controls/progress_ring.dart b/packages/flet/lib/src/controls/progress_ring.dart index 45efca077d..02c1610656 100644 --- a/packages/flet/lib/src/controls/progress_ring.dart +++ b/packages/flet/lib/src/controls/progress_ring.dart @@ -33,7 +33,7 @@ class ProgressRingControl extends StatelessWidget { padding: control.getPadding("padding"), // ignore: deprecated_member_use year2023: control.getBool( - "year2023"), // todo: deprecated and to be removed in future versions + "year_2023"), // todo: deprecated and to be removed in future versions ); return LayoutControl(control: control, child: indicator); } diff --git a/packages/flet/lib/src/controls/raw_image.dart b/packages/flet/lib/src/controls/raw_image.dart new file mode 100644 index 0000000000..dce06b9266 --- /dev/null +++ b/packages/flet/lib/src/controls/raw_image.dart @@ -0,0 +1,188 @@ +import 'dart:async'; +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; + +import '../flet_backend.dart'; +import '../models/control.dart'; +import '../transport/data_channel.dart'; +import '../utils/images.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; + +/// Display widget for pixel-frame streams pushed from Python. +/// +/// Frames arrive over a dedicated [DataChannel] rather than the regular +/// Flet protocol, so the bytes skip MsgPack encode/decode. At most one +/// decoded [ui.Image] is alive at a time: each applied frame replaces the +/// previous one, which is disposed in a post-frame callback. That bound is +/// what keeps the widget safe on Flutter web (CanvasKit/WASM), where Dart +/// GC doesn't promptly reclaim native SkImage refs. +/// +/// Wire format on the data channel (one opcode byte + payload): +/// +/// [0x01][encoded bytes] → decode (PNG/JPEG/WebP), replace +/// [0x03] → clear +/// [0x04][w u32 LE][h u32 LE][RGBA8888] → raw full frame (premultiplied) +/// +/// After every applied frame the widget sends a 1-byte `[0xFF]` ack back +/// to Python — the producer awaits it, which is the backpressure that +/// paces `render()` loops to display speed. +class RawImageControl extends StatefulWidget { + final Control control; + + RawImageControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); + + @override + State createState() => _RawImageControlState(); +} + +class _RawImageControlState extends State { + // Serialize concurrent frame applies so swaps happen in arrival order. + Future? _applyChain; + + DataChannel? _channel; + StreamSubscription? _channelSub; + + ui.Image? _image; + + // 1-byte ack sent back to Python after each apply completes; the Python + // side awaits it, giving `render()` its round-trip backpressure. + static final Uint8List _frameAppliedAck = Uint8List.fromList([0xFF]); + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // Open the data channel lazily on first dependency lookup — we need + // BuildContext to reach FletBackend, which isn't available in initState. + if (_channel != null) return; + _channel = FletBackend.of(context).openDataChannel(); + _channelSub = _channel!.messages.listen(_onChannelFrame); + // Announce the channel to Python via the standard convention event. + widget.control.triggerEvent("data_channel_open", { + "channel_name": "frames", + "channel_id": _channel!.id, + }); + } + + @override + void dispose() { + _channelSub?.cancel(); + _channelSub = null; + _channel?.close(); + _channel = null; + _image?.dispose(); + _image = null; + super.dispose(); + } + + /// Inbound DataChannel frame. Wire format: + /// [0x01][encoded bytes] → apply encoded (PNG/JPEG/WebP) + /// [0x03] → clear + /// [0x04][w u32 LE][h u32 LE][RGBA8888] → apply raw (premultiplied) + void _onChannelFrame(Uint8List bytes) { + if (bytes.isEmpty) return; + // Zero-copy slice of the same underlying buffer. + final payload = Uint8List.sublistView(bytes, 1); + switch (bytes[0]) { + case 0x01: + _enqueueAndAck(() => _applyEncoded(payload)); + break; + case 0x03: + _enqueueAndAck(_clear); + break; + case 0x04: + _enqueueAndAck(() => _applyRaw(payload)); + break; + default: + debugPrint( + "RawImage: unknown data-channel opcode 0x${bytes[0].toRadixString(16)}"); + // Ack anyway so a newer Python side never hangs its render loop + // waiting on a frame this (older) client can't apply. + _channel?.send(_frameAppliedAck); + } + } + + void _enqueueAndAck(Future Function() task) { + final prev = _applyChain ?? Future.value(); + final next = prev.then((_) => task()); + _applyChain = next.catchError((_) {}); + next.whenComplete(() { + _channel?.send(_frameAppliedAck); + }); + } + + Future _applyEncoded(Uint8List bytes) async { + if (bytes.isEmpty) { + debugPrint("RawImage: skipping empty image bytes"); + return; + } + // Defensive copy; Safari's WASM runtime can free underlying buffers + // across async boundaries and trigger "EncodingError: Loading error.". + final owned = Uint8List.fromList(bytes); + ui.Codec? codec; + try { + codec = await ui.instantiateImageCodec(owned, allowUpscaling: false); + final frame = await codec.getNextFrame(); + _swapImage(frame.image); + } catch (e) { + debugPrint("RawImage: decode failed (${owned.length} bytes): $e"); + } finally { + codec?.dispose(); + } + } + + Future _applyRaw(Uint8List payload) async { + if (payload.length < 8) return; + final bd = ByteData.sublistView(payload, 0, 8); + final w = bd.getUint32(0, Endian.little); + final h = bd.getUint32(4, Endian.little); + if (w == 0 || h == 0 || payload.length - 8 != w * h * 4) { + // Skip the frame; the ack still goes out via `_enqueueAndAck`, so + // Python never stalls on a bad frame. + debugPrint("RawImage: bad raw frame ${payload.length - 8} != $w*$h*4"); + return; + } + // Owned copy: the transport may reuse the inbound buffer, Safari's WASM + // runtime can free views across async gaps, and decodeImageFromPixels + // implementations may read from the underlying buffer after this call + // returns. + final pixels = Uint8List.fromList(Uint8List.sublistView(payload, 8)); + final completer = Completer(); + ui.decodeImageFromPixels( + pixels, w, h, ui.PixelFormat.rgba8888, completer.complete); + _swapImage(await completer.future); + } + + Future _clear() async { + _swapImage(null); + } + + void _swapImage(ui.Image? newImage) { + final old = _image; + _image = newImage; + if (mounted) setState(() {}); + if (old != null) { + // Dispose after the frame that stops painting it. + WidgetsBinding.instance.addPostFrameCallback((_) { + old.dispose(); + }); + } + } + + @override + Widget build(BuildContext context) { + return LayoutControl( + control: widget.control, + child: RawImage( + image: _image, // null before the first frame — paints nothing + fit: widget.control.getBoxFit("fit"), + filterQuality: widget.control + .getFilterQuality("filter_quality", FilterQuality.low)!, + scale: widget.control.getDouble("scale", 1.0)!, + ), + ); + } +} diff --git a/packages/flet/lib/src/controls/reorderable_drag_handle.dart b/packages/flet/lib/src/controls/reorderable_drag_handle.dart index 574b2a633a..3755fce43e 100644 --- a/packages/flet/lib/src/controls/reorderable_drag_handle.dart +++ b/packages/flet/lib/src/controls/reorderable_drag_handle.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/mouse.dart'; -import '../utils/numbers.dart'; import '../widgets/error.dart'; import '../widgets/reorderable_item_scope.dart'; @@ -28,7 +27,7 @@ class ReorderableDragHandleControl extends StatelessWidget { "ReorderableDragHandle.content must be set and visible"); } - var mouseCursor = parseMouseCursor(control.getString("mouse_cursor")); + var mouseCursor = control.getMouseCursor("mouse_cursor"); if (mouseCursor != null) { content = MouseRegion( diff --git a/packages/flet/lib/src/controls/reorderable_list_view.dart b/packages/flet/lib/src/controls/reorderable_list_view.dart index 7bcc23afaa..25454e8b49 100644 --- a/packages/flet/lib/src/controls/reorderable_list_view.dart +++ b/packages/flet/lib/src/controls/reorderable_list_view.dart @@ -177,7 +177,7 @@ class _ListViewControlState extends State { scrollController: _controller, child: child); - if (widget.control.getBool("on_scroll", false)!) { + if (widget.control.hasEventHandler("scroll")) { child = ScrollNotificationControl(control: widget.control, child: child); } diff --git a/packages/flet/lib/src/controls/responsive_row.dart b/packages/flet/lib/src/controls/responsive_row.dart index 381da535ce..20949b3b84 100644 --- a/packages/flet/lib/src/controls/responsive_row.dart +++ b/packages/flet/lib/src/controls/responsive_row.dart @@ -79,10 +79,16 @@ class ResponsiveRowControl extends StatelessWidget with FletStoreMixin { childWidth = 0; } + // Key the child with a GlobalKey tied to its Control identity so + // that when this build switches between Row and Wrap (a different + // widget type at the same slot), Flutter re-parents the existing + // Element instead of re-inflating the subtree — otherwise stateful + // descendants (video players, WebViews, scroll positions) would + // lose their State on every breakpoint change. controls.add(ConstrainedBox( constraints: BoxConstraints(minWidth: childWidth, maxWidth: childWidth), - child: ControlWidget(key: key, control: ctrl), + child: ControlWidget(key: GlobalObjectKey(ctrl), control: ctrl), )); } diff --git a/packages/flet/lib/src/controls/row.dart b/packages/flet/lib/src/controls/row.dart index fc0e3756b9..a154ac2045 100644 --- a/packages/flet/lib/src/controls/row.dart +++ b/packages/flet/lib/src/controls/row.dart @@ -56,7 +56,7 @@ class RowControl extends StatelessWidget { wrapIntoScrollableView: true, child: child); - if (control.getBool("on_scroll", false)!) { + if (control.hasEventHandler("scroll")) { child = ScrollNotificationControl(control: control, child: child); } diff --git a/packages/flet/lib/src/controls/scrollable_control.dart b/packages/flet/lib/src/controls/scrollable_control.dart index 188a42122d..0ca05276c1 100644 --- a/packages/flet/lib/src/controls/scrollable_control.dart +++ b/packages/flet/lib/src/controls/scrollable_control.dart @@ -35,6 +35,20 @@ class _ScrollableControlState extends State late bool _ownController = false; final _ConstraintsHolder _outerConstraints = _ConstraintsHolder(); + // Auto-scroll: keep the view pinned to the bottom (end) while the user + // hasn't scrolled away from it. Unlike a one-shot scroll on build, this + // follows content that grows *in place* — e.g. streamed text appended to an + // existing child — which does not rebuild this widget and so is otherwise + // missed. + static const double _autoScrollThreshold = 40.0; + bool _pinnedToEnd = true; + double _lastMaxScrollExtent = 0; + double _lastPixels = 0; + bool _autoScrollScheduled = false; + // When set (via the `auto_scroll_animation` property) auto-scroll animates + // to the end with this duration/curve; otherwise it jumps instantly. + ImplicitAnimationDetails? _autoScrollAnimation; + @override void initState() { super.initState(); @@ -45,6 +59,65 @@ class _ScrollableControlState extends State _controller = ScrollController(); _ownController = true; } + _controller.addListener(_onScroll); + } + + void _onScroll() { + if (!_controller.hasClients) return; + final pos = _controller.position; + // Unpin only when the user scrolls *up* (pixels decrease). Content growing + // beneath a stationary position (e.g. a tall Markdown code block inserted + // at the end) leaves pixels unchanged, so it must NOT unpin — otherwise a + // big extent jump would strand the view above the new content. Re-pin once + // the position returns to within a small threshold of the end. + if (pos.pixels < _lastPixels - 0.5) { + _pinnedToEnd = false; + } else if (pos.pixels >= pos.maxScrollExtent - _autoScrollThreshold) { + _pinnedToEnd = true; + } + _lastPixels = pos.pixels; + } + + void _scheduleScrollToEnd({bool force = false}) { + if (_autoScrollScheduled) return; + _autoScrollScheduled = true; + WidgetsBinding.instance.addPostFrameCallback((_) { + _autoScrollScheduled = false; + if (!mounted || !_controller.hasClients) return; + final max = _controller.position.maxScrollExtent; + _lastMaxScrollExtent = max; + if (force || _pinnedToEnd) { + final anim = _autoScrollAnimation; + if (anim != null && anim.duration > Duration.zero) { + _controller.animateTo(max, + duration: anim.duration, curve: anim.curve); + } else { + _controller.jumpTo(max); + } + _pinnedToEnd = true; + } + }); + } + + // Wraps the scrollable so auto_scroll follows extent growth (streamed text, + // inserted items) even when this widget itself does not rebuild. + Widget _wrapAutoScroll(Widget child) { + return NotificationListener( + onNotification: (notification) { + // Only react to this scrollable's own metrics. Nested scrollables + // (e.g. a Markdown code block's horizontal scroller) bubble their + // notifications through with depth > 0; responding to those would + // track the wrong extent and break end-following. + if (notification.depth != 0) return false; + final max = notification.metrics.maxScrollExtent; + if (max > _lastMaxScrollExtent + 0.5 && _pinnedToEnd) { + _scheduleScrollToEnd(); + } + _lastMaxScrollExtent = max; + return false; + }, + child: child, + ); } Future _invokeMethod(String name, dynamic args) async { @@ -86,6 +159,7 @@ class _ScrollableControlState extends State @override void dispose() { + _controller.removeListener(_onScroll); if (_ownController) { _controller.dispose(); } @@ -99,17 +173,25 @@ class _ScrollableControlState extends State final scrollConfiguration = widget.control.getScrollbarConfiguration("scroll"); - if (widget.control.getBool("auto_scroll", false)!) { - WidgetsBinding.instance.addPostFrameCallback((_) { - _controller.animateTo( - _controller.position.maxScrollExtent, - duration: const Duration(seconds: 1), - curve: Curves.ease, - ); - }); + final autoScroll = widget.control.getBool("auto_scroll", false)!; + if (autoScroll) { + // Default to a 1s ease animation (the historical auto_scroll behavior); + // set `auto_scroll_animation` to override, or to duration 0 for an + // instant jump. + _autoScrollAnimation = widget.control.getAnimation( + "auto_scroll_animation", + ImplicitAnimationDetails( + duration: const Duration(seconds: 1), curve: Curves.ease), + ); + // Re-pin on rebuild (e.g. an item added). Extent growth without a + // rebuild is handled by the ScrollMetricsNotification listener in + // _wrapAutoScroll. + _scheduleScrollToEnd(); } - if (scrollConfiguration == null) return widget.child; + if (scrollConfiguration == null) { + return autoScroll ? _wrapAutoScroll(widget.child) : widget.child; + } Widget child = widget.child; if (widget.wrapIntoScrollableView) { @@ -155,7 +237,7 @@ class _ScrollableControlState extends State ); } - return result; + return autoScroll ? _wrapAutoScroll(result) : result; } } diff --git a/packages/flet/lib/src/controls/search_bar.dart b/packages/flet/lib/src/controls/search_bar.dart index 91f682f064..270c51dc8f 100644 --- a/packages/flet/lib/src/controls/search_bar.dart +++ b/packages/flet/lib/src/controls/search_bar.dart @@ -135,9 +135,9 @@ class _SearchBarControlState extends State { }); } - bool onChange = widget.control.getBool("on_change", false)!; - bool onTap = widget.control.getBool("on_tap", false)!; - bool onSubmit = widget.control.getBool("on_submit", false)!; + bool onChange = widget.control.hasEventHandler("change"); + bool onTap = widget.control.hasEventHandler("tap"); + bool onSubmit = widget.control.hasEventHandler("submit"); TextInputType keyboardType = widget.control.getTextInputType("keyboard_type", TextInputType.text)!; @@ -224,7 +224,7 @@ class _SearchBarControlState extends State { leading: widget.control.buildWidget("bar_leading"), trailing: widget.control.buildWidgets("bar_trailing"), onTap: onTap ? () => widget.control.triggerEvent("tap") : null, - onTapOutside: widget.control.getBool("on_tap_outside_bar", false)! + onTapOutside: widget.control.hasEventHandler("tap_outside_bar") ? (PointerDownEvent? event) => widget.control.triggerEvent("tap_outside_bar") : null, diff --git a/packages/flet/lib/src/controls/semantics.dart b/packages/flet/lib/src/controls/semantics.dart index 941ac0a3a8..645371f3a9 100644 --- a/packages/flet/lib/src/controls/semantics.dart +++ b/packages/flet/lib/src/controls/semantics.dart @@ -50,41 +50,41 @@ class SemanticsControl extends StatelessWidget { headingLevel: control.getInt("heading_level"), excludeSemantics: control.getBool("exclude_semantics", false)!, mixed: control.getBool("mixed"), - onTap: control.getBool("on_click", false)! + onTap: control.hasEventHandler("click") ? () => control.triggerEvent("click") : null, - onIncrease: control.getBool("on_increase", false)! + onIncrease: control.hasEventHandler("increase") ? () => control.triggerEvent("increase") : null, - onDecrease: control.getBool("on_decrease", false)! + onDecrease: control.hasEventHandler("decrease") ? () => control.triggerEvent("decrease") : null, - onDismiss: control.getBool("on_dismiss", false)! + onDismiss: control.hasEventHandler("dismiss") ? () => control.triggerEvent("dismiss") : null, - onScrollLeft: control.getBool("on_scroll_left", false)! + onScrollLeft: control.hasEventHandler("scroll_left") ? () => control.triggerEvent("scroll_left") : null, - onScrollRight: control.getBool("on_scroll_right", false)! + onScrollRight: control.hasEventHandler("scroll_right") ? () => control.triggerEvent("scroll_right") : null, - onScrollUp: control.getBool("on_scroll_up", false)! + onScrollUp: control.hasEventHandler("scroll_up") ? () => control.triggerEvent("scroll_up") : null, - onScrollDown: control.getBool("on_scroll_down", false)! + onScrollDown: control.hasEventHandler("scroll_down") ? () => control.triggerEvent("scroll_down") : null, - onCopy: control.getBool("on_copy", false)! + onCopy: control.hasEventHandler("copy") ? () => control.triggerEvent("copy") : null, - onCut: control.getBool("on_cut", false)! + onCut: control.hasEventHandler("cut") ? () => control.triggerEvent("cut") : null, - onPaste: control.getBool("on_paste", false)! + onPaste: control.hasEventHandler("paste") ? () => control.triggerEvent("paste") : null, - onLongPress: control.getBool("on_dismiss", false)! - ? () => control.triggerEvent("dismiss") + onLongPress: control.hasEventHandler("long_press") + ? () => control.triggerEvent("long_press") : null, onMoveCursorForwardByCharacter: control.getBool( "on_move_cursor_forward_by_character", false)! @@ -97,14 +97,14 @@ class SemanticsControl extends StatelessWidget { control.triggerEvent("move_cursor_backward_by_character", value) : null, onDidGainAccessibilityFocus: - control.getBool("on_did_gain_accessibility_focus", false)! + control.hasEventHandler("did_gain_accessibility_focus") ? () => control.triggerEvent("did_gain_accessibility_focus") : null, onDidLoseAccessibilityFocus: - control.getBool("on_did_lose_accessibility_focus", false)! + control.hasEventHandler("did_lose_accessibility_focus") ? () => control.triggerEvent("did_lose_accessibility_focus") : null, - onSetText: control.getBool("on_set_text", false)! + onSetText: control.hasEventHandler("set_text") ? (String text) => control.triggerEvent("set_text", text) : null, ); diff --git a/packages/flet/lib/src/controls/stack.dart b/packages/flet/lib/src/controls/stack.dart index 8540f8c4a1..f57d87183f 100644 --- a/packages/flet/lib/src/controls/stack.dart +++ b/packages/flet/lib/src/controls/stack.dart @@ -4,7 +4,6 @@ import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/alignment.dart'; import '../utils/misc.dart'; -import '../utils/numbers.dart'; import 'base_controls.dart'; class StackControl extends StatelessWidget { @@ -19,8 +18,7 @@ class StackControl extends StatelessWidget { Widget build(BuildContext context) { debugPrint("Stack build: ${control.id}"); final stack = Stack( - clipBehavior: - parseClip(control.getString("clip_behavior"), Clip.hardEdge)!, + clipBehavior: control.getClipBehavior("clip_behavior", Clip.hardEdge)!, fit: control.getStackFit("fit", StackFit.loose)!, alignment: control.getAlignment("alignment") ?? AlignmentDirectional.topStart, diff --git a/packages/flet/lib/src/controls/submenu_button.dart b/packages/flet/lib/src/controls/submenu_button.dart index 58ff77d05f..8a752d091b 100644 --- a/packages/flet/lib/src/controls/submenu_button.dart +++ b/packages/flet/lib/src/controls/submenu_button.dart @@ -59,9 +59,9 @@ class _SubmenuButtonControlState extends State { ? const StadiumBorder() : RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))); - bool onOpen = widget.control.getBool("on_open", false)!; - bool onClose = widget.control.getBool("on_close", false)!; - bool onHover = widget.control.getBool("on_hover", false)!; + bool onOpen = widget.control.hasEventHandler("open"); + bool onClose = widget.control.hasEventHandler("close"); + bool onHover = widget.control.hasEventHandler("hover"); var subMenuButton = SubmenuButton( focusNode: _focusNode, diff --git a/packages/flet/lib/src/controls/tabs.dart b/packages/flet/lib/src/controls/tabs.dart index 28ecd1523e..66724d2391 100644 --- a/packages/flet/lib/src/controls/tabs.dart +++ b/packages/flet/lib/src/controls/tabs.dart @@ -287,8 +287,7 @@ class _TabBarControlState extends State { widget.control.getDouble("indicator_thickness", 2.0)!; var tabAlignment = widget.control.getTabAlignment("tab_alignment", scrollable ? TabAlignment.start : TabAlignment.fill)!; - var mouseCursor = - parseMouseCursor(widget.control.getString("mouse_cursor")); + var mouseCursor = widget.control.getMouseCursor("mouse_cursor"); var padding = parseEdgeInsets(widget.control.getPadding("padding")); var labelPadding = widget.control.getPadding("label_padding"); var labelStyle = diff --git a/packages/flet/lib/src/controls/text.dart b/packages/flet/lib/src/controls/text.dart index 33eebee6f0..d44aaa9e50 100644 --- a/packages/flet/lib/src/controls/text.dart +++ b/packages/flet/lib/src/controls/text.dart @@ -67,8 +67,7 @@ class TextControl extends StatelessWidget { backgroundColor: control.getColor("bgcolor", context), ); - var textAlign = - parseTextAlign(control.getString("text_align"), TextAlign.start)!; + var textAlign = control.getTextAlign("text_align", TextAlign.start)!; onSelectionChanged(TextSelection selection, SelectionChangedCause? cause) { control.triggerEvent("selection_change", { diff --git a/packages/flet/lib/src/controls/textfield.dart b/packages/flet/lib/src/controls/textfield.dart index 6ff83f4dc3..658edb421f 100644 --- a/packages/flet/lib/src/controls/textfield.dart +++ b/packages/flet/lib/src/controls/textfield.dart @@ -120,7 +120,7 @@ class _TextFieldControlState extends State { _selection = selection; if (!selection.isValid || - !widget.control.getBool("on_selection_change", false)!) { + !widget.control.hasEventHandler("selection_change")) { return; } @@ -180,7 +180,7 @@ class _TextFieldControlState extends State { .getTextCapitalization("capitalization", TextCapitalization.none)!; FilteringTextInputFormatter? inputFilter = - parseInputFilter(widget.control.get("input_filter")); + widget.control.getTextInputFormatter("input_filter"); List? inputFormatters = []; // add non-null input formatters @@ -294,7 +294,7 @@ class _TextFieldControlState extends State { onTap: () { widget.control.triggerEvent("click"); }, - onTapOutside: widget.control.getBool("on_tap_outside", false)! + onTapOutside: widget.control.hasEventHandler("tap_outside") ? (PointerDownEvent? event) { widget.control.triggerEvent("tap_outside"); } @@ -302,7 +302,7 @@ class _TextFieldControlState extends State { onChanged: (String value) { _value = value; widget.control.updateProperties({"value": value}); - if (widget.control.getBool("on_change", false)!) { + if (widget.control.hasEventHandler("change")) { widget.control.triggerEvent("change", value); } }); diff --git a/packages/flet/lib/src/controls/view.dart b/packages/flet/lib/src/controls/view.dart index 4c7bbcee62..9330f10a3b 100644 --- a/packages/flet/lib/src/controls/view.dart +++ b/packages/flet/lib/src/controls/view.dart @@ -17,7 +17,7 @@ import '../utils/colors.dart'; import '../utils/edge_insets.dart'; import '../utils/numbers.dart'; import '../utils/theme.dart'; -import '../widgets/loading_page.dart'; +import '../widgets/boot_screen.dart'; import '../widgets/page_context.dart'; import '../widgets/page_media.dart'; import 'app_bar.dart'; @@ -136,7 +136,7 @@ class _ViewControlState extends State { child: column, ); - if (control.getBool("on_scroll", false)!) { + if (control.hasEventHandler("scroll")) { child = ScrollNotificationControl(control: control, child: child); } @@ -190,12 +190,10 @@ class _ViewControlState extends State { ((pageData?.themeMode == null || pageData?.themeMode == ThemeMode.system) && pageData?.brightness == Brightness.light) - ? parseTheme(control.parent!.get("theme"), context, Brightness.light) + ? control.parent!.getTheme("theme", context, Brightness.light) : control.parent!.getString("dark_theme") != null - ? parseTheme( - control.parent!.get("dark_theme"), context, Brightness.dark) - : parseTheme( - control.parent!.get("theme"), context, Brightness.dark); + ? control.parent!.getTheme("dark_theme", context, Brightness.dark) + : control.parent!.getTheme("theme", context, Brightness.dark); Widget scaffold = Scaffold( key: _materialScaffoldKey, @@ -246,22 +244,18 @@ class _ViewControlState extends State { } var backend = FletBackend.of(context); - var showAppStartupScreen = backend.showAppStartupScreen ?? false; - var appStartupScreenMessage = backend.appStartupScreenMessage ?? ""; var appStatus = context.select( (backend) => (isLoading: backend.isLoading, error: backend.error)); - var formattedErrorMessage = backend.formatAppErrorMessage(appStatus.error); Widget? loadingPage; - if ((appStatus.isLoading || appStatus.error != "") && - showAppStartupScreen) { - loadingPage = LoadingPage( - isLoading: appStatus.isLoading, - message: appStatus.isLoading - ? appStartupScreenMessage - : formattedErrorMessage, + if (appStatus.isLoading || appStatus.error != "") { + loadingPage = resolveBootScreen( + name: backend.bootScreenName, + options: backend.bootScreenOptions, + extensions: backend.extensions, + status: backend.bootStatus, ); } @@ -287,7 +281,7 @@ class _ViewControlState extends State { result = PopScope( canPop: _allowPop || control.getBool("can_pop", true)!, onPopInvokedWithResult: (didPop, result) { - if (didPop || !control.getBool("on_confirm_pop", false)!) { + if (didPop || !control.hasEventHandler("confirm_pop")) { return; } debugPrint("Page.onPopInvokedWithResult()"); diff --git a/packages/flet/lib/src/flet_app.dart b/packages/flet/lib/src/flet_app.dart index ee0873a934..499e2301f4 100644 --- a/packages/flet/lib/src/flet_app.dart +++ b/packages/flet/lib/src/flet_app.dart @@ -5,15 +5,22 @@ import 'controls/control_widget.dart'; import 'flet_app_errors_handler.dart'; import 'flet_backend.dart'; import 'flet_extension.dart'; +import 'models/boot_status.dart'; import 'models/control.dart'; import 'testing/tester.dart'; +import 'transport/data_channel.dart'; +import 'transport/flet_backend_channel.dart'; /// FletApp - The top-level widget that initializes everything class FletApp extends StatefulWidget { final String pageUrl; final String assetsDir; - final bool? showAppStartupScreen; - final String? appStartupScreenMessage; + final String? bootScreenName; + final Map? bootScreenOptions; + /// Optional shared boot status notifier. When provided (e.g. by a persistent + /// boot overlay in the app bootstrap), the backend updates it instead of + /// owning its own, so the same notifier spans both boot phases. + final ValueNotifier? bootStatus; final String? appErrorMessage; final int? controlId; final String? title; @@ -26,12 +33,26 @@ class FletApp extends StatefulWidget { final Tester? tester; final bool multiView; + /// Optional escape hatch for embedders that bring their own transport + /// (e.g. `serious_python`'s in-process FFI bridge). When set, this builder + /// is invoked from [FletBackend.connect] in place of the URL-scheme + /// factory; [pageUrl] is then irrelevant for transport selection. + final FletBackendChannelBuilder? channelBuilder; + + /// Optional factory for high-throughput byte channels (see [DataChannel]). + /// Embedders that ship an in-process Python runtime can inject a + /// `PythonBridge`-backed factory here; when `null`, `FletBackend` falls + /// back to a built-in factory that muxes raw bytes over the regular Flet + /// protocol channel. + final DataChannelFactory? dataChannelFactory; + const FletApp( {super.key, required this.pageUrl, required this.assetsDir, - this.showAppStartupScreen, - this.appStartupScreenMessage, + this.bootScreenName, + this.bootScreenOptions, + this.bootStatus, this.appErrorMessage, this.controlId, this.title, @@ -42,7 +63,9 @@ class FletApp extends StatefulWidget { this.args, this.forcePyodide, this.tester, - this.multiView = false}); + this.multiView = false, + this.channelBuilder, + this.dataChannelFactory}); @override State createState() => _FletAppState(); @@ -62,8 +85,9 @@ class _FletAppState extends State { return ChangeNotifierProvider( create: (context) { return FletBackend( - showAppStartupScreen: widget.showAppStartupScreen, - appStartupScreenMessage: widget.appStartupScreenMessage, + bootScreenName: widget.bootScreenName ?? "flet", + bootScreenOptions: widget.bootScreenOptions ?? const {}, + bootStatus: widget.bootStatus, appErrorMessage: widget.appErrorMessage, controlId: widget.controlId, reconnectIntervalMs: widget.reconnectIntervalMs, @@ -76,6 +100,8 @@ class _FletAppState extends State { forcePyodide: widget.forcePyodide, tester: widget.tester, multiView: widget.multiView, + channelBuilder: widget.channelBuilder, + dataChannelFactory: widget.dataChannelFactory, parentFletBackend: Provider.of(context, listen: false)); }, diff --git a/packages/flet/lib/src/flet_backend.dart b/packages/flet/lib/src/flet_backend.dart index f173ee8584..0785a63782 100644 --- a/packages/flet/lib/src/flet_backend.dart +++ b/packages/flet/lib/src/flet_backend.dart @@ -4,12 +4,14 @@ import 'dart:convert'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:msgpack_dart/msgpack_dart.dart' as msgpack; import 'package:provider/provider.dart'; import 'flet_app_errors_handler.dart'; import 'flet_core_extension.dart'; import 'flet_extension.dart'; import 'models/asset_source.dart'; +import 'models/boot_status.dart'; import 'models/control.dart'; import 'models/window_state.dart'; import 'protocol/control_event_body.dart'; @@ -24,7 +26,11 @@ import 'protocol/register_client_response_body.dart'; import 'protocol/session_crashed_body.dart'; import 'protocol/update_control_body.dart'; import 'testing/tester.dart'; +import 'transport/data_channel.dart'; import 'transport/flet_backend_channel.dart'; +import 'transport/flet_msgpack_decoder.dart'; +import 'transport/flet_msgpack_encoder.dart'; +import 'transport/protocol_muxed_data_channel.dart'; import 'utils/desktop.dart'; import 'utils/images.dart'; import 'utils/numbers.dart'; @@ -45,10 +51,18 @@ class FletBackend extends ChangeNotifier { final WeakReference? _parentFletBackend; final Uri pageUri; final String assetsDir; - final bool? showAppStartupScreen; - final String? appStartupScreenMessage; + final String bootScreenName; + final Map bootScreenOptions; final String? appErrorMessage; final int? controlId; + /// Notifies the boot screen of the current [BootStatus] (stage, any startup + /// error, and whether boot is done). Kept in sync with [isLoading]/[error]. + /// + /// May be injected by the embedder (e.g. a persistent boot overlay in the + /// app bootstrap that needs the same notifier across both boot phases). When + /// injected, this backend updates but does not own/dispose it. + late final ValueNotifier bootStatus; + final bool _ownsBootStatus; final FletAppErrorsHandler? errorsHandler; late final List extensions; final Map? args; @@ -62,6 +76,14 @@ class FletBackend extends ChangeNotifier { int _reconnectStarted = 0; int _reconnectDelayMs = 0; FletBackendChannel? _backendChannel; + final FletBackendChannelBuilder? _channelBuilder; + late final DataChannelFactory _dataChannelFactory; + final DataChannelFactory? _injectedDataChannelFactory; + // Inbound mux registry for ProtocolMuxedDataChannel — type-byte 0x01 + // frames are routed by channel_id to the matching channel's deliver hook. + // PythonBridge-backed DataChannels do NOT live in this registry (their + // bytes arrive on their own native port, never on the Flet transport). + final Map _dataChannels = {}; final List _sendQueue = []; String route = ""; bool isLoading = true; @@ -96,19 +118,29 @@ class FletBackend extends ChangeNotifier { int? reconnectIntervalMs, int? reconnectTimeoutMs, this.errorsHandler, - this.showAppStartupScreen, - this.appStartupScreenMessage, + this.bootScreenName = "flet", + this.bootScreenOptions = const {}, this.appErrorMessage, this.controlId, this.args, this.forcePyodide, this.tester, required extensions, + ValueNotifier? bootStatus, + FletBackendChannelBuilder? channelBuilder, + DataChannelFactory? dataChannelFactory, FletBackend? parentFletBackend}) : _parentFletBackend = parentFletBackend != null ? WeakReference(parentFletBackend) : null, _reconnectTimeoutMs = reconnectTimeoutMs, - _reconnectIntervalMs = reconnectIntervalMs { + _reconnectIntervalMs = reconnectIntervalMs, + _channelBuilder = channelBuilder, + _ownsBootStatus = bootStatus == null, + _injectedDataChannelFactory = dataChannelFactory { + this.bootStatus = bootStatus ?? + ValueNotifier(const BootStatus(BootStage.startingUp)); + _dataChannelFactory = + _injectedDataChannelFactory ?? ProtocolMuxedDataChannelFactory(this); // add Flet extension with core controls and services this.extensions = [...extensions, FletCoreExtension()]; @@ -120,7 +152,7 @@ class FletBackend extends ChangeNotifier { "web": kIsWeb, "debug": kDebugMode, "wasm": const bool.fromEnvironment('dart.tool.dart2wasm'), - "test": tester != null, + "test": tester != null || const bool.fromEnvironment("FLET_TEST"), "multi_view": multiView, "pyodide": isPyodideMode(), "window": { @@ -171,18 +203,30 @@ class FletBackend extends ChangeNotifier { _page.removeListener(_onPageUpdated); _page.dispose(); _backendChannel?.disconnect(); + if (_ownsBootStatus) { + bootStatus.dispose(); + } super.dispose(); } Future connect() async { debugPrint("Connecting to Flet backend $pageUri..."); try { - _backendChannel = FletBackendChannel( - address: pageUri.toString(), - args: args ?? {}, - forcePyodide: forcePyodide == true, - onDisconnect: _onDisconnect, - onMessage: _onMessage); + final builder = _channelBuilder; + if (builder != null) { + // Embedder-supplied transport (e.g. serious_python's in-process FFI + // bridge). The builder is responsible for the entire transport + // lifecycle; we just wire its callbacks to ours. + _backendChannel = builder( + onDisconnect: _onDisconnect, onPacket: _onPacket); + } else { + _backendChannel = FletBackendChannel( + address: pageUri.toString(), + args: args ?? {}, + forcePyodide: forcePyodide == true, + onDisconnect: _onDisconnect, + onPacket: _onPacket); + } await _backendChannel!.connect(); _registerClient(); } catch (e) { @@ -192,6 +236,40 @@ class FletBackend extends ChangeNotifier { } } + /// Opens a dedicated [DataChannel] for high-throughput byte traffic from a + /// widget. In embedded mode this is backed by a fresh `PythonBridge`; in + /// dev / web modes it is a logical channel multiplexed over the active + /// [FletBackendChannel] (see [ProtocolMuxedDataChannelFactory]). + /// + /// Must be called from the main Isolate (it doesn't escape there, but + /// the returned channel is main-Isolate-bound either way). + DataChannel openDataChannel() => _dataChannelFactory.open(); + + // --------------------------------------------------------------------- + // Mux registry — used by ProtocolMuxedDataChannel only. + // --------------------------------------------------------------------- + + /// Registers a muxed data channel so inbound 0x01 frames for [id] are + /// routed to it. Called from [ProtocolMuxedDataChannel.]. + void registerDataChannel(int id, ProtocolMuxedDataChannel channel) { + assert(!_dataChannels.containsKey(id), "duplicate data channel id $id"); + _dataChannels[id] = channel; + } + + /// Removes [id] from the routing table. Called from + /// [ProtocolMuxedDataChannel.close]. Idempotent — frames for an + /// unregistered id are silently dropped. + void unregisterDataChannel(int id) { + _dataChannels.remove(id); + } + + /// Sends a fully-formed packet on the active transport. Used by + /// [ProtocolMuxedDataChannel] to ship `[0x01][channel_id:u32 LE][bytes]` + /// alongside regular protocol traffic. + void sendRawPacket(Uint8List packet) { + _backendChannel?.send(packet); + } + _registerClient() { debugPrint("Registering web client: $page"); _send( @@ -416,9 +494,42 @@ class FletBackend extends ChangeNotifier { return getAssetSrc(src, pageUri, assetsDir); } - _onMessage(Message message) { + /// Inbound transport dispatcher. Every packet starts with a 1-byte type + /// discriminator: + /// 0x00 → MsgPack-encoded Flet control frame (the existing protocol). + /// 0x01 → raw DataChannel frame `[channel_id:u32 LE][payload]`. + void _onPacket(Uint8List packet) { + if (packet.isEmpty) { + debugPrint("Dropping empty packet"); + return; + } + final type = packet[0]; + if (type == 0x00) { + // Decode the MsgPack body and dispatch as a Flet protocol message. + final body = msgpack.deserialize( + Uint8List.sublistView(packet, 1), + extDecoder: FletMsgpackDecoder()); + _onMessage(Message.fromList(body)); + } else if (type == 0x01) { + if (packet.length < 5) { + debugPrint("Dropping malformed data channel frame (len=${packet.length})"); + return; + } + final channelId = + ByteData.sublistView(packet, 1, 5).getUint32(0, Endian.little); + final channel = _dataChannels[channelId]; + if (channel == null) { + // Stale frame after channel.close() — silently drop. + return; + } + channel.deliver(Uint8List.sublistView(packet, 5)); + } else { + debugPrint("Dropping packet with unknown type byte 0x${type.toRadixString(16)}"); + } + } + + void _onMessage(Message message) { debugPrint("Received message: ${message.toList()}"); - //debugPrint("message.payload: ${message.payload}"); switch (message.action) { case MessageAction.registerClient: _onClientRegistered( @@ -507,6 +618,21 @@ class FletBackend extends ChangeNotifier { notifyListeners(); } + @override + void notifyListeners() { + // Keep the boot screen status in sync with the loading/error state. + // While loading (incl. reconnecting) show the loading state; show the + // error only once loading has settled with an error present. + final err = + (!isLoading && error.isNotEmpty) ? formatAppErrorMessage(error) : null; + final newStatus = BootStatus(BootStage.startingUp, + error: err, done: !isLoading && error.isEmpty); + if (bootStatus.value != newStatus) { + bootStatus.value = newStatus; + } + super.notifyListeners(); + } + String formatAppErrorMessage(String rawError) { if (rawError.isEmpty) { return ""; @@ -568,7 +694,12 @@ class FletBackend extends ChangeNotifier { _send(Message message, {bool unbuffered = false}) { if (unbuffered || !isLoading) { debugPrint("_send: ${message.action} ${message.payload}"); - _backendChannel?.send(message); + final encoded = msgpack.serialize(message.toList(), + extEncoder: FletMsgpackEncoder()); + final packet = Uint8List(1 + encoded.length); + packet[0] = 0x00; + packet.setRange(1, packet.length, encoded); + _backendChannel?.send(packet); } else { _sendQueue.add(message); } diff --git a/packages/flet/lib/src/flet_core_extension.dart b/packages/flet/lib/src/flet_core_extension.dart index 295b363f39..9bb0d0232b 100644 --- a/packages/flet/lib/src/flet_core_extension.dart +++ b/packages/flet/lib/src/flet_core_extension.dart @@ -83,6 +83,7 @@ import 'controls/progress_bar.dart'; import 'controls/progress_ring.dart'; import 'controls/radio_group.dart'; import 'controls/range_slider.dart'; +import 'controls/raw_image.dart'; import 'controls/reorderable_drag_handle.dart'; import 'controls/reorderable_list_view.dart'; import 'controls/responsive_row.dart'; @@ -321,6 +322,8 @@ class FletCoreExtension extends FletExtension { return RadioGroupControl(key: key, control: control); case "RangeSlider": return RangeSliderControl(key: key, control: control); + case "RawImage": + return RawImageControl(key: key, control: control); case "ReorderableDragHandle": return ReorderableDragHandleControl(key: key, control: control); case "ReorderableListView": diff --git a/packages/flet/lib/src/flet_extension.dart b/packages/flet/lib/src/flet_extension.dart index 279fb7663f..d41c0f0680 100644 --- a/packages/flet/lib/src/flet_extension.dart +++ b/packages/flet/lib/src/flet_extension.dart @@ -1,6 +1,8 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'flet_service.dart'; +import 'models/boot_status.dart'; import 'models/control.dart'; abstract class FletExtension { @@ -17,4 +19,18 @@ abstract class FletExtension { IconData? createIconData(int iconCode) { return null; } + + /// Creates a custom boot screen identified by [name]. + /// + /// A single extension can provide multiple named boot screens. Return null + /// if this extension does not handle the given [name] (the next extension is + /// then tried, ultimately falling back to the built-in "flet" screen). + /// + /// [options] is the boot screen's settings table from `pyproject.toml`. + /// [status] notifies the widget of the current boot [BootStatus] (stage and + /// any startup error) — watch it with a [ValueListenableBuilder]. + Widget? createBootScreen( + String name, Map options, ValueListenable status) { + return null; + } } diff --git a/packages/flet/lib/src/models/boot_status.dart b/packages/flet/lib/src/models/boot_status.dart new file mode 100644 index 0000000000..e5b4f65ea4 --- /dev/null +++ b/packages/flet/lib/src/models/boot_status.dart @@ -0,0 +1,39 @@ +/// The stage the app is currently at while booting. +enum BootStage { + /// The app bundle is being unpacked and the runtime prepared. No Flet + /// backend exists yet (desktop/mobile production startup). + preparing, + + /// The Python runtime and the Flet app are starting up, until the first + /// page is shown. + startingUp, +} + +/// The current boot status delivered to a boot screen widget. +/// +/// A boot screen observes a [ValueListenable] of [BootStatus] to update its +/// visuals as the app progresses through the boot [stage], and to render an +/// error state when [error] is non-null. +class BootStatus { + final BootStage stage; + + /// Non-null when startup/connection failed. The message is already + /// formatted for display. A heading can be derived from [stage]. + final String? error; + + /// True once the app is ready and the boot screen should be dismissed. + /// Used by a persistent boot overlay to know when to fade out. + final bool done; + + const BootStatus(this.stage, {this.error, this.done = false}); + + @override + bool operator ==(Object other) => + other is BootStatus && + other.stage == stage && + other.error == error && + other.done == done; + + @override + int get hashCode => Object.hash(stage, error, done); +} diff --git a/packages/flet/lib/src/services/base_sensor.dart b/packages/flet/lib/src/services/base_sensor.dart index f7b4831c4e..0b9c7c9a9c 100644 --- a/packages/flet/lib/src/services/base_sensor.dart +++ b/packages/flet/lib/src/services/base_sensor.dart @@ -43,8 +43,8 @@ abstract class BaseSensorService extends FletService { if (interval.isNegative) { interval = defaultInterval; } - var hasReadingSubscribers = control.getBool("on_$eventName") == true; - var hasErrorSubscribers = control.getBool("on_error") == true; + var hasReadingSubscribers = control.hasEventHandler(eventName); + var hasErrorSubscribers = control.hasEventHandler("error"); var cancelOnError = control.getBool("cancel_on_error", true) ?? true; if (forceRestart || diff --git a/packages/flet/lib/src/services/battery.dart b/packages/flet/lib/src/services/battery.dart index 86702986be..4226f73690 100644 --- a/packages/flet/lib/src/services/battery.dart +++ b/packages/flet/lib/src/services/battery.dart @@ -4,7 +4,6 @@ import 'package:battery_plus/battery_plus.dart'; import 'package:flutter/foundation.dart'; import '../flet_service.dart'; -import '../utils/numbers.dart'; class BatteryService extends FletService { final Battery _battery = Battery(); @@ -46,7 +45,7 @@ class BatteryService extends FletService { } void _updateListeners() { - final listenState = control.getBool("on_state_change") == true; + final listenState = control.hasEventHandler("state_change"); if (listenState && _stateSub == null) { _stateSub = _battery.onBatteryStateChanged.listen((state) { control.triggerEvent("state_change", {"state": state.name}); diff --git a/packages/flet/lib/src/services/connectivity.dart b/packages/flet/lib/src/services/connectivity.dart index 1fabe03b96..da0159f861 100644 --- a/packages/flet/lib/src/services/connectivity.dart +++ b/packages/flet/lib/src/services/connectivity.dart @@ -4,7 +4,6 @@ import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/foundation.dart'; import '../flet_service.dart'; -import '../utils/numbers.dart'; class ConnectivityService extends FletService { final Connectivity _connectivity = Connectivity(); @@ -36,7 +35,7 @@ class ConnectivityService extends FletService { } void _updateListeners() { - final listenChange = control.getBool("on_change") == true; + final listenChange = control.hasEventHandler("change"); if (listenChange && _subscription == null) { _subscription = _connectivity.onConnectivityChanged.listen( (List result) { diff --git a/packages/flet/lib/src/services/file_picker.dart b/packages/flet/lib/src/services/file_picker.dart index 609ba20284..1c7c0560e9 100644 --- a/packages/flet/lib/src/services/file_picker.dart +++ b/packages/flet/lib/src/services/file_picker.dart @@ -36,6 +36,9 @@ class FilePickerService extends FletService { ?.map((e) => e.toString()) .toList(); var withData = parseBool(args["with_data"], false)!; + var cancelUploadOnWindowBlur = + parseBool(args["cancel_upload_on_window_blur"], true)!; + var compressionQuality = parseInt(args["compression_quality"], 0)!; var srcBytes = args["src_bytes"]; if (allowedExtensions != null && allowedExtensions.isNotEmpty) { @@ -48,15 +51,17 @@ class FilePickerService extends FletService { uploadFiles(files, control.backend.pageUri); } case "pick_files": - _files = (await FilePicker.platform.pickFiles( + _files = (await FilePicker.pickFiles( dialogTitle: dialogTitle, initialDirectory: initialDirectory, lockParentWindow: true, type: fileType, allowedExtensions: allowedExtensions, + compressionQuality: compressionQuality, allowMultiple: args["allow_multiple"], withData: withData, - withReadStream: !withData)) + withReadStream: !withData, + cancelUploadOnWindowBlur: cancelUploadOnWindowBlur)) ?.files; return _files != null ? _files!.asMap().entries.map((file) { @@ -79,7 +84,7 @@ class FilePickerService extends FletService { throw Exception( "\"file_name\" is required when saving a file on Web."); } - return await FilePicker.platform.saveFile( + return await FilePicker.saveFile( dialogTitle: dialogTitle, fileName: args["file_name"] != null || !isIOSMobile() ? args["file_name"] @@ -93,7 +98,7 @@ class FilePickerService extends FletService { if (kIsWeb) { throw Exception("Get Directory Path dialog is not supported on web."); } - return await FilePicker.platform.getDirectoryPath( + return await FilePicker.getDirectoryPath( dialogTitle: dialogTitle, initialDirectory: initialDirectory, lockParentWindow: true, diff --git a/packages/flet/lib/src/services/screen_brightness.dart b/packages/flet/lib/src/services/screen_brightness.dart index 9b1b3ce290..c38d5667cc 100644 --- a/packages/flet/lib/src/services/screen_brightness.dart +++ b/packages/flet/lib/src/services/screen_brightness.dart @@ -81,13 +81,13 @@ class ScreenBrightnessService extends FletService { } final listenSystem = - control.getBool("on_system_screen_brightness_change") == true; + control.hasEventHandler("system_screen_brightness_change"); final listenApplication = - control.getBool("on_application_screen_brightness_change") == true; + control.hasEventHandler("application_screen_brightness_change"); if (listenSystem && _systemSubscription == null) { - _systemSubscription = _screenBrightness.onSystemScreenBrightnessChanged - .listen((value) { + _systemSubscription = + _screenBrightness.onSystemScreenBrightnessChanged.listen((value) { control.triggerEvent( "system_screen_brightness_change", {"brightness": value}); }, onError: (error) { diff --git a/packages/flet/lib/src/services/tester.dart b/packages/flet/lib/src/services/tester.dart index 18dc410319..cd747a1e55 100644 --- a/packages/flet/lib/src/services/tester.dart +++ b/packages/flet/lib/src/services/tester.dart @@ -50,9 +50,20 @@ class TesterService extends FletService { case "find_by_key": var controlKey = parseKey(args["key"])!; - var key = controlKey is ControlScrollKey + // Preserve the concrete value type so the constructed ValueKey + // matches the one ControlWidget assigned to the rendered widget. + // ValueKey's `==` is runtimeType-strict — `ValueKey('foo')` + // never equals `ValueKey('foo')`, which would make + // `find.byKey(...)` miss every Flet control. + Key? key = controlKey is ControlScrollKey ? control.backend.globalKeys[controlKey.toString()] - : ValueKey(controlKey.value); + : switch (controlKey.value) { + String v => ValueKey(v), + int v => ValueKey(v), + double v => ValueKey(v), + bool v => ValueKey(v), + _ => ValueKey(controlKey.value), + }; if (key == null) { throw Exception("Key not found: $key"); } diff --git a/packages/flet/lib/src/transport/data_channel.dart b/packages/flet/lib/src/transport/data_channel.dart new file mode 100644 index 0000000000..f0d39875a0 --- /dev/null +++ b/packages/flet/lib/src/transport/data_channel.dart @@ -0,0 +1,55 @@ +import 'dart:typed_data'; + +/// One bidirectional byte channel between Dart and Python, dedicated to a +/// single widget's bulk-data traffic. +/// +/// The Dart side of an extension widget opens one via +/// [FletBackend.openDataChannel] in `initState`, then announces it to Python +/// by firing a `data_channel_open` control event carrying +/// `{channel_name, channel_id: id}` — Python's handler retrieves the +/// matching `DataChannel` via `Control.get_data_channel(channel_id)`. +/// +/// Bytes flow over a transport chosen by the active [DataChannelFactory]: +/// a dedicated `PythonBridge` per channel in embedded native mode, or a +/// raw-byte frame muxed over the regular Flet protocol transport in dev / +/// web modes (see `ProtocolMuxedDataChannelFactory`). +/// +/// **Isolate scope.** [FletBackend.openDataChannel] runs on the main Isolate +/// (it goes through `FletBackend.of(BuildContext)`). The returned channel — +/// and, in embedded mode, the backing `PythonBridge` — therefore lives on +/// the main Isolate. For per-Isolate bridges in worker Isolates, construct +/// `PythonBridge` directly from `package:serious_python` and send the port +/// back to the main Isolate via `SendPort` for the `data_channel_open` +/// fire. +abstract class DataChannel { + /// Stable identifier carried in the `data_channel_open` event payload so + /// Python can attach to the same channel. Implementation-specific: for + /// the `PythonBridge`-backed factory this is the Dart native port number, + /// for the muxed fallback it is a monotonic u32 minted by the factory. + int get id; + + /// Bytes pushed from Python via this channel. Hot path — consumers should + /// avoid synchronous heavy work in the listener and instead enqueue to a + /// worker. + Stream get messages; + + /// Send bytes Dart → Python. Returns `false` only during the brief startup + /// window before the Python side has attached (embedded mode); widget + /// code should treat this as transient and retry / queue accordingly. + bool send(Uint8List bytes); + + /// Releases the channel. Must be called from the widget's `dispose()`. + /// Idempotent. + void close(); +} + +/// Factory injected by the embedder. The `flet build` template injects a +/// `PythonBridge`-backed factory for native mode; web / dev / Pyodide +/// deployments leave this `null` and `FletBackend` falls back to the +/// built-in `ProtocolMuxedDataChannelFactory` that rides the existing +/// Flet protocol transport. +abstract class DataChannelFactory { + /// Opens a fresh data channel. Each call mints a new id; a control may + /// open as many channels as it needs. + DataChannel open(); +} diff --git a/packages/flet/lib/src/transport/flet_backend_channel.dart b/packages/flet/lib/src/transport/flet_backend_channel.dart index b4f30c07d5..7b99e1ce02 100644 --- a/packages/flet/lib/src/transport/flet_backend_channel.dart +++ b/packages/flet/lib/src/transport/flet_backend_channel.dart @@ -1,4 +1,5 @@ -import '../protocol/message.dart'; +import 'dart:typed_data'; + import '../utils/platform_utils_web.dart' if (dart.library.io) "../utils/platform_utils_non_web.dart"; import 'flet_backend_channel_javascript_web.dart' @@ -8,7 +9,30 @@ import 'flet_backend_channel_socket.dart'; import 'flet_backend_channel_web_socket.dart'; typedef FletBackendChannelOnDisconnectCallback = void Function(); -typedef FletBackendChannelOnMessageCallback = void Function(Message message); + +/// Called when the transport receives one complete packet from the peer. +/// The packet is the **full** byte sequence including the 1-byte type +/// discriminator at offset 0: +/// +/// `[type:u8][payload]` +/// +/// where `type == 0x00` is a MsgPack-encoded Flet protocol frame and +/// `type == 0x01` is a raw DataChannel frame (`[channel_id:u32 LE][bytes]`). +/// Transports are responsible only for delivering packet boundaries; the +/// type byte is interpreted by [FletBackend]. +typedef FletBackendChannelOnPacketCallback = void Function(Uint8List packet); + +/// Builds a custom [FletBackendChannel] supplied by the embedder. +/// +/// When provided to [FletApp]/[FletBackend], the channel is used directly and +/// the URL-scheme factory below is skipped — letting embedded runtimes (e.g. +/// `serious_python`'s in-process Dart↔Python FFI bridge) plug in a transport +/// that needs more setup than a `String address` URL can express, without +/// forcing the `flet` package to take a Python-related dependency. +typedef FletBackendChannelBuilder = FletBackendChannel Function({ + required FletBackendChannelOnPacketCallback onPacket, + required FletBackendChannelOnDisconnectCallback onDisconnect, +}); abstract class FletBackendChannel { factory FletBackendChannel( @@ -16,33 +40,38 @@ abstract class FletBackendChannel { required Map args, required bool forcePyodide, required FletBackendChannelOnDisconnectCallback onDisconnect, - required FletBackendChannelOnMessageCallback onMessage}) { + required FletBackendChannelOnPacketCallback onPacket}) { if (isPyodideMode() || forcePyodide) { // Pyodide/JavaScript return FletJavaScriptBackendChannel( address: address, args: args, onDisconnect: onDisconnect, - onMessage: onMessage); + onPacket: onPacket); } else if (address.startsWith("http://") || address.startsWith("https://")) { // WebSocket return FletWebSocketBackendChannel( - address: address, onDisconnect: onDisconnect, onMessage: onMessage); + address: address, onDisconnect: onDisconnect, onPacket: onPacket); } else if (address == "mock") { // Mock return FletMockBackendChannel( - address: address, onDisconnect: onDisconnect, onMessage: onMessage); + address: address, onDisconnect: onDisconnect, onPacket: onPacket); } else { // TCP or UDS return FletSocketBackendChannel( - address: address, onDisconnect: onDisconnect, onMessage: onMessage); + address: address, onDisconnect: onDisconnect, onPacket: onPacket); } } Future connect(); bool get isLocalConnection; int get defaultReconnectIntervalMs; - void send(Message message); + + /// Sends one full packet — `[type:u8][payload]` — to the peer. The transport + /// is responsible for delimiting packet boundaries (length prefix on + /// stream-oriented transports; native message boundary on others). + void send(Uint8List packet); + void disconnect(); } diff --git a/packages/flet/lib/src/transport/flet_backend_channel_javascript_io.dart b/packages/flet/lib/src/transport/flet_backend_channel_javascript_io.dart index 65149e543f..1ed8c86b64 100644 --- a/packages/flet/lib/src/transport/flet_backend_channel_javascript_io.dart +++ b/packages/flet/lib/src/transport/flet_backend_channel_javascript_io.dart @@ -1,17 +1,18 @@ -import '../protocol/message.dart'; +import 'dart:typed_data'; + import 'flet_backend_channel.dart'; class FletJavaScriptBackendChannel implements FletBackendChannel { final String address; final Map args; - final FletBackendChannelOnMessageCallback onMessage; + final FletBackendChannelOnPacketCallback onPacket; final FletBackendChannelOnDisconnectCallback onDisconnect; FletJavaScriptBackendChannel( {required this.address, required this.args, required this.onDisconnect, - required this.onMessage}); + required this.onPacket}); @override connect() async {} @@ -23,7 +24,7 @@ class FletJavaScriptBackendChannel implements FletBackendChannel { int get defaultReconnectIntervalMs => 10; @override - void send(Message data) {} + void send(Uint8List packet) {} @override void disconnect() {} diff --git a/packages/flet/lib/src/transport/flet_backend_channel_javascript_web.dart b/packages/flet/lib/src/transport/flet_backend_channel_javascript_web.dart index 46a6933223..7b76dc8765 100644 --- a/packages/flet/lib/src/transport/flet_backend_channel_javascript_web.dart +++ b/packages/flet/lib/src/transport/flet_backend_channel_javascript_web.dart @@ -1,37 +1,35 @@ import 'dart:js_interop'; import 'package:flutter/foundation.dart'; -import 'package:msgpack_dart/msgpack_dart.dart' as msgpack; -import '../protocol/message.dart'; import 'flet_backend_channel.dart'; -import 'flet_msgpack_decoder.dart'; -import 'flet_msgpack_encoder.dart'; @JS() external JSPromise jsConnect( String appId, JSAny args, JSExportedDartFunction onMessage); +/// The optional `transferList` argument names ArrayBuffers (in `data`'s +/// underlying buffer) whose ownership should transfer to the receiver — +/// `postMessage` then avoids the structured-clone copy. We pass the +/// packet's `.buffer` here so bulk DataChannel frames are zero-copy across +/// the Worker boundary. @JS() -external void jsSend(String appId, JSUint8Array data); +external void jsSend(String appId, JSUint8Array data, JSArray? transferList); @JS() external void jsDisconnect(String appId); -typedef FletBackendJavascriptChannelOnMessageCallback = void Function( - List message); - class FletJavaScriptBackendChannel implements FletBackendChannel { final String address; final Map args; - final FletBackendChannelOnMessageCallback onMessage; + final FletBackendChannelOnPacketCallback onPacket; final FletBackendChannelOnDisconnectCallback onDisconnect; FletJavaScriptBackendChannel( {required this.address, required this.args, required this.onDisconnect, - required this.onMessage}); + required this.onPacket}); @override connect() async { @@ -40,8 +38,9 @@ class FletJavaScriptBackendChannel implements FletBackendChannel { } void _onMessage(JSUint8Array data) { - onMessage(Message.fromList( - msgpack.deserialize(data.toDart, extDecoder: FletMsgpackDecoder()))); + // Each postMessage event is one packet — message boundaries are + // preserved by the underlying MessageChannel. + onPacket(data.toDart); } @override @@ -51,12 +50,15 @@ class FletJavaScriptBackendChannel implements FletBackendChannel { int get defaultReconnectIntervalMs => 10000; @override - void send(Message message) { - jsSend( - address, - msgpack - .serialize(message.toList(), extEncoder: FletMsgpackEncoder()) - .toJS); + void send(Uint8List packet) { + final jsBytes = packet.toJS; + // Transfer the underlying ArrayBuffer to the receiver — zero copy + // across the Worker boundary. Safe because the sender does not access + // `packet` after this call (FletBackend always builds a fresh buffer + // per send). + final jsBuffer = packet.buffer.toJS; + final transferList = [jsBuffer as JSObject].toJS; + jsSend(address, jsBytes, transferList); } @override diff --git a/packages/flet/lib/src/transport/flet_backend_channel_mock.dart b/packages/flet/lib/src/transport/flet_backend_channel_mock.dart index f583f23819..a0b53bde40 100644 --- a/packages/flet/lib/src/transport/flet_backend_channel_mock.dart +++ b/packages/flet/lib/src/transport/flet_backend_channel_mock.dart @@ -1,18 +1,32 @@ import 'dart:math'; import 'package:flutter/foundation.dart'; +import 'package:msgpack_dart/msgpack_dart.dart' as msgpack; import '../protocol/message.dart'; import 'flet_backend_channel.dart'; +import 'flet_msgpack_encoder.dart'; class FletMockBackendChannel implements FletBackendChannel { - FletBackendChannelOnMessageCallback onMessage; + FletBackendChannelOnPacketCallback onPacket; FletBackendChannelOnDisconnectCallback onDisconnect; FletMockBackendChannel( {required String address, required this.onDisconnect, - required this.onMessage}); + required this.onPacket}); + + /// Wrap test-scenario `Message` payloads in the on-wire packet shape + /// `[0x00][msgpack(message.toList())]` so the inbound dispatcher sees + /// them through the same code path as real transports. + void onMessage(Message message) { + final encoded = msgpack.serialize(message.toList(), + extEncoder: FletMsgpackEncoder()); + final packet = Uint8List(1 + encoded.length); + packet[0] = 0x00; + packet.setRange(1, packet.length, encoded); + onPacket(packet); + } @override bool get isLocalConnection => true; @@ -296,8 +310,9 @@ class FletMockBackendChannel implements FletBackendChannel { } @override - void send(Message message) { - debugPrint("Send message: ${message.toList()}"); + void send(Uint8List packet) { + debugPrint("Send packet: type=${packet.isNotEmpty ? packet[0] : -1} " + "len=${packet.length}"); } @override diff --git a/packages/flet/lib/src/transport/flet_backend_channel_socket.dart b/packages/flet/lib/src/transport/flet_backend_channel_socket.dart index a1fcb79a01..4ee3913326 100644 --- a/packages/flet/lib/src/transport/flet_backend_channel_socket.dart +++ b/packages/flet/lib/src/transport/flet_backend_channel_socket.dart @@ -1,36 +1,41 @@ import 'dart:io'; +import 'dart:typed_data'; import 'package:flutter/foundation.dart'; -import 'package:msgpack_dart/msgpack_dart.dart' as msgpack; -import '../protocol/message.dart'; import '../utils/networking.dart'; import 'flet_backend_channel.dart'; -import 'flet_msgpack_decoder.dart'; -import 'flet_msgpack_encoder.dart'; -import 'streaming_msgpack_deserializer.dart'; const int defaultLocalReconnectInterval = 200; const int defaultPublicReconnectInterval = 500; +/// TCP / Unix-domain-socket transport. +/// +/// Wire format: every packet on the wire is prefixed with its length as +/// a 4-byte little-endian unsigned integer. The packet itself starts with +/// the 1-byte type discriminator interpreted by [FletBackend]; we just +/// deliver the payload bytes 1:1. class FletSocketBackendChannel implements FletBackendChannel { String address; - FletBackendChannelOnMessageCallback onMessage; + FletBackendChannelOnPacketCallback onPacket; FletBackendChannelOnDisconnectCallback onDisconnect; Socket? _socket; late final bool _isLocalConnection; late final int _defaultReconnectIntervalMs; - // Create an instance of the StreamingDeserializer. - // This object buffers incoming chunks and decodes complete MessagePack objects. - final StreamingMsgpackDeserializer _streamingDeserializer; + // Inbound framing state: accumulate bytes, parse length-prefixed packets. + // The builder is only flattened when a complete packet (or the 4-byte + // length header) is available — never per incoming chunk, which would be + // quadratic in packet size (multi-MB raw image frames arrive in dozens + // of socket chunks). + final BytesBuilder _inboundBuffer = BytesBuilder(copy: false); + int? _pendingLen; FletSocketBackendChannel({ required this.address, required this.onDisconnect, - required this.onMessage, - }) : _streamingDeserializer = - StreamingMsgpackDeserializer(extDecoder: FletMsgpackDecoder()); + required this.onPacket, + }); @override connect() async { @@ -53,19 +58,8 @@ class FletSocketBackendChannel implements FletBackendChannel { debugPrint('Connected to: $udsPath'); } - // Listen for incoming data. _socket!.listen( - (Uint8List data) { - debugPrint("Received packet: ${data.length}"); - // Feed the incoming chunk into the streaming deserializer. - _streamingDeserializer.addChunk(data); - // Try to decode complete MessagePack messages from buffered data. - var messages = _streamingDeserializer.decodeMessages(); - for (var message in messages) { - //debugPrint('Decoded message: ${message.toString()}'); - _onMessage(message); - } - }, + _onBytes, onError: (error) { debugPrint("Error: $error"); _socket?.destroy(); @@ -79,22 +73,45 @@ class FletSocketBackendChannel implements FletBackendChannel { ); } + void _onBytes(Uint8List chunk) { + _inboundBuffer.add(chunk); + // Parse as many complete packets as the buffer currently holds. + while (true) { + if (_pendingLen == null) { + if (_inboundBuffer.length < 4) return; + // Flatten to read the header. Cheap: at this point the buffer + // holds at most one packet's worth of unconsumed leading bytes, + // and with a single stored chunk takeBytes returns it as-is. + final bytes = _inboundBuffer.takeBytes(); + _pendingLen = + ByteData.sublistView(bytes, 0, 4).getUint32(0, Endian.little); + if (bytes.length > 4) { + _inboundBuffer.add(Uint8List.sublistView(bytes, 4)); + } + } + final len = _pendingLen!; + if (_inboundBuffer.length < len) return; + // Single flatten once the whole packet has arrived. + final bytes = _inboundBuffer.takeBytes(); + _pendingLen = null; + onPacket(Uint8List.sublistView(bytes, 0, len)); + if (bytes.length > len) { + _inboundBuffer.add(Uint8List.sublistView(bytes, len)); + } + } + } + @override bool get isLocalConnection => _isLocalConnection; @override int get defaultReconnectIntervalMs => _defaultReconnectIntervalMs; - // Note: At this point, the incoming message is already a decoded MessagePack object. - _onMessage(dynamic message) { - onMessage(Message.fromList(message)); - } - @override - void send(Message message) { - // Serialize the message using MessagePack and send it. - _socket!.add( - msgpack.serialize(message.toList(), extEncoder: FletMsgpackEncoder())); + void send(Uint8List packet) { + final header = ByteData(4)..setUint32(0, packet.length, Endian.little); + _socket!.add(header.buffer.asUint8List()); + _socket!.add(packet); } @override diff --git a/packages/flet/lib/src/transport/flet_backend_channel_web_socket.dart b/packages/flet/lib/src/transport/flet_backend_channel_web_socket.dart index 34cb16580c..4529e6532b 100644 --- a/packages/flet/lib/src/transport/flet_backend_channel_web_socket.dart +++ b/packages/flet/lib/src/transport/flet_backend_channel_web_socket.dart @@ -1,27 +1,23 @@ import 'package:flutter/foundation.dart'; -import 'package:msgpack_dart/msgpack_dart.dart' as msgpack; import 'package:web_socket_channel/web_socket_channel.dart'; -import '../protocol/message.dart'; import '../utils/networking.dart'; import '../utils/platform_utils_web.dart' if (dart.library.io) "../utils/platform_utils_non_web.dart"; import '../utils/uri.dart'; import 'flet_backend_channel.dart'; -import 'flet_msgpack_decoder.dart'; -import 'flet_msgpack_encoder.dart'; class FletWebSocketBackendChannel implements FletBackendChannel { late final String _wsUrl; late final bool _isLocalConnection; - FletBackendChannelOnMessageCallback onMessage; + FletBackendChannelOnPacketCallback onPacket; FletBackendChannelOnDisconnectCallback onDisconnect; WebSocketChannel? _channel; FletWebSocketBackendChannel( {required String address, required this.onDisconnect, - required this.onMessage}) { + required this.onPacket}) { _wsUrl = getWebSocketEndpoint(Uri.parse(address)); } @@ -35,7 +31,6 @@ class FletWebSocketBackendChannel implements FletBackendChannel { Future connect() async { debugPrint("Connecting to WebSocket $_wsUrl..."); try { - // todo var uri = Uri.parse(_wsUrl); if (kIsWeb) { _isLocalConnection = isLocalhost(uri); @@ -56,15 +51,21 @@ class FletWebSocketBackendChannel implements FletBackendChannel { }); } - _onMessage(message) { - onMessage(Message.fromList( - msgpack.deserialize(message, extDecoder: FletMsgpackDecoder()))); + void _onMessage(dynamic message) { + // Each WebSocket binary message is one complete packet — message + // boundaries are preserved by the transport, no framing needed here. + if (message is Uint8List) { + onPacket(message); + } else if (message is List) { + onPacket(Uint8List.fromList(message)); + } else { + debugPrint("Unexpected WebSocket message type: ${message.runtimeType}"); + } } @override - void send(Message message) { - _channel?.sink.add( - msgpack.serialize(message.toList(), extEncoder: FletMsgpackEncoder())); + void send(Uint8List packet) { + _channel?.sink.add(packet); } @override diff --git a/packages/flet/lib/src/transport/protocol_muxed_data_channel.dart b/packages/flet/lib/src/transport/protocol_muxed_data_channel.dart new file mode 100644 index 0000000000..6dc9569d04 --- /dev/null +++ b/packages/flet/lib/src/transport/protocol_muxed_data_channel.dart @@ -0,0 +1,77 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import '../flet_backend.dart'; +import 'data_channel.dart'; + +/// Default [DataChannelFactory] used when the embedder does not inject a +/// faster transport (i.e. dev mode `flet run` over UDS/TCP, web with +/// Python server, web with Pyodide). Allocates a monotonic 32-bit id per +/// channel and ships frames as `[0x01][channel_id:u32 LE][payload]` over +/// the active [FletBackendChannel] alongside regular Flet protocol traffic. +/// +/// Ids start at 1; 0 is reserved as the "unallocated" sentinel for the +/// `channel_id` field on a control before Dart has minted one. Counter is +/// session-scoped (one [FletBackend] = one session); at one allocation +/// per microsecond the space lasts ~1 hour, well past any realistic +/// channel-churn pattern. +class ProtocolMuxedDataChannelFactory implements DataChannelFactory { + ProtocolMuxedDataChannelFactory(this._backend); + final FletBackend _backend; + int _nextId = 1; + + @override + DataChannel open() { + final id = _nextId++; + return ProtocolMuxedDataChannel(_backend, id); + } +} + +/// Concrete [DataChannel] that rides the Flet protocol transport. Frames +/// are wrapped as `[0x01][channel_id:u32 LE][payload]`; inbound frames are +/// dispatched to [deliver] via [FletBackend]'s mux registry. +class ProtocolMuxedDataChannel implements DataChannel { + ProtocolMuxedDataChannel(this._backend, this._id) { + _backend.registerDataChannel(_id, this); + } + + final FletBackend _backend; + final int _id; + final StreamController _controller = + StreamController.broadcast(); + bool _closed = false; + + @override + int get id => _id; + + @override + Stream get messages => _controller.stream; + + @override + bool send(Uint8List bytes) { + if (_closed) return false; + // Header: [0x01][channel_id:u32 LE]. Single allocation for the whole + // packet (no BytesBuilder copies) — keeps the hot path tight. + final packet = Uint8List(5 + bytes.length); + packet[0] = 0x01; + final view = ByteData.sublistView(packet, 1, 5); + view.setUint32(0, _id, Endian.little); + packet.setRange(5, packet.length, bytes); + _backend.sendRawPacket(packet); + return true; + } + + /// Called by [FletBackend._onPacket] when a 0x01 frame arrives for this id. + void deliver(Uint8List bytes) { + if (_closed) return; + _controller.add(bytes); + } + + @override + void close() { + if (_closed) return; + _closed = true; + _backend.unregisterDataChannel(_id); + _controller.close(); + } +} diff --git a/packages/flet/lib/src/transport/streaming_msgpack_deserializer.dart b/packages/flet/lib/src/transport/streaming_msgpack_deserializer.dart deleted file mode 100644 index 41c8dff14b..0000000000 --- a/packages/flet/lib/src/transport/streaming_msgpack_deserializer.dart +++ /dev/null @@ -1,291 +0,0 @@ -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:msgpack_dart/msgpack_dart.dart'; - -/// Thrown when a complete MessagePack object cannot be decoded -/// because the data is incomplete. -class IncompleteDataError extends FormatError { - IncompleteDataError(super.message); -} - -class _Deserializer { - final ExtDecoder? _extDecoder; - final codec = const Utf8Codec(); - final Uint8List _list; - final ByteData _data; - int _offset = 0; - - /// If false, decoded binary data buffers will reference underlying input - /// buffer and thus may change when the content of input buffer changes. - /// If true, decoded buffers are copies and the underlying input buffer is - /// free to change after decoding. - final bool copyBinaryData; - - /// The current offset after decoding - int get offset => _offset; - - _Deserializer( - Uint8List list, { - ExtDecoder? extDecoder, - this.copyBinaryData = false, - int initialOffset = 0, - }) : _list = list, - _data = - ByteData.view(list.buffer, list.offsetInBytes, list.lengthInBytes), - _extDecoder = extDecoder { - _offset = initialOffset; - } - - // Checks that at least [required] bytes are available, - // or throws an IncompleteDataError. - void _ensureAvailable(int required) { - if (_offset + required > _list.length) { - throw IncompleteDataError( - "Not enough data: require $required more bytes, available ${_list.length - _offset}"); - } - } - - dynamic decode() { - _ensureAvailable(1); - final u = _list[_offset++]; - if (u <= 127) { - return u; - } else if ((u & 0xE0) == 0xE0) { - // negative small integer - return u - 256; - } else if ((u & 0xE0) == 0xA0) { - return _readString(u & 0x1F); - } else if ((u & 0xF0) == 0x90) { - return _readArray(u & 0xF); - } else if ((u & 0xF0) == 0x80) { - return _readMap(u & 0xF); - } - switch (u) { - case 0xc0: - return null; - case 0xc2: - return false; - case 0xc3: - return true; - case 0xcc: - return _readUInt8(); - case 0xcd: - return _readUInt16(); - case 0xce: - return _readUInt32(); - case 0xcf: - return _readUInt64(); - case 0xd0: - return _readInt8(); - case 0xd1: - return _readInt16(); - case 0xd2: - return _readInt32(); - case 0xd3: - return _readInt64(); - case 0xca: - return _readFloat(); - case 0xcb: - return _readDouble(); - case 0xd9: - return _readString(_readUInt8()); - case 0xda: - return _readString(_readUInt16()); - case 0xdb: - return _readString(_readUInt32()); - case 0xc4: - return _readBuffer(_readUInt8()); - case 0xc5: - return _readBuffer(_readUInt16()); - case 0xc6: - return _readBuffer(_readUInt32()); - case 0xdc: - return _readArray(_readUInt16()); - case 0xdd: - return _readArray(_readUInt32()); - case 0xde: - return _readMap(_readUInt16()); - case 0xdf: - return _readMap(_readUInt32()); - case 0xd4: - return _readExt(1); - case 0xd5: - return _readExt(2); - case 0xd6: - return _readExt(4); - case 0xd7: - return _readExt(8); - case 0xd8: - return _readExt(16); - case 0xc7: - return _readExt(_readUInt8()); - case 0xc8: - return _readExt(_readUInt16()); - case 0xc9: - return _readExt(_readUInt32()); - default: - throw FormatError("Invalid MessagePack format"); - } - } - - int _readInt8() { - _ensureAvailable(1); - return _data.getInt8(_offset++); - } - - int _readUInt8() { - _ensureAvailable(1); - return _data.getUint8(_offset++); - } - - int _readUInt16() { - _ensureAvailable(2); - final res = _data.getUint16(_offset); - _offset += 2; - return res; - } - - int _readInt16() { - _ensureAvailable(2); - final res = _data.getInt16(_offset); - _offset += 2; - return res; - } - - int _readUInt32() { - _ensureAvailable(4); - final res = _data.getUint32(_offset); - _offset += 4; - return res; - } - - int _readInt32() { - _ensureAvailable(4); - final res = _data.getInt32(_offset); - _offset += 4; - return res; - } - - int _readUInt64() { - _ensureAvailable(8); - final res = _data.getUint64(_offset); - _offset += 8; - return res; - } - - int _readInt64() { - _ensureAvailable(8); - final res = _data.getInt64(_offset); - _offset += 8; - return res; - } - - double _readFloat() { - _ensureAvailable(4); - final res = _data.getFloat32(_offset); - _offset += 4; - return res; - } - - double _readDouble() { - _ensureAvailable(8); - final res = _data.getFloat64(_offset); - _offset += 8; - return res; - } - - Uint8List _readBuffer(int length) { - _ensureAvailable(length); - final res = - Uint8List.view(_list.buffer, _list.offsetInBytes + _offset, length); - _offset += length; - return copyBinaryData ? Uint8List.fromList(res) : res; - } - - String _readString(int length) { - final list = _readBuffer(length); - final len = list.length; - for (int i = 0; i < len; ++i) { - if (list[i] > 127) { - return codec.decode(list); - } - } - return String.fromCharCodes(list); - } - - List _readArray(int length) { - final res = List.filled(length, null, growable: false); - for (int i = 0; i < length; ++i) { - res[i] = decode(); - } - return res; - } - - Map _readMap(int length) { - final res = {}; - while (length > 0) { - res[decode()] = decode(); - --length; - } - return res; - } - - dynamic _readExt(int length) { - final extType = _readUInt8(); - final data = _readBuffer(length); - return _extDecoder?.decodeObject(extType, data); - } -} - -/// A helper to decode MessagePack data as it arrives in chunks. -/// Call [addChunk] for every incoming piece of data, -/// then [decodeMessages] to retrieve complete messages. -class StreamingMsgpackDeserializer { - final ExtDecoder? _extDecoder; - final bool copyBinaryData; - final BytesBuilder _buffer = BytesBuilder(); - - StreamingMsgpackDeserializer( - {ExtDecoder? extDecoder, this.copyBinaryData = false}) - : _extDecoder = extDecoder; - - /// Adds a new chunk of MessagePack data. - void addChunk(Uint8List chunk) { - _buffer.add(chunk); - } - - /// Attempts to decode as many complete messages as possible - /// from the buffered data. Incomplete trailing data remains in the buffer. - List decodeMessages() { - List messages = []; - Uint8List data = _buffer.takeBytes(); - int offset = 0; - while (offset < data.length) { - try { - // Create a Deserializer using the current offset - _Deserializer d = _Deserializer( - data, - extDecoder: _extDecoder, - copyBinaryData: copyBinaryData, - initialOffset: offset, - ); - dynamic message = d.decode(); - messages.add(message); - offset = d.offset; - } on IncompleteDataError { - // Not enough data to decode a full message; break out of the loop. - break; - } on FormatError { - // For actual format errors (not just incomplete data), - // rethrow or handle as needed. - rethrow; - } - } - // If there is any leftover (incomplete) data, put it back into the buffer. - if (offset < data.length) { - _buffer.add(data.sublist(offset)); - } - return messages; - } -} diff --git a/packages/flet/lib/src/utils.dart b/packages/flet/lib/src/utils.dart index 5926764776..880e85a1b7 100644 --- a/packages/flet/lib/src/utils.dart +++ b/packages/flet/lib/src/utils.dart @@ -6,7 +6,10 @@ import 'package:window_manager/window_manager.dart'; import 'utils/platform.dart'; -Future setupDesktop({bool hideWindowOnStart = false}) async { +Future setupDesktop({ + bool hideWindowOnStart = false, + bool waitUntilReadyToShow = true, +}) async { if (isDesktopPlatform()) { WidgetsFlutterBinding.ensureInitialized(); await windowManager.ensureInitialized(); @@ -16,6 +19,10 @@ Future setupDesktop({bool hideWindowOnStart = false}) async { debugPrint("hideWindowOnStart: $hideWindowOnStart"); debugPrint("hideWindowOnStartEnv: $hideWindowOnStartEnv"); + if (!waitUntilReadyToShow) { + return; + } + await windowManager.waitUntilReadyToShow(null, () async { if (hideWindowOnStartEnv == null && !hideWindowOnStart) { await windowManager.show(); diff --git a/packages/flet/lib/src/utils/desktop.dart b/packages/flet/lib/src/utils/desktop.dart index 34d44b696b..fba99767c2 100644 --- a/packages/flet/lib/src/utils/desktop.dart +++ b/packages/flet/lib/src/utils/desktop.dart @@ -1,7 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:window_manager/window_manager.dart'; -import 'package:window_to_front/window_to_front.dart'; import '../models/window_state.dart'; import 'platform.dart'; @@ -243,7 +242,9 @@ Future focusWindow() async { Future windowToFront() async { if (isDesktopPlatform()) { - await WindowToFront.activate(); + // Bring the window to the front, activating the app over other apps + // (window_manager.show() calls NSApp.activate(ignoringOtherApps: true)). + await windowManager.show(); } } diff --git a/packages/flet/lib/src/utils/text.dart b/packages/flet/lib/src/utils/text.dart index bf0519f047..8a3ad5a567 100644 --- a/packages/flet/lib/src/utils/text.dart +++ b/packages/flet/lib/src/utils/text.dart @@ -63,12 +63,12 @@ List parseTextSpans(List spans, ThemeData theme, TextSpan? parseInlineSpan(Control span, ThemeData theme, [void Function(Control, String, [dynamic eventData])? sendControlEvent]) { span.notifyParent = true; - var onClick = span.getBool("on_click", false)!; + var onClick = span.hasEventHandler("click"); var url = span.getUrl("url"); return TextSpan( text: span.getString("text"), - style: parseTextStyle(span.get("style"), theme), + style: span.getTextStyle("style", theme), spellOut: span.getBool("spell_out"), semanticsLabel: span.getString("semantics_label"), children: parseTextSpans(span.children("spans"), theme, sendControlEvent), @@ -83,12 +83,12 @@ TextSpan? parseInlineSpan(Control span, ThemeData theme, if (onClick) sendControlEvent(span, "click"); }) : null, - onEnter: span.getBool("on_enter", false)! && + onEnter: span.hasEventHandler("enter") && !span.disabled && sendControlEvent != null ? (event) => sendControlEvent(span, "enter") : null, - onExit: span.getBool("on_exit", false)! && + onExit: span.hasEventHandler("exit") && !span.disabled && sendControlEvent != null ? (event) => sendControlEvent(span, "exit") diff --git a/packages/flet/lib/src/widgets/boot_screen.dart b/packages/flet/lib/src/widgets/boot_screen.dart new file mode 100644 index 0000000000..bc229156e7 --- /dev/null +++ b/packages/flet/lib/src/widgets/boot_screen.dart @@ -0,0 +1,25 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; + +import '../flet_extension.dart'; +import '../models/boot_status.dart'; +import 'flet_boot_screen.dart'; + +/// Resolves the boot screen widget named [name] by asking each extension in +/// turn (first non-null wins), falling back to the built-in [FletBootScreen]. +/// +/// The fallback lives here — not in any extension — so it works identically in +/// both boot phases (the prepare phase's extension list does not include the +/// core extension). This guarantees a boot screen is ALWAYS rendered. +Widget resolveBootScreen({ + required String name, + required Map options, + required List extensions, + required ValueListenable status, +}) { + for (final ext in extensions) { + final widget = ext.createBootScreen(name, options, status); + if (widget != null) return widget; + } + return FletBootScreen(options: options, status: status); +} diff --git a/packages/flet/lib/src/widgets/flet_boot_screen.dart b/packages/flet/lib/src/widgets/flet_boot_screen.dart new file mode 100644 index 0000000000..20a4f7687c --- /dev/null +++ b/packages/flet/lib/src/widgets/flet_boot_screen.dart @@ -0,0 +1,167 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import '../models/boot_status.dart'; +import '../utils/colors.dart'; +import '../utils/numbers.dart'; +import '../utils/theme.dart'; + +/// The built-in "flet" boot screen, used as the ultimate fallback whenever no +/// custom boot screen is configured or matched. +/// +/// It always renders something (at minimum a configurable background color) so +/// the gap between the Flutter app starting and the Flet/Python app starting is +/// a controlled surface rather than a bare default scaffold. +/// +/// Supported [options] (all optional): +/// - `theme_mode`: `auto` (default) | `light` | `dark` +/// - `bgcolor_light`, `bgcolor_dark` +/// - `spinner_color_light`, `spinner_color_dark` +/// - `spinner_size` (0 or absent → no spinner) +/// - `text_color_light`, `text_color_dark` +/// - `prepare_message`, `startup_message` (empty/absent → no message) +class FletBootScreen extends StatelessWidget { + final Map options; + final ValueListenable status; + + const FletBootScreen( + {super.key, required this.options, required this.status}); + + bool _isDark(BuildContext context) { + switch ((options["theme_mode"] as String?)?.toLowerCase()) { + case "dark": + return true; + case "light": + return false; + default: + return MediaQuery.platformBrightnessOf(context) == Brightness.dark; + } + } + + Color? _color(String key, bool dark) { + final value = options[dark ? "${key}_dark" : "${key}_light"] as String?; + return HexColor.fromString(null, value); + } + + @override + Widget build(BuildContext context) { + final dark = _isDark(context); + // Follow Flet's default theme (not the bare bootstrap MaterialApp theme) so + // unset colors match what the app itself will use. + final theme = + parseTheme(null, context, dark ? Brightness.dark : Brightness.light); + final bgcolor = _color("bgcolor", dark); + final spinnerColor = _color("spinner_color", dark); + final textColor = _color("text_color", dark); + final spinnerSize = parseInt(options["spinner_size"], 0)!; + + return Theme( + data: theme, + child: ValueListenableBuilder( + valueListenable: status, + builder: (context, bootStatus, _) { + final child = bootStatus.error != null + ? _buildError(context, bootStatus) + : _buildLoading(context, bootStatus, spinnerSize, spinnerColor, + textColor); + return Scaffold( + // null → Flet theme's scaffold background. + backgroundColor: bgcolor, + body: Center(child: child), + ); + }, + ), + ); + } + + Widget _buildLoading(BuildContext context, BootStatus bootStatus, + int spinnerSize, Color? spinnerColor, Color? textColor) { + final message = bootStatus.stage == BootStage.preparing + ? options["prepare_message"] as String? + : options["startup_message"] as String?; + + final children = []; + if (spinnerSize > 0) { + children.add(SizedBox( + width: spinnerSize.toDouble(), + height: spinnerSize.toDouble(), + child: CircularProgressIndicator(strokeWidth: 3, color: spinnerColor), + )); + } + if (message != null && message.isNotEmpty) { + if (children.isNotEmpty) { + children.add(const SizedBox(height: 10)); + } + children.add(Text( + message, + style: Theme.of(context) + .textTheme + .bodySmall + ?.copyWith(color: textColor), + )); + } + + return Column(mainAxisAlignment: MainAxisAlignment.center, children: children); + } + + Widget _buildError(BuildContext context, BootStatus bootStatus) { + final theme = Theme.of(context); + final title = bootStatus.stage == BootStage.preparing + ? "Error starting app" + : "Error running app"; + final text = bootStatus.error ?? ""; + + return Container( + margin: const EdgeInsets.all(20), + padding: const EdgeInsets.all(12), + constraints: const BoxConstraints(maxWidth: 600), + decoration: BoxDecoration( + color: theme.colorScheme.errorContainer, + borderRadius: BorderRadius.circular(8)), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Row(mainAxisSize: MainAxisSize.min, children: [ + Icon(Icons.error_outline, + color: theme.colorScheme.onErrorContainer, size: 24), + const SizedBox(width: 8), + Flexible( + child: Text(title, + style: theme.textTheme.titleSmall?.copyWith( + color: theme.colorScheme.onErrorContainer)), + ), + ]), + ), + TextButton.icon( + onPressed: () { + Clipboard.setData(ClipboardData(text: text)); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Copied to clipboard')), + ); + }, + icon: const Icon(Icons.copy, size: 16), + label: const Text("Copy"), + ), + ], + ), + const SizedBox(height: 8), + Flexible( + child: SingleChildScrollView( + child: SelectableText( + text, + style: theme.textTheme.bodySmall + ?.copyWith(color: theme.colorScheme.onErrorContainer), + ), + ), + ), + ], + ), + ); + } +} diff --git a/packages/flet/lib/src/widgets/loading_page.dart b/packages/flet/lib/src/widgets/loading_page.dart deleted file mode 100644 index 34e90d0452..0000000000 --- a/packages/flet/lib/src/widgets/loading_page.dart +++ /dev/null @@ -1,72 +0,0 @@ -import 'package:flutter/material.dart'; - -class LoadingPage extends StatelessWidget { - final bool isLoading; - final String message; - - const LoadingPage( - {super.key, required this.isLoading, required this.message}); - - @override - Widget build(BuildContext context) { - Widget? child; - - var theme = Theme.of(context); - - if (isLoading) { - List children = [ - const SizedBox( - width: 30, - height: 30, - child: CircularProgressIndicator( - strokeWidth: 3, - ), - ) - ]; - if (message != "") { - children.addAll([ - const SizedBox(height: 10), - Text( - message, - style: Theme.of(context).textTheme.bodySmall, - ) - ]); - } - child = Column( - mainAxisAlignment: MainAxisAlignment.center, - children: children, - ); - } else if (message != "") { - child = Container( - margin: const EdgeInsets.all(20), - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: theme.colorScheme.errorContainer, - borderRadius: BorderRadius.circular(8)), - child: Row(mainAxisSize: MainAxisSize.min, children: [ - Icon(Icons.error_outline, - color: theme.colorScheme.onErrorContainer, size: 30), - const SizedBox(width: 8), - Flexible( - child: SelectionArea( - child: Text( - message, - softWrap: true, - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith(color: theme.colorScheme.onErrorContainer), - ))) - ]), - ); - } - - return Scaffold( - backgroundColor: Colors.transparent, - body: Container( - alignment: Alignment.center, - color: theme.colorScheme.surface, - child: child), - ); - } -} diff --git a/packages/flet/pubspec.yaml b/packages/flet/pubspec.yaml index f4c916dbf0..41ca2cded8 100644 --- a/packages/flet/pubspec.yaml +++ b/packages/flet/pubspec.yaml @@ -2,7 +2,7 @@ name: flet description: Write entire Flutter app in Python or add server-driven UI experience into existing Flutter app. homepage: https://flet.dev repository: https://github.com/flet-dev/flet/tree/main/packages/flet -version: 0.85.3 +version: 0.86.0 # Supported platforms platforms: @@ -27,7 +27,7 @@ dependencies: cupertino_icons: ^1.0.6 device_info_plus: ^12.3.0 equatable: ^2.0.3 - file_picker: ^10.3.10 + file_picker: ^11.0.2 flutter_highlight: ^0.7.0 flutter_markdown_plus: ^1.0.7 flutter_markdown_plus_latex: ^1.0.5 @@ -39,10 +39,10 @@ dependencies: package_info_plus: ^9.0.0 path: ^1.9.0 path_provider: ^2.1.5 - pasteboard: ^0.4.0 + pasteboard: ^0.5.0 provider: ^6.1.2 screenshot: ^3.0.0 - screen_brightness: ^2.1.7 + screen_brightness: ^2.1.11 sensors_plus: ^7.0.0 shared_preferences: ^2.5.3 share_plus: ^12.0.1 @@ -52,7 +52,6 @@ dependencies: web: ^1.1.1 web_socket_channel: ^3.0.2 window_manager: ^0.5.1 - window_to_front: ^0.0.3 wakelock_plus: ^1.4.0 dev_dependencies: diff --git a/packages/flet/test/transport/data_channel_test.dart b/packages/flet/test/transport/data_channel_test.dart new file mode 100644 index 0000000000..750caf9171 --- /dev/null +++ b/packages/flet/test/transport/data_channel_test.dart @@ -0,0 +1,128 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:flet/flet.dart'; +import 'package:flet/src/transport/protocol_muxed_data_channel.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// Minimal in-memory transport: captures outbound packets and lets the test +/// inject inbound ones, exercising FletBackend's type-byte dispatch + the +/// muxed DataChannel routing without spinning up a real transport. +class _FakeChannel implements FletBackendChannel { + final List sent = []; + late FletBackendChannelOnPacketCallback _onPacket; + + FletBackendChannelBuilder get builder => ({ + required FletBackendChannelOnPacketCallback onPacket, + required FletBackendChannelOnDisconnectCallback onDisconnect, + }) { + _onPacket = onPacket; + return this; + }; + + void deliver(Uint8List packet) => _onPacket(packet); + + @override + Future connect() async {} + + @override + bool get isLocalConnection => true; + + @override + int get defaultReconnectIntervalMs => 0; + + @override + void send(Uint8List packet) => sent.add(Uint8List.fromList(packet)); + + @override + void disconnect() {} +} + +void main() { + group('ProtocolMuxedDataChannel wire format', () { + test('send emits [0x01][channel_id:u32 LE][payload]', () { + final backend = FletBackend( + pageUri: Uri.parse("mock"), + assetsDir: "", + extensions: [], + multiView: false); + final ch1 = backend.openDataChannel(); + final ch2 = backend.openDataChannel(); + expect(ch1.id, 1); + expect(ch2.id, 2); + }); + + test('inbound 0x01 frame routes to the right channel', () async { + final fake = _FakeChannel(); + final backend = FletBackend( + pageUri: Uri.parse("mock"), + assetsDir: "", + extensions: [], + multiView: false, + channelBuilder: fake.builder); + // Trigger the connect path so FletBackend wires the fake's onPacket. + // We don't await — connect() also tries _registerClient which goes + // through the (now unused) channel send path; both are fine for this + // smoke test. + // ignore: unawaited_futures + backend.connect(); + + final chA = backend.openDataChannel() as ProtocolMuxedDataChannel; + final chB = backend.openDataChannel() as ProtocolMuxedDataChannel; + + final aFrames = []; + final bFrames = []; + chA.messages.listen(aFrames.add); + chB.messages.listen(bFrames.add); + + // Inbound for channel B (id=2) → 0x01, id LE, payload. + final inbound = Uint8List(5 + 3); + inbound[0] = 0x01; + ByteData.sublistView(inbound, 1, 5).setUint32(0, chB.id, Endian.little); + inbound.setRange(5, 8, [10, 20, 30]); + fake.deliver(inbound); + + // Let the stream-controller microtask flush. + await Future.delayed(Duration.zero); + + expect(aFrames, isEmpty); + expect(bFrames, hasLength(1)); + expect(bFrames.single, equals(Uint8List.fromList([10, 20, 30]))); + + // Stale frame for closed channel is silently dropped. + chA.close(); + final staleA = Uint8List(5 + 1); + staleA[0] = 0x01; + ByteData.sublistView(staleA, 1, 5).setUint32(0, 1, Endian.little); + staleA[5] = 99; + fake.deliver(staleA); // no throw, no delivery + }); + + test('outbound send emits the muxed packet shape', () async { + final fake = _FakeChannel(); + final backend = FletBackend( + pageUri: Uri.parse("mock"), + assetsDir: "", + extensions: [], + multiView: false, + channelBuilder: fake.builder); + // ignore: unawaited_futures + backend.connect(); + + // Drain the register-client packet that FletBackend.connect emits. + final preCount = fake.sent.length; + + final ch = backend.openDataChannel(); + ch.send(Uint8List.fromList([0xAA, 0xBB, 0xCC])); + + // Filter to the 0x01 packets we care about. + final dataPackets = + fake.sent.skip(preCount).where((p) => p.isNotEmpty && p[0] == 0x01).toList(); + expect(dataPackets, hasLength(1)); + final p = dataPackets.single; + expect(p[0], 0x01); + expect(ByteData.sublistView(p, 1, 5).getUint32(0, Endian.little), ch.id); + expect(p.sublist(5), equals(Uint8List.fromList([0xAA, 0xBB, 0xCC]))); + }); + }); +} diff --git a/packages/flet_integration_test/.gitignore b/packages/flet_integration_test/.gitignore new file mode 100644 index 0000000000..35ee281d14 --- /dev/null +++ b/packages/flet_integration_test/.gitignore @@ -0,0 +1,32 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ +.flutter-plugins +.flutter-plugins-dependencies diff --git a/packages/flet_integration_test/analysis_options.yaml b/packages/flet_integration_test/analysis_options.yaml new file mode 100644 index 0000000000..a5744c1cfb --- /dev/null +++ b/packages/flet_integration_test/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/packages/flet_integration_test/lib/flet_integration_test.dart b/packages/flet_integration_test/lib/flet_integration_test.dart new file mode 100644 index 0000000000..eb0e7ce1f7 --- /dev/null +++ b/packages/flet_integration_test/lib/flet_integration_test.dart @@ -0,0 +1,14 @@ +/// Flet integration-testing driver. +/// +/// This is a separate package (not part of `package:flet`) because it depends +/// on the dev-only `flutter_test` and `integration_test` packages, which must +/// never enter a normal Flet app's runtime dependency graph. Depend on it only +/// from a Flutter integration test (under `integration_test/`), where those +/// packages are available. +library flet_integration_test; + +export 'src/device_test.dart'; +export 'src/flutter_test_finder.dart'; +export 'src/flutter_tester.dart'; +export 'src/host_test.dart'; +export 'src/remote_widget_tester.dart'; diff --git a/packages/flet_integration_test/lib/src/device_test.dart b/packages/flet_integration_test/lib/src/device_test.dart new file mode 100644 index 0000000000..f39c5ffcd1 --- /dev/null +++ b/packages/flet_integration_test/lib/src/device_test.dart @@ -0,0 +1,52 @@ +// ignore_for_file: depend_on_referenced_packages +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; + +import 'remote_widget_tester.dart'; + +/// Device-mode integration test entry point for an app built with `flet build`. +/// +/// The app under test runs on-device with embedded Python over the in-process +/// dart_bridge transport (via [appMain]). A [RemoteWidgetTester] connects over a +/// raw socket to the Python `RemoteTester` server (`FLET_TEST_SERVER_URL`) and +/// drives the integration-test `WidgetTester` — an independent channel that does +/// not touch Flet's own transport and adds no widget to the tree. +void runFletDeviceTest({required void Function(List) appMain}) { + var binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + group('end-to-end test', () { + testWidgets('test app', (tester) async { + const serverUrl = String.fromEnvironment("FLET_TEST_SERVER_URL"); + if (serverUrl.isEmpty) { + throw Exception("FLET_TEST_SERVER_URL dart-define is required."); + } + + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.linux) { + await binding.setSurfaceSize(const Size(1280, 720)); + addTearDown(() => binding.setSurfaceSize(null)); + } + + // Launch the on-device app (no args => production/dart_bridge mode) and + // pump frames here, in the test body, so it starts and renders its first + // UI before any remote command arrives. + appMain(const []); + for (var i = 0; i < 20; i++) { + await tester.pump(const Duration(milliseconds: 100)); + } + + // Connect the remote tester last; the Python RemoteTester server unblocks + // once connected and drives the app from here on. + debugPrint("Connecting to remote tester at $serverUrl"); + final widgetTester = await RemoteWidgetTester.connect( + tester: tester, + binding: binding, + serverUri: Uri.parse(serverUrl), + ); + + await widgetTester.waitForTeardown(); + }); + }); +} diff --git a/client/integration_test/flutter_test_finder.dart b/packages/flet_integration_test/lib/src/flutter_test_finder.dart similarity index 85% rename from client/integration_test/flutter_test_finder.dart rename to packages/flet_integration_test/lib/src/flutter_test_finder.dart index 645852a63f..ee356ef421 100644 --- a/client/integration_test/flutter_test_finder.dart +++ b/packages/flet_integration_test/lib/src/flutter_test_finder.dart @@ -1,6 +1,8 @@ -import 'package:flet/flet.dart'; +// ignore_for_file: depend_on_referenced_packages import 'package:flutter_test/flutter_test.dart'; +import 'package:flet/flet.dart'; + class FlutterTestFinder extends TestFinder { final Finder finder; diff --git a/client/integration_test/flutter_tester.dart b/packages/flet_integration_test/lib/src/flutter_tester.dart similarity index 89% rename from client/integration_test/flutter_tester.dart rename to packages/flet_integration_test/lib/src/flutter_tester.dart index 49bb544e4d..d94f55ebb3 100644 --- a/client/integration_test/flutter_tester.dart +++ b/packages/flet_integration_test/lib/src/flutter_tester.dart @@ -1,11 +1,13 @@ +// ignore_for_file: depend_on_referenced_packages import 'dart:async'; -import 'package:flet/flet.dart'; -import 'package:flutter/gestures.dart'; + import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; +import 'package:flet/flet.dart'; import 'flutter_test_finder.dart'; class FlutterWidgetTester implements Tester { @@ -17,6 +19,11 @@ class FlutterWidgetTester implements Tester { FlutterWidgetTester(this._tester, this._binding); + /// The integration-test binding, exposed for subclasses (e.g. + /// `RemoteWidgetTester`). + @protected + IntegrationTestWidgetsFlutterBinding get binding => _binding; + @override Future pumpAndSettle({Duration? duration}) async { await lock.acquire(); @@ -101,14 +108,15 @@ class FlutterWidgetTester implements Tester { } @override - Future tapAt(Offset offset) => - _tester.tapAt(offset); + Future tapAt(Offset offset) => _tester.tapAt(offset); @override - Future mouseClickAt(Offset offset) => _mouseClickAt(offset, kPrimaryButton); + Future mouseClickAt(Offset offset) => + _mouseClickAt(offset, kPrimaryButton); @override - Future mouseDoubleClickAt(Offset offset) => _mouseDoubleClickAt(offset); + Future mouseDoubleClickAt(Offset offset) => + _mouseDoubleClickAt(offset); @override Future rightMouseClickAt(Offset offset) => @@ -130,8 +138,7 @@ class FlutterWidgetTester implements Tester { _tester.longPress((finder as FlutterTestFinder).raw.at(finderIndex)); @override - Future enterText( - TestFinder finder, int finderIndex, String text) => + Future enterText(TestFinder finder, int finderIndex, String text) => _tester.enterText( (finder as FlutterTestFinder).raw.at(finderIndex), text, @@ -184,7 +191,11 @@ class FlutterWidgetTester implements Tester { } @override - void teardown() => _teardown.complete(); + void teardown() { + if (!_teardown.isCompleted) { + _teardown.complete(); + } + } @override Future waitForTeardown() => _teardown.future; diff --git a/packages/flet_integration_test/lib/src/frame_decoder.dart b/packages/flet_integration_test/lib/src/frame_decoder.dart new file mode 100644 index 0000000000..2dff2704eb --- /dev/null +++ b/packages/flet_integration_test/lib/src/frame_decoder.dart @@ -0,0 +1,65 @@ +import 'dart:async'; +import 'dart:typed_data'; + +/// Decodes a byte stream of length-prefixed frames into individual frame +/// payloads. Each frame is a big-endian uint32 length followed by that many +/// payload bytes. More robust than a newline delimiter — payloads may contain +/// arbitrary bytes (e.g. base64 screenshots) without escaping. +class FrameDecoder extends StreamTransformerBase { + final int maxFrameLength; + + const FrameDecoder({this.maxFrameLength = 64 * 1024 * 1024}); + + /// Encodes [payload] as a length-prefixed frame. + static Uint8List encode(List payload) { + final frame = Uint8List(4 + payload.length); + ByteData.view(frame.buffer).setUint32(0, payload.length, Endian.big); + frame.setRange(4, frame.length, payload); + return frame; + } + + @override + Stream bind(Stream stream) { + var buffer = Uint8List(0); + late StreamController controller; + StreamSubscription? subscription; + + void onChunk(Uint8List chunk) { + final merged = Uint8List(buffer.length + chunk.length) + ..setRange(0, buffer.length, buffer) + ..setRange(buffer.length, buffer.length + chunk.length, chunk); + buffer = merged; + + while (buffer.length >= 4) { + final length = + ByteData.sublistView(buffer, 0, 4).getUint32(0, Endian.big); + if (length > maxFrameLength) { + controller.addError( + StateError("Frame length $length exceeds limit $maxFrameLength."), + ); + subscription?.cancel(); + return; + } + if (buffer.length < 4 + length) break; + controller.add(Uint8List.fromList(buffer.sublist(4, 4 + length))); + buffer = Uint8List.fromList(buffer.sublist(4 + length)); + } + } + + controller = StreamController( + onListen: () { + subscription = stream.listen( + onChunk, + onError: controller.addError, + onDone: controller.close, + cancelOnError: false, + ); + }, + onPause: () => subscription?.pause(), + onResume: () => subscription?.resume(), + onCancel: () => subscription?.cancel(), + ); + + return controller.stream; + } +} diff --git a/packages/flet_integration_test/lib/src/host_test.dart b/packages/flet_integration_test/lib/src/host_test.dart new file mode 100644 index 0000000000..d20ceccdbd --- /dev/null +++ b/packages/flet_integration_test/lib/src/host_test.dart @@ -0,0 +1,81 @@ +// ignore_for_file: depend_on_referenced_packages + +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; + +import 'package:flet/flet.dart'; +import 'flutter_tester.dart'; + +/// Runs an integration test in "host" mode: the Flet app under test runs in a +/// separate Python (pytest) process which also acts as the Flet server, and the +/// Flutter app connects back to it over a single transport (TCP/HTTP/UDS). The +/// [Tester] rides that same connection. +/// +/// This is the mechanism used by the Flet dev "client" shell and the Flet +/// team's white-box tests. For testing an app built with `flet build` (embedded +/// Python over dart_bridge), use `runFletDeviceTest` instead. +/// +/// [appMain] is the host app's `main(args)` entry point. [assignTester] is +/// called with the constructed [Tester] before `appMain` runs so the host can +/// wire it into its `FletApp(tester: ...)`. +void runFletHostTest({ + required void Function(List) appMain, + required void Function(Tester) assignTester, +}) { + var binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + // With the integration_test binding `flutter test` prints only + // "Test failed. See exception logs above." without ever printing the + // exception that failed the test (e.g. a render overflow reported during a + // frame). Log it here so the failure reason is visible in the test process + // output. + final prevReportTestException = reportTestException; + reportTestException = (details, testDescription) { + debugPrint("Test exception ($testDescription): " + "${details.exceptionAsString()}\n${details.stack ?? ''}"); + prevReportTestException(details, testDescription); + }; + debugPrint("Flet host test: exception reporter installed"); + + tearDownAll(() async { + // Exceptions are reported when the test body completes, moments before + // the app process exits; give the device-log relay time to flush them so + // they are not lost from the `flutter test` output. + await Future.delayed(const Duration(seconds: 2)); + }); + + group('end-to-end test', () { + testWidgets('test app', (tester) async { + var dir = Directory.current.path; + debugPrint("Current dir: $dir"); + + var fletTester = FlutterWidgetTester(tester, binding); + assignTester(fletTester); + + List args = []; + const fletTestAppUrl = String.fromEnvironment("FLET_TEST_APP_URL"); + if (fletTestAppUrl != "") { + args.add(fletTestAppUrl); + } + + const fletTestPidFile = String.fromEnvironment("FLET_TEST_PID_FILE_PATH"); + if (fletTestPidFile != "") { + args.add(fletTestPidFile); + } + + const fletTestAssetsDir = String.fromEnvironment("FLET_TEST_ASSETS_DIR"); + if (fletTestAssetsDir != "") { + args.add(fletTestAssetsDir); + } + + appMain(args); + + await Future.delayed(const Duration(milliseconds: 500)); + await fletTester.pump(duration: const Duration(seconds: 1)); + await fletTester.pumpAndSettle( + duration: const Duration(milliseconds: 100)); + await fletTester.waitForTeardown(); + }); + }); +} diff --git a/packages/flet_integration_test/lib/src/remote_widget_tester.dart b/packages/flet_integration_test/lib/src/remote_widget_tester.dart new file mode 100644 index 0000000000..03cbbb9471 --- /dev/null +++ b/packages/flet_integration_test/lib/src/remote_widget_tester.dart @@ -0,0 +1,278 @@ +// ignore_for_file: depend_on_referenced_packages +// ignore_for_file: non_const_argument_for_const_parameter +import 'dart:async'; +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; + +import 'package:flet/flet.dart'; +import 'flutter_test_finder.dart'; +import 'flutter_tester.dart'; +import 'frame_decoder.dart'; + +/// Drives [FlutterWidgetTester] over an independent length-prefixed JSON +/// protocol on a raw TCP socket — completely separate from Flet's own transport. +/// +/// The on-device app under test runs normally (embedded Python over +/// dart_bridge); this socket connects out to the Python `RemoteTester` server +/// and is the only channel that drives the integration-test `WidgetTester`. No +/// `FletApp`/`FletBackend` is added to the widget tree, so the app settles +/// normally and `WidgetTester.pump`/`pumpAndSettle` behave as usual. +class RemoteWidgetTester extends FlutterWidgetTester { + final Socket _socket; + final Map _finders = {}; + final Completer _connectionClosed = Completer(); + Future _commandQueue = Future.value(); + StreamSubscription? _subscription; + bool _teardownRequested = false; + + RemoteWidgetTester._( + super.tester, + super.binding, + this._socket, + ) { + _startListening(); + } + + static Future connect({ + required WidgetTester tester, + required IntegrationTestWidgetsFlutterBinding binding, + required Uri serverUri, + Duration timeout = const Duration(seconds: 10), + }) async { + if (!serverUri.hasPort) { + throw ArgumentError("Server URL must include a port: $serverUri"); + } + final host = serverUri.host.isEmpty ? "127.0.0.1" : serverUri.host; + final port = serverUri.port; + final socket = await Socket.connect(host, port, timeout: timeout); + socket.setOption(SocketOption.tcpNoDelay, true); + return RemoteWidgetTester._(tester, binding, socket); + } + + void _startListening() { + final stream = _socket.transform(const FrameDecoder()); + _subscription = stream.listen(null, onError: (error, stackTrace) { + if (!_connectionClosed.isCompleted) { + _connectionClosed.completeError(error, stackTrace); + } + _closeSilently(); + }, onDone: () { + _closeSilently(); + if (!_connectionClosed.isCompleted) { + _connectionClosed.complete(); + } + }, cancelOnError: true); + // Serialize commands by chaining them onto a single queue. Do NOT pause the + // subscription while a command runs: pausing also stops the socket being + // serviced for writes, so `_sendResponse`'s flush would deadlock (the + // response only transmits when an unrelated incoming byte wakes the link). + _subscription!.onData((frame) { + _commandQueue = _commandQueue.then((_) => _processFrame(frame)); + }); + } + + Future _processFrame(Uint8List frame) async { + final dynamic decoded = jsonDecode(utf8.decode(frame)); + if (decoded is! Map) { + throw Exception("Invalid command payload: $decoded"); + } + final id = decoded["id"]; + final method = decoded["method"] as String?; + final params = (decoded["params"] as Map?) + ?.cast() ?? + const {}; + + if (id == null || method == null) { + throw Exception("Command must include both 'id' and 'method'."); + } + + try { + final response = await _handleCommand(method, params); + await _sendResponse(id, result: response.result); + if (response.closeAfter) { + await _socket.flush(); + await _socket.close(); + await _subscription?.cancel(); + if (!_connectionClosed.isCompleted) { + _connectionClosed.complete(); + } + } + } catch (error, stackTrace) { + await _sendResponse(id, error: "$error", stack: stackTrace.toString()); + } + } + + _CommandResponse _ok([dynamic result]) => + _CommandResponse(result, closeAfter: false); + + Future<_CommandResponse> _handleCommand( + String method, + Map params, + ) async { + switch (method) { + case "pump": + await pump(duration: _parseDuration(params["duration"])); + return _ok(); + case "pump_and_settle": + await pumpAndSettle(duration: _parseDuration(params["duration"])); + return _ok(); + case "find_by_text": + return _ok(_storeFinder(findByText(params["text"] as String))); + case "find_by_text_containing": + return _ok( + _storeFinder(findByTextContaining(params["pattern"] as String)), + ); + case "find_by_key": + return _ok(_storeFinder(findByKey(_parseKey(params["key"])))); + case "find_by_tooltip": + return _ok(_storeFinder(findByTooltip(params["value"] as String))); + case "find_by_icon": + return _ok(_storeFinder(findByIcon(_parseIcon(params["icon"])))); + case "take_screenshot": + final bytes = await takeScreenshot(params["name"] as String); + return _ok(base64Encode(bytes)); + case "tap": + await _withFinder( + params, (finder, index) => tap(finder, index)); + return _ok(); + case "long_press": + await _withFinder( + params, (finder, index) => longPress(finder, index)); + return _ok(); + case "enter_text": + await _withFinder(params, + (finder, index) => enterText(finder, index, params["text"] as String)); + return _ok(); + case "mouse_hover": + await _withFinder( + params, (finder, index) => mouseHover(finder, index)); + return _ok(); + case "teardown": + _triggerTeardown(); + return const _CommandResponse(null, closeAfter: true); + default: + throw Exception("Unknown Tester method: $method"); + } + } + + Map _storeFinder(TestFinder finder) { + final flutterFinder = finder as FlutterTestFinder; + _finders[flutterFinder.id] = flutterFinder; + return flutterFinder.toMap(); + } + + Future _withFinder( + Map params, + Future Function(FlutterTestFinder finder, int index) action, + ) async { + final id = params["finder_id"]; + final index = (params["finder_index"] as int?) ?? 0; + final finder = _finders[id]; + if (finder == null) { + throw Exception("Finder with id $id is not registered."); + } + await action(finder, index); + } + + Duration? _parseDuration(dynamic value) { + if (value == null) return null; + if (value is int) return Duration(milliseconds: value); + if (value is double) return Duration(milliseconds: value.round()); + if (value is Map) { + final ms = value["milliseconds"] ?? value["ms"]; + if (ms is num) return Duration(milliseconds: ms.round()); + } + return null; + } + + IconData _parseIcon(dynamic value) { + if (value is Map) { + final codePoint = value["code_point"] as int?; + if (codePoint == null) { + throw Exception("Icon payload must include 'code_point'."); + } + return IconData( + codePoint, + fontFamily: value["font_family"] as String?, + fontPackage: value["font_package"] as String?, + matchTextDirection: (value["match_text_direction"] as bool?) ?? false, + ); + } else if (value is int) { + return IconData(value, fontFamily: "MaterialIcons"); + } + throw Exception("Invalid icon format: $value"); + } + + Key _parseKey(dynamic value) { + final v = (value is Map) ? value["value"] : value; + // Preserve the concrete value type so the constructed ValueKey matches + // the one the rendered control assigned — ValueKey's `==` is runtimeType + // strict (ValueKey('x') != ValueKey('x')). + return switch (v) { + String s => ValueKey(s), + int i => ValueKey(i), + double d => ValueKey(d), + bool b => ValueKey(b), + _ => ValueKey(v), + }; + } + + Future _sendResponse( + dynamic id, { + dynamic result, + String? error, + String? stack, + }) async { + final payload = {"id": id}; + if (error != null) { + payload["error"] = error; + if (stack != null) { + payload["stack"] = stack; + } + } else { + payload["result"] = result; + } + final encoded = jsonEncode(payload); + _socket.add(FrameDecoder.encode(utf8.encode(encoded))); + await _socket.flush(); + } + + void _closeSilently() { + _subscription?.cancel(); + _triggerTeardown(); + if (!_connectionClosed.isCompleted) { + _connectionClosed.complete(); + } + } + + void _triggerTeardown() { + if (_teardownRequested) { + return; + } + _teardownRequested = true; + super.teardown(); + } + + @override + void teardown() => _triggerTeardown(); + + /// Blocks until Python calls teardown (or the connection drops). Commands are + /// handled in the socket subscription; the test body just parks here, exactly + /// like the host-mode FlutterWidgetTester. + @override + Future waitForTeardown() async { + await _commandQueue; + await Future.wait([super.waitForTeardown(), _connectionClosed.future]); + } +} + +class _CommandResponse { + final dynamic result; + final bool closeAfter; + + const _CommandResponse(this.result, {required this.closeAfter}); +} diff --git a/packages/flet_integration_test/pubspec.yaml b/packages/flet_integration_test/pubspec.yaml new file mode 100644 index 0000000000..6ab6cb745b --- /dev/null +++ b/packages/flet_integration_test/pubspec.yaml @@ -0,0 +1,38 @@ +name: flet_integration_test +description: Driver for running Flet app integration tests on-device. Internal Flet tooling, not published to pub.dev. +homepage: https://flet.dev +repository: https://github.com/flet-dev/flet/tree/main/packages/flet_integration_test +version: 0.86.0 +publish_to: none + +environment: + sdk: '>=3.0.0 <4.0.0' + +dependencies: + flutter: + sdk: flutter + # flet is depended on by VERSION (not path) so that when this package is + # consumed — as a path dep in repo dev or a git dep in an end user's test host + # — flet resolves to the SAME source as the app's flet (the app's + # dependency_overrides win for the whole graph). A path here would pin a second + # flet source and conflict with the app's pub.dev flet. + flet: ^0.86.0 + # integration_test (on-device test binding) and flutter_test (WidgetTester) are + # regular dependencies, not dev: this is a test-helper package, so consumers + # that depend on it get both transitively for `flutter test`. + integration_test: + sdk: flutter + flutter_test: + sdk: flutter + +dev_dependencies: + flutter_lints: ^3.0.1 + +# Only used when this package is the root (standalone analyze / repo dev): build +# the driver against the in-repo flet rather than a published version. Ignored +# when this package is consumed as a dependency. +dependency_overrides: + flet: + path: ../flet + +flutter: diff --git a/sdk/python/.pre-commit-config.yaml b/sdk/python/.pre-commit-config.yaml index 9a0bd650d0..1e5cc48899 100644 --- a/sdk/python/.pre-commit-config.yaml +++ b/sdk/python/.pre-commit-config.yaml @@ -28,4 +28,8 @@ repos: hooks: - id: typos args: [ --config, sdk/python/_typos.toml ] - exclude: /templates/ + # Generated *.pbxproj files contain random hex UUIDs that typos + # misreads as misspelled words; flet-mcp's icons.json vendors + # Google's icon search tags, which deliberately include common + # misspellings for typo-tolerant search. + exclude: (/templates/|\.pbxproj$|flet_mcp/data/icons\.json$) diff --git a/sdk/python/_typos.toml b/sdk/python/_typos.toml index e68027a320..0e89826b56 100644 --- a/sdk/python/_typos.toml +++ b/sdk/python/_typos.toml @@ -1,6 +1,21 @@ +[files] +# Generated Xcode project files contain random hex UUIDs that typos +# misreads as misspelled words. flet-mcp's icons.json vendors Google's +# icon search metadata, whose tags deliberately include common +# misspellings for typo-tolerant search. +extend-exclude = [ + "*.pbxproj", + "sdk/python/packages/flet-mcp/src/flet_mcp/data/icons.json", +] + [default.extend-words] # AAC High Efficiency audio codec enum member name AACHE = "AACHE" ROUTEROS = "ROUTEROS" # OpenType variable font axis tag for width wdth = "wdth" +# iOS Unique Device IDentifier (simctl `.udid` JSON field / shell var names) +UDID = "UDID" +udid = "udid" +# Python package name (Mozilla CA bundle) +certifi = "certifi" diff --git a/sdk/python/examples/apps/flet_build_test/pyproject.toml b/sdk/python/examples/apps/flet_build_test/pyproject.toml index 256622f74b..6bd918b24b 100644 --- a/sdk/python/examples/apps/flet_build_test/pyproject.toml +++ b/sdk/python/examples/apps/flet_build_test/pyproject.toml @@ -14,6 +14,8 @@ dependencies = [ "flet-audio-recorder", "flet-camera", "flet-charts", + "flet-code-editor", + "flet-color-pickers", "flet-datatable2", "flet-flashlight", "flet-geolocator", @@ -44,6 +46,8 @@ flet-audio = { path = "../../../packages/flet-audio", editable = true } flet-audio-recorder = { path = "../../../packages/flet-audio-recorder", editable = true } flet-camera = { path = "../../../packages/flet-camera", editable = true } flet-charts = { path = "../../../packages/flet-charts", editable = true } +flet-code-editor = { path = "../../../packages/flet-code-editor", editable = true } +flet-color-pickers = { path = "../../../packages/flet-color-pickers", editable = true } flet-datatable2 = { path = "../../../packages/flet-datatable2", editable = true } flet-flashlight = { path = "../../../packages/flet-flashlight", editable = true } flet-geolocator = { path = "../../../packages/flet-geolocator", editable = true } @@ -63,6 +67,8 @@ flet-audio = "../../../packages/flet-audio" flet-audio-recorder = "../../../packages/flet-audio-recorder" flet-camera = "../../../packages/flet-camera" flet-charts = "../../../packages/flet-charts" +flet-code-editor = "../../../packages/flet-code-editor" +flet-color-pickers = "../../../packages/flet-color-pickers" flet-datatable2 = "../../../packages/flet-datatable2" flet-flashlight = "../../../packages/flet-flashlight" flet-geolocator = "../../../packages/flet-geolocator" @@ -88,6 +94,19 @@ build_number = 1 [tool.flet.app] path = "src" +[tool.flet.boot_screen] +name = "spinkit" + +[tool.flet.boot_screen.spinkit] +theme_mode = "auto" +spinner = "ChasingDots" +spinner_color_light = "#7c4dff" +spinner_color_dark = "#b388ff" +spinner_size = 60 +prepare_message = "Preparing your app..." +startup_message = "Starting up..." +fade_out_duration = 200 + [tool.flet.android.permission] "android.permission.READ_EXTERNAL_STORAGE" = true "android.permission.WRITE_EXTERNAL_STORAGE" = true @@ -97,8 +116,8 @@ path = "src" [tool.flet.android.meta_data] "com.google.android.gms.ads.APPLICATION_ID" = "ca-app-pub-3940256099942544~3347511713" -[tool.flet.android.provider] -"rikka.shizuku.ShizukuProvider" = { authorities = "${applicationId}.shizuku", multiprocess = "false", enabled = "true", exported = "true", permission = "android.permission.INTERACT_ACROSS_USERS_FULL" } +# [tool.flet.android.provider] +# "rikka.shizuku.ShizukuProvider" = { authorities = "${applicationId}.shizuku", multiprocess = "false", enabled = "true", exported = "true", permission = "android.permission.INTERACT_ACROSS_USERS_FULL" } [tool.flet.ios.info] GADApplicationIdentifier = "ca-app-pub-3940256099942544~3347511713" diff --git a/sdk/python/examples/apps/flet_build_test/src/main.py b/sdk/python/examples/apps/flet_build_test/src/main.py index 5eb53b1e05..63c35edd28 100644 --- a/sdk/python/examples/apps/flet_build_test/src/main.py +++ b/sdk/python/examples/apps/flet_build_test/src/main.py @@ -1,5 +1,7 @@ import sys +import flet_code_editor # noqa: F401 +import flet_spinkit # noqa: F401 import numpy import PIL from modules.utils import greet @@ -10,6 +12,7 @@ import flet_audio # noqa: F401 import flet_audio_recorder # noqa: F401 import flet_charts # noqa: F401 +import flet_color_pickers # noqa: F401 import flet_datatable2 # noqa: F401 import flet_flashlight # noqa: F401 import flet_geolocator # noqa: F401 diff --git a/sdk/python/examples/apps/flet_test_counter/pyproject.toml b/sdk/python/examples/apps/flet_test_counter/pyproject.toml new file mode 100644 index 0000000000..e589264c34 --- /dev/null +++ b/sdk/python/examples/apps/flet_test_counter/pyproject.toml @@ -0,0 +1,46 @@ +[project] +name = "flet_test_counter" +version = "0.1.0" +description = "Counter app used by the flet-test CI workflow to exercise `flet test` on-device." +requires-python = ">=3.10" +authors = [{ name = "Appveyor Systems Inc.", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = [ + "flet-cli", + "flet-desktop", + # Integration testing with `flet test` / pytest. The `test` extra brings in + # pytest, pytest-asyncio and the screenshot-comparison dependencies used by + # flet.testing. + "flet[test]", +] + +[tool.uv.sources] +flet = { path = "../../../packages/flet", editable = true } +flet-cli = { path = "../../../packages/flet-cli", editable = true } +flet-desktop = { path = "../../../packages/flet-desktop", editable = true } + +[tool.pytest.ini_options] +asyncio_mode = "auto" +testpaths = ["tests"] + +# Docs: https://flet.dev/docs/publish/ +[tool.flet] +product = "Flet Test Counter" +artifact = "flet-test-counter" +project = "flet_test_counter" +company = "Flet" +org = "com.flet" +copyright = "Copyright (C) 2026 by Flet" + +[tool.flet.app] +path = "src" + +# Embedded Python flet = in-repo source (not pub.dev). +[tool.flet.dev_packages] +flet = "../../../packages/flet" + +# Dart flet = in-repo source (relative to the provisioned build/flutter dir). +[tool.flet.flutter.pubspec.dependency_overrides] +flet = { path = "../../../../../../../packages/flet" } diff --git a/sdk/python/examples/apps/flet_test_counter/src/main.py b/sdk/python/examples/apps/flet_test_counter/src/main.py new file mode 100644 index 0000000000..4ece41a18e --- /dev/null +++ b/sdk/python/examples/apps/flet_test_counter/src/main.py @@ -0,0 +1,42 @@ +import platform + +import flet as ft + + +def main(page: ft.Page): + counter = ft.Text("0", size=50) + version = ft.Text(f"Python {platform.python_version()}", key="python_version") + + def increment(e): + counter.value = str(int(counter.value) + 1) + counter.update() + + def decrement(e): + counter.value = str(int(counter.value) - 1) + counter.update() + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + version, + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.IconButton( + ft.Icons.REMOVE, key="decrement", on_click=decrement + ), + counter, + ft.IconButton( + ft.Icons.ADD, key="increment", on_click=increment + ), + ], + ), + ], + ) + ) + ) + + +ft.run(main) diff --git a/sdk/python/examples/apps/flet_test_counter/tests/test_main.py b/sdk/python/examples/apps/flet_test_counter/tests/test_main.py new file mode 100644 index 0000000000..7d36d9da25 --- /dev/null +++ b/sdk/python/examples/apps/flet_test_counter/tests/test_main.py @@ -0,0 +1,35 @@ +import os +import re + +import flet.testing as ftt + + +async def test_counter(flet_app: ftt.FletTestApp): + tester = flet_app.tester + + await tester.pump_and_settle() + + # The app displays the embedded Python version it was built against. CI pins + # it per matrix leg (EXPECTED_PYTHON_VERSION, e.g. "3.14"); assert the app + # reports that major.minor. Without the env var (e.g. a local run) just + # assert some version is shown. + expected = os.getenv("EXPECTED_PYTHON_VERSION") + if expected: + pattern = rf"Python {re.escape(expected)}\." + else: + pattern = r"Python \d+\.\d+\.\d+" + assert (await tester.find_by_text_containing(pattern)).count == 1 + + # Initial state + assert (await tester.find_by_text("0")).count == 1 + + # Increment once + await tester.tap(await tester.find_by_key("increment")) + await tester.pump_and_settle() + assert (await tester.find_by_text("1")).count == 1 + + # Decrement twice -> -1 + await tester.tap(await tester.find_by_key("decrement")) + await tester.tap(await tester.find_by_key("decrement")) + await tester.pump_and_settle() + assert (await tester.find_by_text("-1")).count == 1 diff --git a/sdk/python/examples/controls/core/raw_image/game_of_life/main.py b/sdk/python/examples/controls/core/raw_image/game_of_life/main.py new file mode 100644 index 0000000000..297c1040e3 --- /dev/null +++ b/sdk/python/examples/controls/core/raw_image/game_of_life/main.py @@ -0,0 +1,135 @@ +import asyncio +import time +from collections import deque + +import numpy as np + +import flet as ft + +GRID_WIDTH = 160 +GRID_HEIGHT = 100 +CELL_SIZE = 5 # logical pixels per cell on screen +FPS_WINDOW_SECONDS = 2.0 + +ALIVE_COLOR = (80, 250, 123) +DEAD_COLOR = (30, 32, 44) + + +def step(world: np.ndarray) -> np.ndarray: + """One Game of Life generation on a wrapping (toroidal) grid.""" + neighbors = sum( + np.roll(np.roll(world, dy, axis=0), dx, axis=1) + for dy in (-1, 0, 1) + for dx in (-1, 0, 1) + if (dy, dx) != (0, 0) + ) + return (neighbors == 3) | (world & (neighbors == 2)) + + +def world_frame(world: np.ndarray) -> np.ndarray: + frame = np.empty((GRID_HEIGHT, GRID_WIDTH, 4), dtype=np.uint8) + frame[..., :3] = np.where(world[..., None], ALIVE_COLOR, DEAD_COLOR) + frame[..., 3] = 255 + return frame + + +async def main(page: ft.Page): + page.title = "RawImage Game of Life" + + rng = np.random.default_rng(42) + world = rng.random((GRID_HEIGHT, GRID_WIDTH)) < 0.2 + + # One frame pixel per cell: the client upscales with nearest-neighbor + # (filter_quality=NONE), so each cell stays a crisp square and frames + # remain tiny (grid-sized) regardless of the on-screen size. + raw_image = ft.RawImage( + width=GRID_WIDTH * CELL_SIZE, + height=GRID_HEIGHT * CELL_SIZE, + fit=ft.BoxFit.FILL, + filter_quality=ft.FilterQuality.NONE, + ) + + playing = True + dirty = asyncio.Event() + frame_times: deque[float] = deque() + + def toggle_playing(): + nonlocal playing + playing = not playing + play_button.icon = ft.Icons.PAUSE if playing else ft.Icons.PLAY_ARROW + play_button.update() + dirty.set() + + def randomize(): + nonlocal world + world = rng.random((GRID_HEIGHT, GRID_WIDTH)) < 0.2 + dirty.set() + + def clear(): + nonlocal world + world = np.zeros((GRID_HEIGHT, GRID_WIDTH), dtype=bool) + dirty.set() + + def paint_cell(position: ft.Offset): + # Draw with the pointer, also while the simulation is running. + x = int(position.x // CELL_SIZE) + y = int(position.y // CELL_SIZE) + if 0 <= x < GRID_WIDTH and 0 <= y < GRID_HEIGHT: + world[y, x] = True + dirty.set() + + play_button = ft.IconButton(ft.Icons.PAUSE, on_click=toggle_playing) + speed_slider = ft.Slider(min=1, max=60, value=20, width=150) + fps_text = ft.Text("fps: —", size=12) + + page.add( + ft.Row( + [ + play_button, + ft.Text("speed:"), + speed_slider, + ft.OutlinedButton("Randomize", on_click=randomize), + ft.OutlinedButton("Clear", on_click=clear), + fps_text, + ], + spacing=10, + ), + ft.GestureDetector( + content=raw_image, + on_tap_down=lambda e: paint_cell(e.local_position), + on_pan_update=lambda e: paint_cell(e.local_position), + drag_interval=10, + ), + ) + + async def run_loop(): + nonlocal world + while True: + if playing: + world = step(world) + dirty.clear() + else: + # Paused: wait for pointer edits or the play button. + await dirty.wait() + dirty.clear() + try: + await raw_image.render(world_frame(world), premultiplied=True) + except (RuntimeError, TimeoutError): + return # window closed — session destroyed + now = time.monotonic() + frame_times.append(now) + while frame_times and frame_times[0] < now - FPS_WINDOW_SECONDS: + frame_times.popleft() + fps_text.value = f"fps: {len(frame_times) / FPS_WINDOW_SECONDS:.1f}" + try: + page.update() + except RuntimeError: + return + if playing: + await asyncio.sleep(1 / speed_slider.value) + + asyncio.create_task(run_loop()) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/raw_image/game_of_life/pyproject.toml b/sdk/python/examples/controls/core/raw_image/game_of_life/pyproject.toml new file mode 100644 index 0000000000..1f4d34ea39 --- /dev/null +++ b/sdk/python/examples/controls/core/raw_image/game_of_life/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "raw-image-game-of-life" +version = "1.0.0" +description = "Conway's Game of Life with pointer drawing, play/pause and speed control, rendered through RawImage." +requires-python = ">=3.10" +keywords = ["raw image", "game of life", "cellular automaton", "numpy", "interactive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "numpy"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/RawImage"] + +[tool.flet.metadata] +title = "Game of Life" +controls = ["RawImage", "GestureDetector", "Row", "Slider", "IconButton", "OutlinedButton"] +layout_pattern = "toolbar above canvas" +complexity = "intermediate" +features = ["cellular automaton", "nearest-neighbor upscaling", "pointer cell drawing", "play/pause", "speed slider", "fps counter"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/raw_image/mandelbrot/main.py b/sdk/python/examples/controls/core/raw_image/mandelbrot/main.py new file mode 100644 index 0000000000..3014355c63 --- /dev/null +++ b/sdk/python/examples/controls/core/raw_image/mandelbrot/main.py @@ -0,0 +1,147 @@ +import asyncio +import time +from collections import deque + +import numpy as np + +import flet as ft + +WIDTH = 640 +HEIGHT = 480 +MAX_ITER = 96 +ZOOM_PER_CLICK = 8.0 +ZOOM_FRAMES = 30 +HOME = (-0.65, 0.0, 1.6) # center x, center y, half-width of the view +FPS_WINDOW_SECONDS = 2.0 + + +def mandelbrot_frame(center_x: float, center_y: float, scale: float) -> np.ndarray: + """ + Escape-time Mandelbrot render, fully vectorized: points that stay + bounded for MAX_ITER iterations are painted black, escaped points get + a sine palette keyed on the escape iteration. + """ + aspect = HEIGHT / WIDTH + x = np.linspace(center_x - scale, center_x + scale, WIDTH) + y = np.linspace(center_y - scale * aspect, center_y + scale * aspect, HEIGHT) + c = x[None, :] + 1j * y[:, None] + z = np.zeros_like(c) + escape_iter = np.full(c.shape, MAX_ITER, dtype=np.int32) + alive = np.ones(c.shape, dtype=bool) + for i in range(MAX_ITER): + z[alive] = z[alive] ** 2 + c[alive] + escaped = alive & (np.abs(z) > 2.0) + escape_iter[escaped] = i + alive &= ~escaped + t = escape_iter / MAX_ITER + frame = np.zeros((HEIGHT, WIDTH, 4), dtype=np.uint8) + outside = ~alive + frame[outside, 0] = np.sin(t[outside] * 9.0) * 127 + 128 + frame[outside, 1] = np.sin(t[outside] * 9.0 + 1.2) * 127 + 128 + frame[outside, 2] = np.sin(t[outside] * 9.0 + 2.4) * 127 + 128 + frame[..., 3] = 255 + return frame + + +async def main(page: ft.Page): + page.title = "RawImage Mandelbrot" + + # No fixed size: the control fills the window (expand=True) and CONTAIN + # scales the 640x480 frame into whatever box the layout provides, so the + # image grows and shrinks with the window. + raw_image = ft.RawImage(expand=True, fit=ft.BoxFit.CONTAIN) + fps_text = ft.Text("fps: —", size=12) + zoom_text = ft.Text("zoom: 1x", size=12) + hint_text = ft.Text("click to zoom in", size=12, italic=True) + + view = HOME + frame_times: deque[float] = deque() + zoom_task: asyncio.Task | None = None + box_size = (float(WIDTH), float(HEIGHT)) # laid-out size of the control + + def track_size(e: ft.LayoutSizeChangeEvent): + nonlocal box_size + box_size = (e.width, e.height) + + raw_image.on_size_change = track_size + + async def show(center_x: float, center_y: float, scale: float): + nonlocal view + view = (center_x, center_y, scale) + # The render itself is CPU-heavy — keep it off the event loop. + frame = await asyncio.to_thread(mandelbrot_frame, center_x, center_y, scale) + await raw_image.render(frame, premultiplied=True) + now = time.monotonic() + frame_times.append(now) + while frame_times and frame_times[0] < now - FPS_WINDOW_SECONDS: + frame_times.popleft() + fps_text.value = f"fps: {len(frame_times) / FPS_WINDOW_SECONDS:.1f}" + zoom_text.value = f"zoom: {HOME[2] / scale:,.0f}x" + page.update() + + async def zoom_to(target_x: float, target_y: float, factor: float): + # A burst of ZOOM_FRAMES awaited renders: exponential interpolation + # of the view towards the target, each frame displayed as soon as + # the client acks the previous one. + start_x, start_y, start_scale = view + for i in range(1, ZOOM_FRAMES + 1): + k = i / ZOOM_FRAMES + f = factor**k + scale = start_scale / f + x = target_x + (start_x - target_x) / f + y = target_y + (start_y - target_y) / f + try: + await show(x, y, scale) + except (RuntimeError, TimeoutError): + return + + def start_zoom(target_x: float, target_y: float, factor: float): + nonlocal zoom_task + if zoom_task is not None and not zoom_task.done(): + return # ignore clicks while a zoom animation is running + zoom_task = asyncio.create_task(zoom_to(target_x, target_y, factor)) + + def tap(e: ft.TapEvent): + if e.local_position is None: + return + # With CONTAIN the frame is centered in the box with letterbox + # bands; undo that mapping to get frame-pixel coordinates. + box_width, box_height = box_size + display_scale = min(box_width / WIDTH, box_height / HEIGHT) + offset_x = (box_width - WIDTH * display_scale) / 2 + offset_y = (box_height - HEIGHT * display_scale) / 2 + frame_x = (e.local_position.x - offset_x) / display_scale + frame_y = (e.local_position.y - offset_y) / display_scale + if not (0 <= frame_x < WIDTH and 0 <= frame_y < HEIGHT): + return # tap landed on a letterbox band + center_x, center_y, scale = view + aspect = HEIGHT / WIDTH + x = center_x + (frame_x / WIDTH * 2 - 1) * scale + y = center_y + (frame_y / HEIGHT * 2 - 1) * scale * aspect + start_zoom(x, y, ZOOM_PER_CLICK) + + def reset(): + nonlocal zoom_task + if zoom_task is not None: + zoom_task.cancel() + zoom_task = None + asyncio.create_task(show(*HOME)) + + page.add( + ft.Row( + [ + ft.OutlinedButton("Reset", on_click=reset), + zoom_text, + fps_text, + hint_text, + ], + spacing=20, + ), + ft.GestureDetector(content=raw_image, on_tap_down=tap, expand=True), + ) + + await show(*HOME) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/raw_image/mandelbrot/pyproject.toml b/sdk/python/examples/controls/core/raw_image/mandelbrot/pyproject.toml new file mode 100644 index 0000000000..4231b286a2 --- /dev/null +++ b/sdk/python/examples/controls/core/raw_image/mandelbrot/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "raw-image-mandelbrot" +version = "1.0.0" +description = "Click-to-zoom Mandelbrot explorer streaming numpy-rendered frames through RawImage." +requires-python = ">=3.10" +keywords = ["raw image", "mandelbrot", "fractal", "zoom", "numpy", "interactive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "numpy"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/RawImage"] + +[tool.flet.metadata] +title = "Mandelbrot explorer" +controls = ["RawImage", "GestureDetector", "Row", "OutlinedButton"] +layout_pattern = "toolbar above canvas" +complexity = "intermediate" +features = ["click-to-zoom animation", "numpy fractal rendering", "background-thread compute", "fps counter"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/raw_image/paint/main.py b/sdk/python/examples/controls/core/raw_image/paint/main.py new file mode 100644 index 0000000000..cd6cdca767 --- /dev/null +++ b/sdk/python/examples/controls/core/raw_image/paint/main.py @@ -0,0 +1,152 @@ +import asyncio + +from PIL import Image, ImageDraw + +import flet as ft + +CANVAS_WIDTH = 700 +CANVAS_HEIGHT = 450 +# ImageDraw has no anti-aliasing: lines and ellipses get hard, jagged +# edges. Painting on a canvas this many times larger and letting the +# client downscale it into the control's box averages each screen pixel +# from SUPERSAMPLE^2 canvas pixels — cheap, GPU-side anti-aliasing. +SUPERSAMPLE = 2 +PALETTE = [ + "#1d1d21", + "#e53935", + "#fb8c00", + "#fdd835", + "#43a047", + "#1e88e5", + "#8e24aa", +] + + +async def main(page: ft.Page): + page.title = "RawImage paint" + + image = Image.new( + "RGBA", (CANVAS_WIDTH * SUPERSAMPLE, CANVAS_HEIGHT * SUPERSAMPLE), "white" + ) + draw = ImageDraw.Draw(image) + + # Frames arrive at SUPERSAMPLE times the control's size; fit=FILL + # scales them down and filter_quality blends the extra pixels away. + raw_image = ft.RawImage( + width=CANVAS_WIDTH, + height=CANVAS_HEIGHT, + fit=ft.BoxFit.FILL, + filter_quality=ft.FilterQuality.MEDIUM, + ) + + brush_color = PALETTE[0] + last_point: tuple[float, float] | None = None # in canvas pixels + + # Pan events arrive faster than frames can be displayed, so handlers + # only mutate the Pillow image and flag it dirty; a single loop below + # streams the latest state as fast as the display confirms frames. + dirty = asyncio.Event() + + def stroke_to(point: ft.Offset): + nonlocal last_point + # Pointer coordinates are in control (logical) pixels; the canvas + # lives at SUPERSAMPLE resolution. + x = point.x * SUPERSAMPLE + y = point.y * SUPERSAMPLE + radius = brush_size_slider.value / 2 * SUPERSAMPLE + if last_point is not None: + draw.line( + (last_point[0], last_point[1], x, y), + fill=brush_color, + width=int(radius * 2), + ) + # Round cap: a line alone leaves flat, jagged joints. + draw.ellipse( + (x - radius, y - radius, x + radius, y + radius), + fill=brush_color, + ) + last_point = (x, y) + dirty.set() + + def pan_start(e: ft.DragStartEvent): + nonlocal last_point + last_point = None + stroke_to(e.local_position) + + def pan_update(e: ft.DragUpdateEvent): + stroke_to(e.local_position) + + def select_color(color: str): + nonlocal brush_color + brush_color = color + for dot in palette_row.controls: + dot.border = ( + ft.Border.all(3, ft.Colors.BLUE_GREY_200) if dot.data == color else None + ) + palette_row.update() + + def clear_canvas(): + draw.rectangle( + (0, 0, CANVAS_WIDTH * SUPERSAMPLE, CANVAS_HEIGHT * SUPERSAMPLE), + fill="white", + ) + dirty.set() + + palette_row = ft.Row( + [ + ft.Container( + width=28, + height=28, + border_radius=14, + bgcolor=color, + data=color, + on_click=lambda e: select_color(e.control.data), + ) + for color in PALETTE + ], + spacing=8, + ) + brush_size_slider = ft.Slider(min=2, max=40, value=8, width=150) + + page.add( + ft.Row( + [ + palette_row, + ft.Text("size:"), + brush_size_slider, + ft.OutlinedButton("Clear", on_click=clear_canvas), + ], + spacing=10, + ), + ft.Container( + content=ft.GestureDetector( + content=raw_image, + on_pan_start=pan_start, + on_pan_update=pan_update, + drag_interval=10, + ), + border=ft.Border.all(1, ft.Colors.BLUE_GREY_200), + width=CANVAS_WIDTH, + height=CANVAS_HEIGHT, + ), + ) + select_color(brush_color) + + async def render_loop(): + while True: + await dirty.wait() + dirty.clear() + try: + # The canvas is opaque, so it is premultiplied by definition. + # Awaiting the render paces this loop to display speed: any + # strokes drawn meanwhile coalesce into the next frame. + await raw_image.render(image, premultiplied=True) + except (RuntimeError, TimeoutError): + return # window closed — session destroyed + + dirty.set() # show the blank canvas + asyncio.create_task(render_loop()) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/raw_image/paint/pyproject.toml b/sdk/python/examples/controls/core/raw_image/paint/pyproject.toml new file mode 100644 index 0000000000..3fba6a7501 --- /dev/null +++ b/sdk/python/examples/controls/core/raw_image/paint/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "raw-image-paint" +version = "1.0.0" +description = "Interactive paint app drawing brush strokes with Pillow and streaming the canvas through RawImage." +requires-python = ">=3.10" +keywords = ["raw image", "paint", "pillow", "drawing", "gesture detector"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "pillow"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/RawImage"] + +[tool.flet.metadata] +title = "Pillow paint" +controls = ["RawImage", "GestureDetector", "Row", "Slider", "Container", "OutlinedButton"] +layout_pattern = "toolbar above canvas" +complexity = "intermediate" +features = ["pillow image streaming", "pan gesture drawing", "color palette", "brush size", "dirty-flag render loop", "supersampled anti-aliasing"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/raw_image/photo_viewer/main.py b/sdk/python/examples/controls/core/raw_image/photo_viewer/main.py new file mode 100644 index 0000000000..2609a5a3ce --- /dev/null +++ b/sdk/python/examples/controls/core/raw_image/photo_viewer/main.py @@ -0,0 +1,59 @@ +import asyncio +import urllib.request + +import flet as ft + +PHOTOS = [ + f"https://picsum.photos/seed/{seed}/800/500.jpg" + for seed in ("flet", "raw", "image", "viewer", "photo") +] + + +async def main(page: ft.Page): + page.title = "RawImage photo viewer" + + raw_image = ft.RawImage(expand=True, fit=ft.BoxFit.CONTAIN) + status_text = ft.Text("", size=12) + + index = 0 + cache: dict[str, bytes] = {} + + async def fetch(url: str) -> bytes: + if url not in cache: + cache[url] = await asyncio.to_thread( + lambda: urllib.request.urlopen(url, timeout=20).read() + ) + return cache[url] + + async def show(i: int): + nonlocal index + index = i % len(PHOTOS) + status_text.value = f"loading {index + 1}/{len(PHOTOS)}…" + page.update() + data = await fetch(PHOTOS[index]) + # render_encoded displays PNG/JPEG/WebP bytes from anywhere: an + # HTTP response like here, a file (Path("photo.jpg").read_bytes()), + # a database blob. The client decodes them with its image codecs. + await raw_image.render_encoded(data) + status_text.value = f"{index + 1}/{len(PHOTOS)} — {len(data) // 1024} KB JPEG" + page.update() + + def go(delta: int): + asyncio.create_task(show(index + delta)) + + page.add( + ft.Row( + [ + ft.IconButton(ft.Icons.CHEVRON_LEFT, on_click=lambda: go(-1)), + ft.IconButton(ft.Icons.CHEVRON_RIGHT, on_click=lambda: go(1)), + status_text, + ], + spacing=10, + ), + raw_image, + ) + await show(0) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/raw_image/photo_viewer/pyproject.toml b/sdk/python/examples/controls/core/raw_image/photo_viewer/pyproject.toml new file mode 100644 index 0000000000..0d70a6cc2a --- /dev/null +++ b/sdk/python/examples/controls/core/raw_image/photo_viewer/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "raw-image-photo-viewer" +version = "1.0.0" +description = "Browses network JPEG photos by pushing the downloaded bytes through RawImage.render_encoded." +requires-python = ">=3.10" +keywords = ["raw image", "photo viewer", "jpeg", "png", "encoded images", "network"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/RawImage"] + +[tool.flet.metadata] +title = "Photo viewer" +controls = ["RawImage", "Row", "IconButton"] +layout_pattern = "toolbar above canvas" +complexity = "basic" +features = ["encoded JPEG rendering", "network image download", "prev/next navigation", "byte cache"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/raw_image/plasma/main.py b/sdk/python/examples/controls/core/raw_image/plasma/main.py new file mode 100644 index 0000000000..cb81a62a4d --- /dev/null +++ b/sdk/python/examples/controls/core/raw_image/plasma/main.py @@ -0,0 +1,113 @@ +import asyncio +import time +from collections import deque + +import numpy as np + +import flet as ft + +FPS_WINDOW_SECONDS = 2.0 + + +def plasma_frame(width: int, height: int, t: float) -> np.ndarray: + """ + Renders a classic demoscene plasma: several drifting sine fields summed + and mapped through a rotating RGB palette. Fully vectorized in numpy. + """ + x = np.linspace(0.0, 3.0 * np.pi, width, dtype=np.float32)[None, :] + y = np.linspace(0.0, 3.0 * np.pi, height, dtype=np.float32)[:, None] + cx = x - 1.5 * np.pi + np.sin(t / 3.0) * np.pi + cy = y - 1.5 * np.pi + np.cos(t / 2.0) * np.pi + v = ( + np.sin(x + t) + + np.sin((y + t) / 2.0) + + np.sin((x + y + t) / 2.0) + + np.sin(np.sqrt(cx * cx + cy * cy + 1.0) + t) + ) / 4.0 + frame = np.empty((height, width, 4), dtype=np.uint8) + frame[..., 0] = np.sin(v * np.pi) * 127 + 128 + frame[..., 1] = np.sin(v * np.pi + 2.0 * np.pi / 3.0) * 127 + 128 + frame[..., 2] = np.sin(v * np.pi + 4.0 * np.pi / 3.0) * 127 + 128 + frame[..., 3] = 255 + return frame + + +async def main(page: ft.Page): + page.title = "RawImage plasma" + page.padding = 0 + + raw_image = ft.RawImage(expand=True, fit=ft.BoxFit.FILL) + + fps_text = ft.Text("fps: —", size=12) + resolution_text = ft.Text("res: —", size=12) + detail_slider = ft.Slider( + min=1, + max=8, + divisions=7, + value=2, + width=200, + label="downscale 1/{value}", + ) + + status_bar = ft.Container( + content=ft.Row( + [fps_text, resolution_text, ft.Text("detail:", size=12), detail_slider], + spacing=20, + ), + padding=ft.Padding.symmetric(horizontal=12, vertical=2), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGH, + ) + + page.add( + ft.SafeArea( + content=ft.Column([raw_image, status_bar], expand=True, spacing=0), + expand=True, + ) + ) + + frame_times: deque[float] = deque() + frame_size = (0, 0) + + async def animate(): + nonlocal frame_size + started = time.monotonic() + while True: + downscale = int(detail_slider.value) + width = max(2, int(page.width or 800) // downscale) + height = max(2, (int(page.height or 600) - 50) // downscale) + frame_size = (width, height) + frame = plasma_frame(width, height, time.monotonic() - started) + try: + # The frame is opaque, so it is premultiplied by definition — + # saying so skips an alpha scan per frame. The await resolves + # when the frame is on screen, pacing the loop to display + # speed. + await raw_image.render(frame, premultiplied=True) + except (RuntimeError, TimeoutError): + return # window closed — session destroyed + now = time.monotonic() + frame_times.append(now) + while frame_times and frame_times[0] < now - FPS_WINDOW_SECONDS: + frame_times.popleft() + + async def refresh_stats(): + # Refresh labels at ~4 Hz instead of once per frame, which would + # thrash the layout. + while True: + now = time.monotonic() + while frame_times and frame_times[0] < now - FPS_WINDOW_SECONDS: + frame_times.popleft() + fps_text.value = f"fps: {len(frame_times) / FPS_WINDOW_SECONDS:.1f}" + resolution_text.value = f"res: {frame_size[0]}x{frame_size[1]}" + try: + page.update() + except RuntimeError: + return + await asyncio.sleep(0.25) + + asyncio.create_task(animate()) + asyncio.create_task(refresh_stats()) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/raw_image/plasma/pyproject.toml b/sdk/python/examples/controls/core/raw_image/plasma/pyproject.toml new file mode 100644 index 0000000000..02c005dd80 --- /dev/null +++ b/sdk/python/examples/controls/core/raw_image/plasma/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "raw-image-plasma" +version = "1.0.0" +description = "Streams a procedurally generated plasma animation through RawImage with a live FPS counter." +requires-python = ">=3.10" +keywords = ["raw image", "plasma", "animation", "streaming", "numpy", "fps"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "numpy"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/RawImage"] + +[tool.flet.metadata] +title = "Plasma animation" +controls = ["RawImage", "SafeArea", "Column", "Row", "Slider"] +layout_pattern = "fullscreen canvas with status bar" +complexity = "intermediate" +features = ["raw frame streaming", "numpy-generated frames", "fps counter", "render resolution slider"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/data_table/sortable_and_selectable/main.py b/sdk/python/examples/controls/material/data_table/sortable_and_selectable/main.py index ba277b0ff2..d2f552d5e7 100644 --- a/sdk/python/examples/controls/material/data_table/sortable_and_selectable/main.py +++ b/sdk/python/examples/controls/material/data_table/sortable_and_selectable/main.py @@ -2,6 +2,7 @@ def main(page: ft.Page): + page.scroll = ft.ScrollMode.AUTO inventory_items = [ {"id": 1, "name": "Alpha", "qty": 4}, {"id": 2, "name": "Bravo", "qty": 9}, diff --git a/sdk/python/examples/cookbook/multiprocessing/cancel_task.py b/sdk/python/examples/cookbook/multiprocessing/cancel_task.py new file mode 100644 index 0000000000..e7c284dbf9 --- /dev/null +++ b/sdk/python/examples/cookbook/multiprocessing/cancel_task.py @@ -0,0 +1,69 @@ +import multiprocessing +import time + +import flet as ft + + +def long_job(seconds: int) -> None: + """Burn CPU for roughly `seconds` seconds. + + Stands in for work you cannot interrupt from Python itself, e.g. a tight + loop inside a C extension library. Runs in a worker process, which is why + it can be cancelled at any point — threads can't be stopped like that. + """ + deadline = time.monotonic() + seconds + while time.monotonic() < deadline: + sum(range(1_000_000)) + + +def main(page: ft.Page): + process = None + + def watch(p: multiprocessing.Process): + """Wait (on a background thread) for the worker to end, then report + whether it finished on its own or was cancelled.""" + p.join() + if p.exitcode == 0: + status.value = "Process finished normally." + else: + # terminate() ends the child with a negative exit code (-SIGTERM). + status.value = f"Process was terminated (exit code {p.exitcode})." + start.disabled = False + cancel.disabled = True + page.update() + + def start_job(): + nonlocal process + process = multiprocessing.Process(target=long_job, args=(30,), daemon=True) + process.start() + status.value = f"Running in process {process.pid}…" + start.disabled = True + cancel.disabled = False + page.update() + page.run_thread(watch, process) + + def cancel_job(): + if process is not None and process.is_alive(): + process.terminate() # threads can't do this + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + controls=[ + start := ft.Button("Start 30s job", on_click=start_job), + cancel := ft.Button( + "Cancel", on_click=cancel_job, disabled=True + ), + ] + ), + status := ft.Text(), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/cookbook/multiprocessing/parallel_sort.py b/sdk/python/examples/cookbook/multiprocessing/parallel_sort.py new file mode 100644 index 0000000000..2a9c8e4fa3 --- /dev/null +++ b/sdk/python/examples/cookbook/multiprocessing/parallel_sort.py @@ -0,0 +1,46 @@ +import random +from concurrent.futures import ProcessPoolExecutor, as_completed + +import flet as ft + + +def sort_chunk(chunk: list[float]) -> list[float]: + """Sort one chunk of data.""" + return sorted(chunk) + + +def main(page: ft.Page): + def run_sort(): + """Orchestrate the pool from a background thread, updating the UI + from the main process as results come in.""" + chunks = [[random.random() for _ in range(250_000)] for _ in range(8)] + completed = 0 + # Without max_workers, the pool sizes itself to the machine's CPUs. + with ProcessPoolExecutor() as pool: + futures = [pool.submit(sort_chunk, c) for c in chunks] + # as_completed() yields each future as soon as its worker is done. + for _ in as_completed(futures): + completed += 1 + progress.value = completed / len(futures) + status.value = f"Sorted {completed}/{len(futures)} chunks" + page.update() + status.value = "Done!" + page.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + "Start sorting", on_click=lambda: page.run_thread(run_sort) + ), + status := ft.Text("Idle"), + progress := ft.ProgressBar(value=0, width=300), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/cookbook/multiprocessing/persistent_worker.py b/sdk/python/examples/cookbook/multiprocessing/persistent_worker.py new file mode 100644 index 0000000000..3531c832c1 --- /dev/null +++ b/sdk/python/examples/cookbook/multiprocessing/persistent_worker.py @@ -0,0 +1,65 @@ +import multiprocessing +import time + +import flet as ft + + +def calc_worker(conn) -> None: + """Serve calculation jobs over the pipe until told to stop. + + Runs in a worker process that stays alive across jobs, so the process + startup cost is paid once. Expensive setup (loading models, opening + datasets, warming caches) could be done once here, before the loop, + and reused by every job. Receiving `None` is the shutdown signal. + """ + while (job := conn.recv()) is not None: + started = time.perf_counter() + result = sum(i * i for i in range(job)) + conn.send((result, time.perf_counter() - started)) + conn.close() + + +def main(page: ft.Page): + # One end of the pipe goes to the worker, the other stays with the UI. + parent_conn, child_conn = multiprocessing.Pipe() + worker = multiprocessing.Process( + target=calc_worker, args=(child_conn,), daemon=True + ) + worker.start() + + def submit(): + # One job in flight at a time: the button stays disabled until the + # worker replies (a bare Pipe is not multiplexed). + button.disabled = True + status.value = "Working…" + page.update() + page.run_thread(request) + + def request(): + """Send a job to the worker and wait for its reply. + + Should be run on a background thread: conn.recv() blocks until the worker + answers, so it must stay off the UI event loop. + """ + parent_conn.send(100_000_000) + result, duration = parent_conn.recv() + status.value = ( + f"sum of squares = {result}\n{duration:.2f}s in process {worker.pid}" + ) + button.disabled = False + page.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + button := ft.Button("Compute in worker", on_click=submit), + status := ft.Text(f"Worker ready (pid {worker.pid})"), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/cookbook/multiprocessing/worker_progress.py b/sdk/python/examples/cookbook/multiprocessing/worker_progress.py new file mode 100644 index 0000000000..bc89d0158d --- /dev/null +++ b/sdk/python/examples/cookbook/multiprocessing/worker_progress.py @@ -0,0 +1,58 @@ +import multiprocessing + +import flet as ft + + +def crunch(progress_queue: multiprocessing.Queue, steps: int) -> None: + """Do `steps` slices of CPU-heavy work, reporting progress after each one. + + Runs in a worker process, which has no access to the page — the queue is + the only channel back to the UI. Values are fractions 0..1; a final `None` + tells the consumer there is nothing more to read. + """ + for i in range(steps): + sum(range(50_000_000)) # one slice of real work + progress_queue.put((i + 1) / steps) + progress_queue.put(None) # sentinel: no more updates + + +def main(page: ft.Page): + def start(): + button.disabled = True + status.value = "Starting worker…" + page.update() + queue = multiprocessing.Queue() + worker = multiprocessing.Process(target=crunch, args=(queue, 20), daemon=True) + worker.start() + page.run_thread(drain, queue, worker) + + def drain(queue: multiprocessing.Queue, worker: multiprocessing.Process): + """Forward the worker's progress reports to the UI. + + Runs on a background thread: queue.get() blocks until the worker + reports again, so it must stay off the UI event loop. + """ + while (value := queue.get()) is not None: + progress.value = value + status.value = f"Crunching… {value:.0%}" + page.update() + worker.join() + status.value = "Done!" + button.disabled = False + page.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + button := ft.Button("Start", on_click=start), + progress := ft.ProgressBar(value=0, width=300), + status := ft.Text(), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/ads/banner_ad_and_interstitial_ad/pyproject.toml b/sdk/python/examples/extensions/ads/banner_ad_and_interstitial_ad/pyproject.toml index fe07d0a166..6aef403a67 100644 --- a/sdk/python/examples/extensions/ads/banner_ad_and_interstitial_ad/pyproject.toml +++ b/sdk/python/examples/extensions/ads/banner_ad_and_interstitial_ad/pyproject.toml @@ -25,3 +25,10 @@ platforms = ["ios", "android"] org = "dev.flet" company = "Flet" copyright = "Copyright (C) 2023-2026 by Flet" + +# AdMob test app ID — replace with your own for production. +[tool.flet.android.meta_data] +"com.google.android.gms.ads.APPLICATION_ID" = "ca-app-pub-3940256099942544~3347511713" + +[tool.flet.ios.info] +GADApplicationIdentifier = "ca-app-pub-3940256099942544~3347511713" diff --git a/sdk/python/examples/extensions/ads/consent/main.py b/sdk/python/examples/extensions/ads/consent/main.py new file mode 100644 index 0000000000..f1d188a6ba --- /dev/null +++ b/sdk/python/examples/extensions/ads/consent/main.py @@ -0,0 +1,102 @@ +import flet as ft +import flet_ads as fta + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + # mobile-only + supported = not page.web and page.platform.is_mobile() + if supported: + page.services.append(consent_manager := fta.ConsentManager()) + + async def refresh_status(): + consent_status = await consent_manager.get_consent_status() + privacy_status = await consent_manager.get_privacy_options_requirement_status() + can_request = await consent_manager.can_request_ads() + status.value = ( + f"Consent status: {consent_status.name}\n" + f"Privacy options required: {privacy_status.name}\n" + f"Can request ads: {can_request}" + ) + # Only surface the privacy options entry point when we are required to. + privacy_button.visible = ( + privacy_status == fta.PrivacyOptionsRequirementStatus.REQUIRED + ) + page.update() + + async def gather_consent(e: ft.Event[ft.OutlinedButton]): + status.value = "Gathering consent…" + status.update() + try: + # Remember to remove the debug settings in production. + await consent_manager.request_consent_info_update( + fta.ConsentRequestParameters( + consent_debug_settings=fta.ConsentDebugSettings( + debug_geography=fta.DebugGeography.EEA, + # test_identifiers=[""], # for physical devices only + ), + ) + ) + # Loads and shows the consent form only if consent is required. + await consent_manager.load_and_show_consent_form_if_required() + await refresh_status() + # At this point, if `can_request_ads()` is True, it is safe to start + # loading ads (e.g. fta.BannerAd / fta.InterstitialAd). + except Exception as ex: + status.value = f"Error: {ex}" + status.update() + + async def show_privacy_options(e: ft.Event[ft.OutlinedButton]): + try: + await consent_manager.show_privacy_options_form() + await refresh_status() + except Exception as ex: + status.value = f"Error: {ex}" + page.update() + + async def reset_consent(e: ft.Event[ft.OutlinedButton]): + # For testing only: resets consent so you can replay the flow. + try: + await consent_manager.reset() + status.value = 'Consent reset. Tap "Gather consent" to begin again.' + privacy_button.visible = False + except Exception as ex: + status.value = f"Error: {ex}" + page.update() + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text( + "Gather user consent (e.g. GDPR/EEA) with Google's User " + "Messaging Platform before requesting ads.", + text_align=ft.TextAlign.CENTER, + ), + ft.OutlinedButton( + content="Gather consent", + on_click=gather_consent, + disabled=not supported, + ), + privacy_button := ft.OutlinedButton( + content="Show privacy options form", + visible=False, + on_click=show_privacy_options, + ), + ft.OutlinedButton( + content="Reset consent (testing)", + on_click=reset_consent, + disabled=not supported, + ), + ft.Divider(), + status := ft.Text('Tap "Gather consent" to begin.'), + ], + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/ads/consent/pyproject.toml b/sdk/python/examples/extensions/ads/consent/pyproject.toml new file mode 100644 index 0000000000..f8f07d63aa --- /dev/null +++ b/sdk/python/examples/extensions/ads/consent/pyproject.toml @@ -0,0 +1,34 @@ +[project] +name = "ads-consent" +version = "1.0.0" +description = "Gather user consent for ads with Google's User Messaging Platform (UMP)." +requires-python = ">=3.10" +keywords = ["ads", "consent", "ump", "gdpr", "admob", "mobile", "privacy"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-ads"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Marketing/Ads"] + +[tool.flet.metadata] +title = "AdMob Consent (UMP)" +controls = ["SafeArea", "Column", "OutlinedButton", "Text", "Divider", "ConsentManager"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["consent gathering", "consent form", "privacy options form", "consent status"] + +[tool.flet] +platforms = ["ios", "android"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" + +# AdMob test app ID — replace with your own for production. +[tool.flet.android.meta_data] +"com.google.android.gms.ads.APPLICATION_ID" = "ca-app-pub-3940256099942544~3347511713" + +[tool.flet.ios.info] +GADApplicationIdentifier = "ca-app-pub-3940256099942544~3347511713" diff --git a/sdk/python/examples/extensions/charts/bar_chart/bar_chart_with_hover/main.py b/sdk/python/examples/extensions/charts/bar_chart/bar_chart_with_hover/main.py index c03f535fd5..6ac92d3050 100644 --- a/sdk/python/examples/extensions/charts/bar_chart/bar_chart_with_hover/main.py +++ b/sdk/python/examples/extensions/charts/bar_chart/bar_chart_with_hover/main.py @@ -60,6 +60,7 @@ def on_chart_event(e: fch.BarChartEvent): page.add( ft.SafeArea( + expand=True, content=ft.Container( bgcolor=ft.Colors.GREEN_200, padding=10, diff --git a/sdk/python/examples/extensions/charts/bar_chart/interactive_bar_chart/main.py b/sdk/python/examples/extensions/charts/bar_chart/interactive_bar_chart/main.py index 36955504a3..700dc72e22 100644 --- a/sdk/python/examples/extensions/charts/bar_chart/interactive_bar_chart/main.py +++ b/sdk/python/examples/extensions/charts/bar_chart/interactive_bar_chart/main.py @@ -5,6 +5,7 @@ def main(page: ft.Page): page.add( ft.SafeArea( + expand=True, content=fch.BarChart( expand=True, interactive=True, diff --git a/sdk/python/examples/extensions/charts/candlestick_chart/candlestick_chart/main.py b/sdk/python/examples/extensions/charts/candlestick_chart/candlestick_chart/main.py index 342be7df31..72dc148c6f 100644 --- a/sdk/python/examples/extensions/charts/candlestick_chart/candlestick_chart/main.py +++ b/sdk/python/examples/extensions/charts/candlestick_chart/candlestick_chart/main.py @@ -104,6 +104,7 @@ def handle_event(e: fch.CandlestickChartEvent): page.add( ft.SafeArea( + expand=True, content=ft.Container( expand=True, border_radius=16, diff --git a/sdk/python/examples/extensions/charts/line_chart/line_chart_with_custom_axes/main.py b/sdk/python/examples/extensions/charts/line_chart/line_chart_with_custom_axes/main.py index e4dffef422..839d384228 100644 --- a/sdk/python/examples/extensions/charts/line_chart/line_chart_with_custom_axes/main.py +++ b/sdk/python/examples/extensions/charts/line_chart/line_chart_with_custom_axes/main.py @@ -135,11 +135,13 @@ def toggle_data(e: ft.Event[ft.ElevatedButton]): page.add( ft.SafeArea( + expand=True, content=ft.Column( + expand=True, controls=[ ft.Button("avg", on_click=toggle_data), chart, - ] + ], ), ) ) diff --git a/sdk/python/examples/extensions/charts/line_chart/multi_series_line_chart/main.py b/sdk/python/examples/extensions/charts/line_chart/multi_series_line_chart/main.py index 5721e35204..9a03f598df 100644 --- a/sdk/python/examples/extensions/charts/line_chart/multi_series_line_chart/main.py +++ b/sdk/python/examples/extensions/charts/line_chart/multi_series_line_chart/main.py @@ -201,11 +201,13 @@ def toggle_data(e: ft.Event[ft.IconButton]): page.add( ft.SafeArea( + expand=True, content=ft.Column( + expand=True, controls=[ ft.IconButton(ft.Icons.REFRESH, on_click=toggle_data), chart, - ] + ], ), ) ) diff --git a/sdk/python/examples/extensions/charts/matplotlib_chart/three_d/main.py b/sdk/python/examples/extensions/charts/matplotlib_chart/three_d/main.py index 9cc1c2084d..88559b6bce 100644 --- a/sdk/python/examples/extensions/charts/matplotlib_chart/three_d/main.py +++ b/sdk/python/examples/extensions/charts/matplotlib_chart/three_d/main.py @@ -1,4 +1,8 @@ +import asyncio import logging +import time +from collections import deque +from dataclasses import dataclass import matplotlib.pyplot as plt @@ -8,7 +12,147 @@ logging.basicConfig(level=logging.INFO) -def main(page: ft.Page): +@dataclass +class _Frame: + t: float + size: int + + +class FrameStats: + """Rolling counters for the matplotlib WebAgg-style frame stream. + + Cumulative averages for per-frame size + total bytes (lifetime of the + run); a short sliding window for transfer speed and FPS so the bar + reflects current activity rather than being dragged down by idle time. + + Latency split (also sliding-window): + + * `dart_ms` — time from a frame leaving Python (`apply_full/diff` call) + to Dart's `[0xFF]` ack arriving. This is Dart-side decode + paint + + ack transit. Transit is microseconds, so essentially decode + paint. + * `mpl_ms` — time from one ack arriving to the next frame leaving + Python. Combines matplotlib's render of the next frame and any + idle time waiting for matplotlib to react to the next "draw" + request. Under sustained interactive load (continuous dragging) + idle ≈ 0 and this is dominated by matplotlib's render cost. + """ + + WINDOW_SECONDS = 2.0 + + def __init__(self) -> None: + self.full_count = 0 + self.full_total = 0 + self.diff_count = 0 + self.diff_total = 0 + self.raw_count = 0 + self.raw_total = 0 + self.bytes_total = 0 + self._recent: deque[_Frame] = deque() + # Latency tracking: each entry is (timestamp_when_observed, latency_seconds). + self._dart_latencies: deque[tuple[float, float]] = deque() + self._mpl_gaps: deque[tuple[float, float]] = deque() + # In-flight bookkeeping for pairing send with ack. + self._inflight_send_ts: float | None = None + self._last_ack_ts: float | None = None + + def record_send(self, size: int, kind: str) -> None: + """Frame about to leave Python — record size and mark in-flight. + + `kind` is "raw" (uncompressed RGBA full frame, local transports), + "full" or "diff" (PNG frames, remote transports). + """ + now = time.monotonic() + if kind == "raw": + self.raw_count += 1 + self.raw_total += size + elif kind == "full": + self.full_count += 1 + self.full_total += size + else: + self.diff_count += 1 + self.diff_total += size + self.bytes_total += size + self._recent.append(_Frame(now, size)) + self._evict(now) + # mpl-side gap: how long since the previous ack. + if self._last_ack_ts is not None: + self._mpl_gaps.append((now, now - self._last_ack_ts)) + self._evict_latency_window(self._mpl_gaps, now) + self._inflight_send_ts = now + + def record_ack(self) -> None: + """Dart confirms the frame painted — close the dart-side timing.""" + now = time.monotonic() + if self._inflight_send_ts is not None: + self._dart_latencies.append((now, now - self._inflight_send_ts)) + self._evict_latency_window(self._dart_latencies, now) + self._inflight_send_ts = None + self._last_ack_ts = now + + def _evict(self, now: float) -> None: + cutoff = now - self.WINDOW_SECONDS + while self._recent and self._recent[0].t < cutoff: + self._recent.popleft() + + def _evict_latency_window( + self, window: deque[tuple[float, float]], now: float + ) -> None: + cutoff = now - self.WINDOW_SECONDS + while window and window[0][0] < cutoff: + window.popleft() + + @property + def avg_full(self) -> float: + return self.full_total / self.full_count if self.full_count else 0.0 + + @property + def avg_diff(self) -> float: + return self.diff_total / self.diff_count if self.diff_count else 0.0 + + @property + def avg_raw(self) -> float: + return self.raw_total / self.raw_count if self.raw_count else 0.0 + + def speed_and_fps(self) -> tuple[float, float]: + now = time.monotonic() + self._evict(now) + if not self._recent: + return 0.0, 0.0 + span = max(self.WINDOW_SECONDS, now - self._recent[0].t) + speed = sum(f.size for f in self._recent) / span + fps = len(self._recent) / span + return speed, fps + + def dart_avg_ms(self) -> float: + now = time.monotonic() + self._evict_latency_window(self._dart_latencies, now) + if not self._dart_latencies: + return 0.0 + return ( + 1000.0 + * sum(lat for _, lat in self._dart_latencies) + / len(self._dart_latencies) + ) + + def mpl_avg_ms(self) -> float: + now = time.monotonic() + self._evict_latency_window(self._mpl_gaps, now) + if not self._mpl_gaps: + return 0.0 + return 1000.0 * sum(g for _, g in self._mpl_gaps) / len(self._mpl_gaps) + + +def _human_bytes(n: float) -> str: + if n < 1024: + return f"{n:.0f} B" + if n < 1024 * 1024: + return f"{n / 1024:.1f} KB" + if n < 1024**3: + return f"{n / (1024 * 1024):.1f} MB" + return f"{n / (1024**3):.2f} GB" + + +async def main(page: ft.Page): from mpl_toolkits.mplot3d import axes3d fig = plt.figure() @@ -36,13 +180,111 @@ def main(page: ft.Page): zlabel="Z", ) + chart = flet_charts.MatplotlibChartWithToolbar(figure=fig, expand=True) + + # Status bar: regular Flet Text controls in a Row at the bottom. + avg_raw_text = ft.Text("avg raw: —", size=12) + avg_full_text = ft.Text("avg full: —", size=12) + avg_diff_text = ft.Text("avg diff: —", size=12) + total_text = ft.Text("total: —", size=12) + speed_text = ft.Text("speed: —", size=12) + fps_text = ft.Text("fps: —", size=12) + dart_text = ft.Text("dart: —", size=12) + mpl_text = ft.Text("mpl: —", size=12) + + status_bar = ft.Container( + content=ft.Row( + [ + avg_raw_text, + avg_full_text, + avg_diff_text, + total_text, + speed_text, + fps_text, + dart_text, + mpl_text, + ], + spacing=20, + # Scroll instead of overflowing when the window is narrower + # than the full set of counters. + scroll=ft.ScrollMode.HIDDEN, + ), + padding=ft.Padding.symmetric(horizontal=12, vertical=6), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGH, + ) + page.add( ft.SafeArea( - content=flet_charts.MatplotlibChartWithToolbar(figure=fig, expand=True), + content=ft.Column( + [chart, status_bar], + expand=True, + spacing=0, + ), expand=True, ) ) + stats = FrameStats() + + # Instrument the canvas to capture per-frame sizes + latency. Both + # `chart.mpl` and `chart.mpl.mpl_canvas` are populated by their + # respective `build()` calls, which run only after the control is + # mounted — hence this wrapping has to happen after `page.add(...)`. + canvas = chart.mpl.mpl_canvas + orig_full = canvas.apply_full + orig_diff = canvas.apply_diff + orig_raw = canvas.apply_raw_packet + + async def apply_full(image_bytes: bytes) -> None: + stats.record_send(len(image_bytes), kind="full") + await orig_full(image_bytes) + + async def apply_diff(image_bytes: bytes) -> None: + stats.record_send(len(image_bytes), kind="diff") + await orig_diff(image_bytes) + + async def apply_raw_packet(packet: bytes) -> None: + stats.record_send(len(packet), kind="raw") + await orig_raw(packet) + + canvas.apply_full = apply_full + canvas.apply_diff = apply_diff + canvas.apply_raw_packet = apply_raw_packet + + # Register an observer for frame-applied acks so we can record the + # Dart-side timing. Pure observation — backpressure is handled by + # the apply_*/await pattern in `MatplotlibChart._receive_loop`. + canvas.set_on_frame_applied(stats.record_ack) + + # Background task: refresh the labels at ~4 Hz so speed/fps decay + # visibly when traffic stops and stay readable during fast drags + # (vs. updating once per frame, which thrashes the layout). + async def refresh_loop() -> None: + while True: + speed, fps = stats.speed_and_fps() + avg_raw_text.value = ( + f"avg raw: {_human_bytes(stats.avg_raw)} (n={stats.raw_count})" + ) + avg_full_text.value = ( + f"avg full: {_human_bytes(stats.avg_full)} (n={stats.full_count})" + ) + avg_diff_text.value = ( + f"avg diff: {_human_bytes(stats.avg_diff)} (n={stats.diff_count})" + ) + total_text.value = f"total: {_human_bytes(stats.bytes_total)}" + speed_text.value = f"speed: {_human_bytes(speed)}/s" + fps_text.value = f"fps: {fps:.1f}" + dart_text.value = f"dart: {stats.dart_avg_ms():.1f} ms" + mpl_text.value = f"mpl: {stats.mpl_avg_ms():.1f} ms" + try: + page.update() + except RuntimeError: + # Window closed — session destroyed; stop refreshing. + return + await asyncio.sleep(0.25) + + asyncio.create_task(refresh_loop()) + if __name__ == "__main__": ft.run(main) diff --git a/sdk/python/examples/extensions/charts/pie_chart/pie_chart_with_hover_borders/main.py b/sdk/python/examples/extensions/charts/pie_chart/pie_chart_with_hover_borders/main.py index dd909aa49b..46e5c9205b 100644 --- a/sdk/python/examples/extensions/charts/pie_chart/pie_chart_with_hover_borders/main.py +++ b/sdk/python/examples/extensions/charts/pie_chart/pie_chart_with_hover_borders/main.py @@ -46,7 +46,7 @@ def on_chart_event(e: fch.PieChartEvent): ], ) - page.add(ft.SafeArea(content=chart)) + page.add(ft.SafeArea(expand=True, content=chart)) if __name__ == "__main__": diff --git a/sdk/python/examples/extensions/charts/pie_chart/pie_chart_with_hover_sections/main.py b/sdk/python/examples/extensions/charts/pie_chart/pie_chart_with_hover_sections/main.py index fc58e9be39..10f2ee1925 100644 --- a/sdk/python/examples/extensions/charts/pie_chart/pie_chart_with_hover_sections/main.py +++ b/sdk/python/examples/extensions/charts/pie_chart/pie_chart_with_hover_sections/main.py @@ -62,7 +62,7 @@ def on_chart_event(e: fch.PieChartEvent): ], ) - page.add(ft.SafeArea(content=chart)) + page.add(ft.SafeArea(expand=True, content=chart)) if __name__ == "__main__": diff --git a/sdk/python/examples/extensions/charts/pie_chart/pie_chart_with_icon_badges/main.py b/sdk/python/examples/extensions/charts/pie_chart/pie_chart_with_icon_badges/main.py index 6f4c0b204c..fe39027f3f 100644 --- a/sdk/python/examples/extensions/charts/pie_chart/pie_chart_with_icon_badges/main.py +++ b/sdk/python/examples/extensions/charts/pie_chart/pie_chart_with_icon_badges/main.py @@ -84,7 +84,7 @@ def on_chart_event(e: fch.PieChartEvent): ], ) - page.add(ft.SafeArea(content=chart)) + page.add(ft.SafeArea(expand=True, content=chart)) if __name__ == "__main__": diff --git a/sdk/python/examples/extensions/charts/plotly_chart/plotly_bar_chart/main.py b/sdk/python/examples/extensions/charts/plotly_chart/plotly_bar_chart/main.py index 663b3c9099..2da37114c6 100644 --- a/sdk/python/examples/extensions/charts/plotly_chart/plotly_bar_chart/main.py +++ b/sdk/python/examples/extensions/charts/plotly_chart/plotly_bar_chart/main.py @@ -16,7 +16,7 @@ def main(page: ft.Page): height=400, ) - page.add(ft.SafeArea(content=fch.PlotlyChart(figure=fig, expand=True))) + page.add(ft.SafeArea(expand=True, content=fch.PlotlyChart(figure=fig, expand=True))) if __name__ == "__main__": diff --git a/sdk/python/examples/extensions/charts/plotly_chart/plotly_box_plot/main.py b/sdk/python/examples/extensions/charts/plotly_chart/plotly_box_plot/main.py index 9f50698e45..d30e24c0fd 100644 --- a/sdk/python/examples/extensions/charts/plotly_chart/plotly_box_plot/main.py +++ b/sdk/python/examples/extensions/charts/plotly_chart/plotly_box_plot/main.py @@ -52,7 +52,7 @@ def main(page: ft.Page): boxmode="group", # group together boxes of the different traces ) - page.add(ft.SafeArea(content=fch.PlotlyChart(figure=fig, expand=True))) + page.add(ft.SafeArea(expand=True, content=fch.PlotlyChart(figure=fig, expand=True))) if __name__ == "__main__": diff --git a/sdk/python/examples/extensions/charts/plotly_chart/plotly_line_chart/main.py b/sdk/python/examples/extensions/charts/plotly_chart/plotly_line_chart/main.py index 2354419df0..f7ad8306eb 100644 --- a/sdk/python/examples/extensions/charts/plotly_chart/plotly_line_chart/main.py +++ b/sdk/python/examples/extensions/charts/plotly_chart/plotly_line_chart/main.py @@ -8,7 +8,7 @@ def main(page: ft.Page): df = px.data.gapminder().query("continent=='Oceania'") fig = px.line(df, x="year", y="lifeExp", color="country") - page.add(ft.SafeArea(content=fch.PlotlyChart(figure=fig, expand=True))) + page.add(ft.SafeArea(expand=True, content=fch.PlotlyChart(figure=fig, expand=True))) if __name__ == "__main__": diff --git a/sdk/python/examples/extensions/charts/plotly_chart/plotly_pie_chart/main.py b/sdk/python/examples/extensions/charts/plotly_chart/plotly_pie_chart/main.py index 0f28b067fd..87dfad6bb6 100644 --- a/sdk/python/examples/extensions/charts/plotly_chart/plotly_pie_chart/main.py +++ b/sdk/python/examples/extensions/charts/plotly_chart/plotly_pie_chart/main.py @@ -10,7 +10,7 @@ def main(page: ft.Page): fig = go.Figure(data=[go.Pie(labels=labels, values=values)]) - page.add(ft.SafeArea(content=fch.PlotlyChart(figure=fig, expand=True))) + page.add(ft.SafeArea(expand=True, content=fch.PlotlyChart(figure=fig, expand=True))) if __name__ == "__main__": diff --git a/sdk/python/examples/extensions/charts/radar_chart/radar_chart/main.py b/sdk/python/examples/extensions/charts/radar_chart/radar_chart/main.py index 4cefb9815a..867fa7b5e4 100644 --- a/sdk/python/examples/extensions/charts/radar_chart/radar_chart/main.py +++ b/sdk/python/examples/extensions/charts/radar_chart/radar_chart/main.py @@ -12,6 +12,7 @@ def main(page: ft.Page): page.add( ft.SafeArea( + expand=True, content=fch.RadarChart( expand=True, titles=[fch.RadarChartTitle(text=label) for label in categories], diff --git a/sdk/python/examples/extensions/charts/scatter_chart/scatter_chart/main.py b/sdk/python/examples/extensions/charts/scatter_chart/scatter_chart/main.py index 8b6faa3d45..27d3e5c5e1 100644 --- a/sdk/python/examples/extensions/charts/scatter_chart/scatter_chart/main.py +++ b/sdk/python/examples/extensions/charts/scatter_chart/scatter_chart/main.py @@ -133,7 +133,9 @@ def handle_event(e: fch.ScatterChartEvent): page.add( ft.SafeArea( + expand=True, content=ft.Column( + expand=True, controls=[ ft.Text( "Tap on the chart to toggle between random spots and Flutter " diff --git a/sdk/python/examples/extensions/spinkit/spinkit_showcase/pyproject.toml b/sdk/python/examples/extensions/spinkit/spinkit_showcase/pyproject.toml index caaf23184f..62c8fcb88c 100644 --- a/sdk/python/examples/extensions/spinkit/spinkit_showcase/pyproject.toml +++ b/sdk/python/examples/extensions/spinkit/spinkit_showcase/pyproject.toml @@ -31,3 +31,18 @@ features = ["spinner grid", "color selection", "size slider", "all 31 spinner ty org = "dev.flet" company = "Flet" copyright = "Copyright (C) 2023-2026 by Flet" + +# Animated SpinKit boot screen, shown while the packaged app starts up. +# Provided by the flet-spinkit extension (see its src/flutter/.../boot_screen.dart). +[tool.flet.boot_screen] +name = "spinkit" + +[tool.flet.boot_screen.spinkit] +spinner = "WanderingCubes" +spinner_color_light = "#7c4dff" +spinner_color_dark = "#b388ff" +spinner_size = 60 +bgcolor_light = "#ffffff" +bgcolor_dark = "#0d0d12" +prepare_message = "Preparing your app…" +startup_message = "Starting up…" diff --git a/sdk/python/examples/gallery.yaml b/sdk/python/examples/gallery.yaml index 85881d3d51..8b5319b061 100644 --- a/sdk/python/examples/gallery.yaml +++ b/sdk/python/examples/gallery.yaml @@ -106,6 +106,7 @@ categories: Markdown: ProgressBar: ProgressRing: + RawImage: Text: Tooltip: WebView: diff --git a/sdk/python/packages/flet-ads/CHANGELOG.md b/sdk/python/packages/flet-ads/CHANGELOG.md index f555bfce12..fb4f3dbd3b 100644 --- a/sdk/python/packages/flet-ads/CHANGELOG.md +++ b/sdk/python/packages/flet-ads/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## 0.86.0 + +### Added + +- New `ConsentManager` service for gathering and managing user consent for ads (e.g. GDPR/EEA) via Google's User Messaging Platform (UMP): request consent updates, present the consent and privacy options forms, and read the consent status before requesting ads ([#6569](https://github.com/flet-dev/flet/issues/6569), [#6615](https://github.com/flet-dev/flet/pull/6615)) by @ndonkoHenri. + ## 0.82.0 ### Changed diff --git a/sdk/python/packages/flet-ads/src/flet_ads/__init__.py b/sdk/python/packages/flet-ads/src/flet_ads/__init__.py index 03bf87a29e..cdfb359e87 100644 --- a/sdk/python/packages/flet-ads/src/flet_ads/__init__.py +++ b/sdk/python/packages/flet-ads/src/flet_ads/__init__.py @@ -1,17 +1,29 @@ from flet_ads.banner_ad import BannerAd from flet_ads.base_ad import BaseAd +from flet_ads.consent_manager import ConsentManager from flet_ads.interstitial_ad import InterstitialAd from flet_ads.types import ( AdRequest, + ConsentDebugSettings, + ConsentRequestParameters, + ConsentStatus, + DebugGeography, PaidAdEvent, PrecisionType, + PrivacyOptionsRequirementStatus, ) __all__ = [ "AdRequest", "BannerAd", "BaseAd", + "ConsentDebugSettings", + "ConsentManager", + "ConsentRequestParameters", + "ConsentStatus", + "DebugGeography", "InterstitialAd", "PaidAdEvent", "PrecisionType", + "PrivacyOptionsRequirementStatus", ] diff --git a/sdk/python/packages/flet-ads/src/flet_ads/base_ad.py b/sdk/python/packages/flet-ads/src/flet_ads/base_ad.py index 1f2d1a5137..f64da9d242 100644 --- a/sdk/python/packages/flet-ads/src/flet_ads/base_ad.py +++ b/sdk/python/packages/flet-ads/src/flet_ads/base_ad.py @@ -66,7 +66,8 @@ class BaseAd(ft.BaseControl): Called when this ad is clicked. """ - def before_update(self): + def init(self): + super().init() if self.page.web or not self.page.platform.is_mobile(): raise ft.FletUnsupportedPlatformException( f"{self.__class__.__name__} is only supported on " diff --git a/sdk/python/packages/flet-ads/src/flet_ads/consent_manager.py b/sdk/python/packages/flet-ads/src/flet_ads/consent_manager.py new file mode 100644 index 0000000000..e7e7208e93 --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flet_ads/consent_manager.py @@ -0,0 +1,136 @@ +from typing import Optional + +import flet as ft +from flet_ads.types import ( + ConsentRequestParameters, + ConsentStatus, + PrivacyOptionsRequirementStatus, +) + +__all__ = ["ConsentManager"] + + +@ft.control("ConsentManager") +class ConsentManager(ft.Service): + """ + Gathers and manages user consent for ads using + Google's User Messaging Platform (UMP). + + Use this service to request consent information, present the consent form + (for example, the GDPR/EEA consent dialog) and the privacy options form, + and query the consent status before requesting ads. + + A typical flow looks like this: + + 1. :meth:`request_consent_info_update` (at every app launch); + 2. :meth:`load_and_show_consent_form_if_required` (shows the form only if needed); + 3. :meth:`can_request_ads` (to decide whether to start loading ads). + + More info in the [AdMob documentation](https://developers.google.com/admob/flutter/privacy). + + Raises: + FletUnsupportedPlatformException: When any of its methods are called on + a web and/or non-mobile platform. + """ # noqa: E501 + + def init(self): + super().init() + if self.page.web or not self.page.platform.is_mobile(): + raise ft.FletUnsupportedPlatformException( + f"{self.__class__.__name__} is only supported on " + f"Mobile (Android and iOS)" + ) + + async def request_consent_info_update( + self, params: Optional[ConsentRequestParameters] = None + ): + """ + Requests an update of the user's consent information. + + This should be called (and awaited) at every app launch, before + loading/showing a consent form or reading the consent status. + + Args: + params: Parameters such as debug settings (useful for + testing the form during development) or the under-age tag. + If `None`, default parameters are used. + """ + await self._invoke_method("request_consent_info_update", {"params": params}) + + async def is_consent_form_available(self) -> bool: + """ + Checks whether a consent form is available to be loaded and shown. + + Note: + :meth:`request_consent_info_update` should be awaited before calling + this method. + + Returns: + `True` if a consent form is available, `False` otherwise. + """ + return await self._invoke_method("is_consent_form_available") + + async def get_consent_status(self) -> ConsentStatus: + """ + Get the user’s consent status. + + This value is cached between app sessions and can be read before + requesting an update of the consent information. + + Returns: + The user's current consent status. + """ + return ConsentStatus(await self._invoke_method("get_consent_status")) + + async def can_request_ads(self) -> bool: + """ + Indicates whether the app has gathered enough consent to request ads. + + Returns: + `True` if ads can be requested, `False` otherwise. + """ + return bool(await self._invoke_method("can_request_ads")) + + async def get_privacy_options_requirement_status( + self, + ) -> PrivacyOptionsRequirementStatus: + """ + Gets the requirement status for showing a privacy options entry point. + + Returns: + Whether a privacy options entry point (for example, a button + that calls :meth:`show_privacy_options_form`) is required. + """ + return PrivacyOptionsRequirementStatus( + await self._invoke_method("get_privacy_options_requirement_status") + ) + + async def load_and_show_consent_form_if_required(self): + """ + Loads a consent form and immediately shows it if consent is required. + + If consent is not required, this method completes without showing + anything. This is the simplest way to gather consent: call + :meth:`request_consent_info_update` first, then this method. + """ + await self._invoke_method("load_and_show_consent_form_if_required") + + async def show_privacy_options_form(self): + """ + Presents the privacy options form to the user. + + This lets users change or withdraw their consent after the initial + choice. Only present it when :meth:`get_privacy_options_requirement_status` + returns :attr:`flet_ads.PrivacyOptionsRequirementStatus.REQUIRED`. + """ + await self._invoke_method("show_privacy_options_form") + + async def reset(self): + """ + Resets the consent state. + + Warning: + This is intended only for testing, allowing you to simulate a first-time + user. It should not be used in production. + """ + await self._invoke_method("reset") diff --git a/sdk/python/packages/flet-ads/src/flet_ads/native_ad.py b/sdk/python/packages/flet-ads/src/flet_ads/native_ad.py index b3d45272af..0a9b6f5e1f 100644 --- a/sdk/python/packages/flet-ads/src/flet_ads/native_ad.py +++ b/sdk/python/packages/flet-ads/src/flet_ads/native_ad.py @@ -27,7 +27,7 @@ class NativeAd(BannerAd): ValueError: When neither :attr:`factory_id` nor `template_style` is set. """ - def before_update(self): - super().before_update() + def init(self): + super().init() if self.factory_id is None and self.template_style is None: raise ValueError("factory_id or template_style must be set") diff --git a/sdk/python/packages/flet-ads/src/flet_ads/types.py b/sdk/python/packages/flet-ads/src/flet_ads/types.py index a15e144cb8..5578f99df9 100644 --- a/sdk/python/packages/flet-ads/src/flet_ads/types.py +++ b/sdk/python/packages/flet-ads/src/flet_ads/types.py @@ -6,12 +6,17 @@ __all__ = [ "AdRequest", + "ConsentDebugSettings", + "ConsentRequestParameters", + "ConsentStatus", + "DebugGeography", "NativeAdTemplateStyle", "NativeAdTemplateTextStyle", "NativeAdTemplateType", "NativeTemplateFontStyle", "PaidAdEvent", "PrecisionType", + "PrivacyOptionsRequirementStatus", ] @@ -129,3 +134,132 @@ class NativeAdTemplateStyle: primary_text_style: Optional[NativeAdTemplateTextStyle] = None secondary_text_style: Optional[NativeAdTemplateTextStyle] = None tertiary_text_style: Optional[NativeAdTemplateTextStyle] = None + + +class ConsentStatus(Enum): + """ + The state of the consent-gathering process, as reported by the + User Messaging Platform (UMP). + + Note: + This describes whether a consent decision has been *collected* — not + what the user chose. It is never "granted" versus "denied": the user's + actual selections live in the IAB TCF consent string, which the ads SDK reads + automatically. Use :meth:`flet_ads.ConsentManager.can_request_ads` to decide + whether to request ads. + """ + + NOT_REQUIRED = "notRequired" + """Consent is not required (e.g. the user is outside a regulated region).""" + + OBTAINED = "obtained" + """ + A consent decision has been collected. + + Set once the user completes the form — whether they consented, declined + ("Do not consent"), or saved custom choices. This does **not** imply that + consent was granted. + """ + + REQUIRED = "required" + """Consent is required but has not yet been collected.""" + + UNKNOWN = "unknown" + """Consent status is unknown.""" + + +class PrivacyOptionsRequirementStatus(Enum): + """ + Whether your app must show a privacy options entry point: a persistent + control (for example, a button in a settings menu) that lets the user + change or withdraw their consent at any time after their initial choice. + + Note: + Some regulations (e.g. GDPR) require this ongoing entry point. + When the user triggers it, call + :meth:`flet_ads.ConsentManager.show_privacy_options_form`. + """ + + NOT_REQUIRED = "notRequired" + """A privacy options entry point is not required.""" + + REQUIRED = "required" + """A privacy options entry point must be shown.""" + + UNKNOWN = "unknown" + """ + The requirement status is unknown — for example, before + :meth:`flet_ads.ConsentManager.request_consent_info_update` completes. + """ + + +class DebugGeography(Enum): + """ + Debug geography values used to test consent flows. + + Note: + These only take effect on devices registered as test devices through + :attr:`flet_ads.ConsentDebugSettings.test_identifiers`. + """ + + DISABLED = "disabled" + """Debug geography disabled.""" + + EEA = "eea" + """Geography appears as in the EEA (European Economic Area) for debug devices.""" + + REGULATED_US_STATE = "regulatedUsState" + """Geography appears as in a regulated US State for debug devices.""" + + OTHER = "other" + """Geography appears as in a region with no regulation in force.""" + + +@ft.value +class ConsentDebugSettings: + """ + Debug settings to hardcode in consent requests, useful for testing the + consent flow during development. + """ + + debug_geography: Optional[DebugGeography] = None + """ + The geography to simulate when gathering consent on test devices. + """ + + test_identifiers: Optional[list[str]] = None + """ + A list of device identifiers for which debug features + (such as :attr:`debug_geography`) are enabled. + + Note: + Simulators and emulators are automatically registered as test devices, + so this is only needed for physical devices. + + A physical device's hashed ID is printed to the **native** device log + (Xcode console/Console.app on iOS, `adb logcat` on Android) + the first time a consent request is made from it. + """ + + +@ft.value +class ConsentRequestParameters: + """ + Parameters sent when updating the user's consent information. + """ + + tag_for_under_age_of_consent: Optional[bool] = None + """ + Whether the user is tagged as being under the age of consent. + + `False` means users are not under the age of consent. + + Warning: + When `True`, the consent form is not shown, as users under the age of + consent cannot be asked to provide consent. + """ + + consent_debug_settings: Optional[ConsentDebugSettings] = None + """ + Debug settings to hardcode in test requests. + """ diff --git a/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/consent_manager.dart b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/consent_manager.dart new file mode 100644 index 0000000000..308d24c438 --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/consent_manager.dart @@ -0,0 +1,92 @@ +import 'dart:async'; + +import 'package:flet/flet.dart'; +import 'package:flutter/foundation.dart'; +import 'package:google_mobile_ads/google_mobile_ads.dart'; + +import '../utils/consent.dart'; + +class ConsentManagerService extends FletService { + ConsentManagerService({required super.control}); + + @override + void init() { + super.init(); + debugPrint("ConsentManager(${control.id}).init"); + control.addInvokeMethodListener(_invokeMethod); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("ConsentManager.$name($args)"); + switch (name) { + case "request_consent_info_update": + final completer = Completer(); + ConsentInformation.instance.requestConsentInfoUpdate( + parseConsentRequestParameters(args?["params"]), + () { + if (!completer.isCompleted) completer.complete(); + }, + (FormError error) { + if (!completer.isCompleted) { + completer.completeError(Exception( + "Consent info update failed (${error.errorCode}): ${error.message}")); + } + }, + ); + return completer.future; + + case "is_consent_form_available": + return await ConsentInformation.instance.isConsentFormAvailable(); + + case "get_consent_status": + return (await ConsentInformation.instance.getConsentStatus()).name; + + case "can_request_ads": + return await ConsentInformation.instance.canRequestAds(); + + case "get_privacy_options_requirement_status": + return (await ConsentInformation.instance + .getPrivacyOptionsRequirementStatus()) + .name; + + case "load_and_show_consent_form_if_required": + final completer = Completer(); + ConsentForm.loadAndShowConsentFormIfRequired((FormError? error) { + if (completer.isCompleted) return; + if (error != null) { + completer.completeError(Exception( + "Consent form error (${error.errorCode}): ${error.message}")); + } else { + completer.complete(); + } + }); + return completer.future; + + case "show_privacy_options_form": + final completer = Completer(); + ConsentForm.showPrivacyOptionsForm((FormError? error) { + if (completer.isCompleted) return; + if (error != null) { + completer.completeError(Exception( + "Privacy options form error (${error.errorCode}): ${error.message}")); + } else { + completer.complete(); + } + }); + return completer.future; + + case "reset": + return await ConsentInformation.instance.reset(); + + default: + throw Exception("Unknown ConsentManager method: $name"); + } + } + + @override + void dispose() { + debugPrint("ConsentManager(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } +} diff --git a/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/extension.dart b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/extension.dart index fa04866801..63e90828ef 100644 --- a/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/extension.dart +++ b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/extension.dart @@ -3,6 +3,7 @@ import 'package:flutter/cupertino.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; import 'banner.dart'; +import 'consent_manager.dart'; import 'interstitial.dart'; class Extension extends FletExtension { @@ -18,6 +19,8 @@ class Extension extends FletExtension { switch (control.type) { case "InterstitialAd": return InterstitialAdService(control: control); + case "ConsentManager": + return ConsentManagerService(control: control); default: return null; } diff --git a/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/utils/consent.dart b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/utils/consent.dart new file mode 100644 index 0000000000..f523d4ac82 --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/utils/consent.dart @@ -0,0 +1,25 @@ +import 'package:flet/flet.dart'; +import 'package:google_mobile_ads/google_mobile_ads.dart'; + +DebugGeography? parseDebugGeography(String? value, + [DebugGeography? defaultValue]) => + parseEnum(DebugGeography.values, "debugGeography$value", defaultValue); + +ConsentDebugSettings? parseConsentDebugSettings(dynamic value, + [ConsentDebugSettings? defaultValue]) { + if (value == null) return defaultValue; + return ConsentDebugSettings( + debugGeography: parseDebugGeography(value["debug_geography"]), + testIdentifiers: + (value["test_identifiers"] as List?)?.map((e) => e.toString()).toList(), + ); +} + +ConsentRequestParameters parseConsentRequestParameters(dynamic value) { + if (value == null) return ConsentRequestParameters(); + return ConsentRequestParameters( + tagForUnderAgeOfConsent: value["tag_for_under_age_of_consent"], + consentDebugSettings: + parseConsentDebugSettings(value["consent_debug_settings"]), + ); +} diff --git a/sdk/python/packages/flet-ads/src/flutter/flet_ads/pubspec.yaml b/sdk/python/packages/flet-ads/src/flutter/flet_ads/pubspec.yaml index 060cdf5d28..ceba00fd80 100644 --- a/sdk/python/packages/flet-ads/src/flutter/flet_ads/pubspec.yaml +++ b/sdk/python/packages/flet-ads/src/flutter/flet_ads/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: sdk: flutter collection: ^1.16.0 - google_mobile_ads: ^8.0.0 + google_mobile_ads: ^9.0.0 flet: path: ../../../../../../../packages/flet diff --git a/sdk/python/packages/flet-audio-recorder/src/flet_audio_recorder/types.py b/sdk/python/packages/flet-audio-recorder/src/flet_audio_recorder/types.py index 0f6472d21f..c8bca24aab 100644 --- a/sdk/python/packages/flet-audio-recorder/src/flet_audio_recorder/types.py +++ b/sdk/python/packages/flet-audio-recorder/src/flet_audio_recorder/types.py @@ -317,14 +317,6 @@ class IosRecorderConfiguration: Optional audio behaviors. """ - manage_audio_session: bool = True - """ - Whether to manage the shared AVAudioSession. - - Set this to `False` if another plugin is - already managing the AVAudioSession. - """ - @ft.value class InputDevice: diff --git a/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/lib/src/utils/audio_recorder.dart b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/lib/src/utils/audio_recorder.dart index 9f65d339df..d231280ca5 100644 --- a/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/lib/src/utils/audio_recorder.dart +++ b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/lib/src/utils/audio_recorder.dart @@ -49,7 +49,6 @@ IosRecordConfig? parseIosRecordConfig(dynamic value, .nonNulls .toList(); return IosRecordConfig( - manageAudioSession: parseBool(value["manage_audio_session"], true)!, categoryOptions: options, ); } diff --git a/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/pubspec.yaml b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/pubspec.yaml index 626f0576e3..2476b65809 100644 --- a/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/pubspec.yaml +++ b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: collection: ^1.16.0 http: ^1.2.2 - record: ^6.2.0 + record: ^7.1.0 flet: path: ../../../../../../../packages/flet diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/example_apps.py b/sdk/python/packages/flet-charts/integration_tests/examples/example_apps.py new file mode 100644 index 0000000000..6edbbb4eab --- /dev/null +++ b/sdk/python/packages/flet-charts/integration_tests/examples/example_apps.py @@ -0,0 +1,37 @@ +"""Loader for chart example apps used by integration tests. + +Chart examples live as standalone apps in +`sdk/python/examples/extensions/charts///main.py` (each with +its own pyproject.toml), so they are not importable as regular modules. +This helper loads an app's `main.py` by path and returns the module. +""" + +import importlib.util +import sys +from pathlib import Path + +_EXAMPLES_ROOT = ( + Path(__file__).resolve().parents[4] / "examples" / "extensions" / "charts" +) + + +def load_example(app_dir: str): + """Load the `main.py` module of an example app. + + Args: + app_dir: App directory relative to `examples/extensions/charts`, + e.g. `"bar_chart/interactive_bar_chart"`. + + Returns: + The loaded module; its `main` attribute is the app entry point. + """ + main_py = _EXAMPLES_ROOT / app_dir / "main.py" + module_name = "charts_example_" + app_dir.replace("/", "_") + if module_name in sys.modules: + return sys.modules[module_name] + spec = importlib.util.spec_from_file_location(module_name, main_py) + assert spec is not None and spec.loader is not None, f"Cannot load {main_py}" + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.exec_module(module) + return module diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/example_1.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/example_1.png index d8edda72f3..1e40602c7d 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/example_1.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/example_1.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/example_2.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/example_2.png index 59984cabf1..44abea8fcf 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/example_2.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/example_2.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/image_for_docs.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/image_for_docs.png index 896bf4e802..4feda4fdda 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/image_for_docs.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/image_for_docs.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/candlestick_chart/example_1.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/candlestick_chart/example_1.png index 31bd5be78a..061a233aec 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/candlestick_chart/example_1.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/candlestick_chart/example_1.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/candlestick_chart/image_for_docs.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/candlestick_chart/image_for_docs.png index ebe189336c..95d052720c 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/candlestick_chart/image_for_docs.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/candlestick_chart/image_for_docs.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/example_1.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/example_1.png index 0d50433bee..c4a8fc022b 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/example_1.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/example_1.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/example_2.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/example_2.png index 35f2c91b14..81c41de7cb 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/example_2.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/example_2.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/image_for_docs.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/image_for_docs.png index b5d03d566c..d59311f0c5 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/image_for_docs.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/image_for_docs.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/bar_chart.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/bar_chart.png index 7f3250b9d8..c37c1a00ea 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/bar_chart.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/bar_chart.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/handle_events.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/handle_events.png index ebaffcbe88..fd391bbaf6 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/handle_events.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/handle_events.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/three_d.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/three_d.png index c3fd1f8d4f..37468d63e0 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/three_d.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/three_d.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/toolbar.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/toolbar.png index 63f0388b82..dbada7bc33 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/toolbar.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/toolbar.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_1.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_1.png index 30716c1f34..1e1595923a 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_1.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_1.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_2.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_2.png index 6abdb67a5d..f66aa863fa 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_2.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_2.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_3.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_3.png index e9ef47d553..910bccb3ce 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_3.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_3.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_1.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_1.png index 668f2c0b2b..ebd9cc6052 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_1.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_1.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_2.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_2.png index 9828e790dc..2bf39c00f3 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_2.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_2.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_3.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_3.png index a8fe17dd8d..1a9e464a65 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_3.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_3.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_4.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_4.png index 4a668512f2..f4a90d0d1f 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_4.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_4.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/image_for_docs.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/image_for_docs.png index 76da2da143..f0a2a11e4b 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/image_for_docs.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/image_for_docs.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/radar_chart/example_1.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/radar_chart/example_1.png index afd0d9b91f..fe377c3e26 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/radar_chart/example_1.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/radar_chart/example_1.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/radar_chart/image_for_docs.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/radar_chart/image_for_docs.png index e978295f44..431d658fc4 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/radar_chart/image_for_docs.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/radar_chart/image_for_docs.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/scatter_chart/example_1.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/scatter_chart/example_1.png index 75b1d61347..e67e668fcb 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/scatter_chart/example_1.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/scatter_chart/example_1.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/scatter_chart/image_for_docs.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/scatter_chart/image_for_docs.png index 2284808ac1..03cd48c117 100644 Binary files a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/scatter_chart/image_for_docs.png and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/scatter_chart/image_for_docs.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/test_bar_chart.py b/sdk/python/packages/flet-charts/integration_tests/examples/test_bar_chart.py index 7453ded581..bd2c7bf9b0 100644 --- a/sdk/python/packages/flet-charts/integration_tests/examples/test_bar_chart.py +++ b/sdk/python/packages/flet-charts/integration_tests/examples/test_bar_chart.py @@ -1,9 +1,12 @@ import pytest +from example_apps import load_example import flet as ft import flet.testing as ftt import flet_charts as fch -from examples.controls.charts.bar_chart import example_1, example_2 + +example_1 = load_example("bar_chart/interactive_bar_chart") +example_2 = load_example("bar_chart/bar_chart_with_hover") @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/test_candlestick_chart.py b/sdk/python/packages/flet-charts/integration_tests/examples/test_candlestick_chart.py index 0a665d91d5..f1c61d7611 100644 --- a/sdk/python/packages/flet-charts/integration_tests/examples/test_candlestick_chart.py +++ b/sdk/python/packages/flet-charts/integration_tests/examples/test_candlestick_chart.py @@ -1,9 +1,11 @@ import pytest +from example_apps import load_example import flet as ft import flet.testing as ftt import flet_charts as fch -from examples.controls.charts.candlestick_chart import example_1 + +example_1 = load_example("candlestick_chart/candlestick_chart") @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/test_line_chart.py b/sdk/python/packages/flet-charts/integration_tests/examples/test_line_chart.py index bf91b7b037..d256f6239d 100644 --- a/sdk/python/packages/flet-charts/integration_tests/examples/test_line_chart.py +++ b/sdk/python/packages/flet-charts/integration_tests/examples/test_line_chart.py @@ -1,9 +1,12 @@ import pytest +from example_apps import load_example import flet as ft import flet.testing as ftt import flet_charts as fch -from examples.controls.charts.line_chart import example_1, example_2 + +example_1 = load_example("line_chart/multi_series_line_chart") +example_2 = load_example("line_chart/line_chart_with_custom_axes") @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/test_matplotlib_chart.py b/sdk/python/packages/flet-charts/integration_tests/examples/test_matplotlib_chart.py index d2aafaa4dd..2da522e639 100644 --- a/sdk/python/packages/flet-charts/integration_tests/examples/test_matplotlib_chart.py +++ b/sdk/python/packages/flet-charts/integration_tests/examples/test_matplotlib_chart.py @@ -1,12 +1,12 @@ import pytest +from example_apps import load_example import flet.testing as ftt -from examples.controls.charts.matplotlib_chart import ( - bar_chart, - handle_events, - three_d, - toolbar, -) + +bar_chart = load_example("matplotlib_chart/bar_chart") +handle_events = load_example("matplotlib_chart/handle_events") +three_d = load_example("matplotlib_chart/three_d") +toolbar = load_example("matplotlib_chart/toolbar") @pytest.mark.parametrize( @@ -64,7 +64,13 @@ async def test_toolbar(flet_app_function: ftt.FletTestApp): ) @pytest.mark.asyncio(loop_scope="function") async def test_three_d(flet_app_function: ftt.FletTestApp): + # Full-page screenshot, like the sibling tests: the controls-capture + # path measures intrinsic dimensions, which the LayoutBuilder-based + # matplotlib canvas cannot provide. + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() flet_app_function.assert_screenshot( "three_d", - await flet_app_function.take_page_controls_screenshot(), + await flet_app_function.page.take_screenshot(), ) diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/test_pie_chart.py b/sdk/python/packages/flet-charts/integration_tests/examples/test_pie_chart.py index af0e8f1723..c4660a1047 100644 --- a/sdk/python/packages/flet-charts/integration_tests/examples/test_pie_chart.py +++ b/sdk/python/packages/flet-charts/integration_tests/examples/test_pie_chart.py @@ -1,7 +1,11 @@ import pytest +from example_apps import load_example import flet.testing as ftt -from examples.controls.charts.pie_chart import example_1, example_2, example_3 + +example_1 = load_example("pie_chart/pie_chart_with_hover_borders") +example_2 = load_example("pie_chart/pie_chart_with_hover_sections") +example_3 = load_example("pie_chart/pie_chart_with_icon_badges") @pytest.mark.parametrize( diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/test_plotly_chart.py b/sdk/python/packages/flet-charts/integration_tests/examples/test_plotly_chart.py index 8b97b5c30d..2f8e18610c 100644 --- a/sdk/python/packages/flet-charts/integration_tests/examples/test_plotly_chart.py +++ b/sdk/python/packages/flet-charts/integration_tests/examples/test_plotly_chart.py @@ -1,15 +1,15 @@ import plotly.express as px import pytest +from example_apps import load_example import flet as ft import flet.testing as ftt import flet_charts as fch -from examples.controls.charts.plotly_chart import ( - example_1, - example_2, - example_3, - example_4, -) + +example_1 = load_example("plotly_chart/plotly_line_chart") +example_2 = load_example("plotly_chart/plotly_bar_chart") +example_3 = load_example("plotly_chart/plotly_pie_chart") +example_4 = load_example("plotly_chart/plotly_box_plot") @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/test_radar_chart.py b/sdk/python/packages/flet-charts/integration_tests/examples/test_radar_chart.py index c46f69fdc1..1471ec82ce 100644 --- a/sdk/python/packages/flet-charts/integration_tests/examples/test_radar_chart.py +++ b/sdk/python/packages/flet-charts/integration_tests/examples/test_radar_chart.py @@ -1,9 +1,11 @@ import pytest +from example_apps import load_example import flet as ft import flet.testing as ftt import flet_charts as fch -from examples.controls.charts.radar_chart import example_1 + +example_1 = load_example("radar_chart/radar_chart") @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/test_scatter_chart.py b/sdk/python/packages/flet-charts/integration_tests/examples/test_scatter_chart.py index 6d8c3a3187..e2e5510dd4 100644 --- a/sdk/python/packages/flet-charts/integration_tests/examples/test_scatter_chart.py +++ b/sdk/python/packages/flet-charts/integration_tests/examples/test_scatter_chart.py @@ -1,9 +1,11 @@ import pytest +from example_apps import load_example import flet as ft import flet.testing as ftt import flet_charts as fch -from examples.controls.charts.scatter_chart import example_1 + +example_1 = load_example("scatter_chart/scatter_chart") @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_backends/backend_flet_agg.py b/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_backends/backend_flet_agg.py index 450ecab3af..ed63db8c8e 100644 --- a/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_backends/backend_flet_agg.py +++ b/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_backends/backend_flet_agg.py @@ -1,3 +1,4 @@ +import numpy as np from matplotlib import _api from matplotlib.backends import backend_webagg_core @@ -8,12 +9,57 @@ class FigureCanvasFletAgg(backend_webagg_core.FigureCanvasWebAggCore): manager_class = _api.classproperty(lambda cls: FigureManagerFletAgg) supports_blit = False + def get_raw_frame(self): + """Raw analogue of `get_diff_image()` for local transports. + + Returns `(width, height, rgba)` when the renderer holds newer pixels + than the last sent frame, else `None`. Raw frames are always full + frames — no diffing, no PNG encoding. Unless premultiplication made + a copy, `rgba` aliases the live Agg buffer that the next draw + mutates in place, so the caller must consume it synchronously. + """ + if not self._png_is_old: + return None + renderer = self.get_renderer() + buf = renderer.buffer_rgba() # memoryview, straight alpha + w, h = int(renderer.width), int(renderer.height) + pixels = np.asarray(buf) + if (pixels[:, :, 3] != 255).any(): + # Flutter's rgba8888 upload assumes premultiplied alpha; Agg + # produces straight alpha. Premultiply only when needed. + out = pixels.copy() + a = out[:, :, 3:4].astype(np.uint16) + out[:, :, :3] = (out[:, :, :3].astype(np.uint16) * a // 255).astype( + np.uint8 + ) + buf = out.tobytes() + # Raw mode deliberately leaves `_last_buff` untouched: if the PNG + # path ever runs afterwards, the shape mismatch forces a full frame. + self._force_full = False + self._png_is_old = False + return (w, h, buf) + class FigureManagerFletAgg(backend_webagg_core.FigureManagerWebAgg): """Figure manager binding Matplotlib WebAgg tooling to Flet transport.""" _toolbar2_class = backend_webagg_core.NavigationToolbar2WebAgg + def refresh_all(self): + if not self.web_sockets: + return + raw = {s for s in self.web_sockets if getattr(s, "wants_raw_frames", False)} + if raw and raw == self.web_sockets: + frame = self.canvas.get_raw_frame() + if frame is not None: + for s in raw: + s.send_binary(frame) # tuple => raw frame + else: + # All-PNG, or mixed transports (same figure shown on two + # connection types — practically impossible in one process): + # everyone gets the PNG full/diff path. + super().refresh_all() + FigureCanvas = FigureCanvasFletAgg FigureManager = FigureManagerFletAgg diff --git a/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart.py b/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart.py index ed31e64403..eb88675a98 100644 --- a/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart.py +++ b/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart.py @@ -126,6 +126,14 @@ def build(self): self.__dpr = self.page.media.device_pixel_ratio logger.debug(f"DPR: {self.__dpr}") self.__image_mode = "full" + # Local transports (embedded native, Pyodide, dev socket) move + # DataChannel bytes at memcpy speed, so skip diffing + PNG encoding + # and stream raw RGBA full frames instead. Remote WebSocket clients + # keep the compact PNG full/diff pipeline. + self.wants_raw_frames = getattr( + self.page.session.connection, "local_data_transport", False + ) + logger.debug(f"wants_raw_frames: {self.wants_raw_frames}") self.mpl_canvas = MatplotlibChartCanvas( on_resize=self._on_canvas_resize, @@ -432,15 +440,24 @@ async def _receive_loop(self): is_binary, content = await self._receive_queue.get() if is_binary: - assert isinstance(content, (bytes, bytearray)) - logger.debug(f"receive_binary({len(content)})") - # Hand the frame to the client widget — full PNG replaces the - # backbuffer, diff PNG composites onto it. Awaiting naturally - # rate-limits this loop to the client's processing speed and - # yields the asyncio loop for incoming events. - if self.__image_mode == "full": + # Hand the frame to the client widget — a raw RGBA frame + # (pre-encoded 0x04 packet) or full PNG replaces the + # backbuffer, diff PNG composites onto it. `await` + # here serialises this receive loop on the Dart-side + # frame-applied ack: matplotlib "draw" notifications that + # arrive during the round-trip stay queued in + # `_receive_queue` and are processed after the ack returns, + # instead of being eagerly dropped against a stale + # `_waiting=True` gate. This is the same backpressure shape + # the 0.85 `_invoke_method` round-trip used to provide. + if isinstance(content, tuple) and content[0] == "raw": + logger.debug(f"receive_binary(raw, {len(content[1])})") + await self.mpl_canvas.apply_raw_packet(content[1]) + elif self.__image_mode == "full": + logger.debug(f"receive_binary(full, {len(content)})") await self.mpl_canvas.apply_full(bytes(content)) else: + logger.debug(f"receive_binary(diff, {len(content)})") await self.mpl_canvas.apply_diff(bytes(content)) self.img_count += 1 self._waiting = False @@ -503,7 +520,18 @@ def send_json(self, content): ) def send_binary(self, blob): - """Sends a binary message to the front end.""" + """Sends a binary message to the front end. + + Receives PNG `bytes` from matplotlib's stock full/diff path, or a + `(width, height, rgba)` tuple from `FigureManagerFletAgg.refresh_all` + in raw mode. This method runs synchronously inside `refresh_all()` + (same stack as `draw()`), which is the last safe moment to copy the + raw buffer — it aliases the live Agg buffer that the next draw + mutates in place. `encode_raw_frame` performs that one copy while + assembling the wire packet. + """ + if isinstance(blob, tuple): + blob = ("raw", MatplotlibChartCanvas.encode_raw_frame(*blob)) self._main_loop.call_soon_threadsafe( lambda: self._receive_queue.put_nowait((True, blob)) ) diff --git a/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart_canvas.py b/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart_canvas.py index 174167a404..981b75b0f0 100644 --- a/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart_canvas.py +++ b/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart_canvas.py @@ -1,5 +1,8 @@ +import asyncio +import contextlib +from collections import deque from dataclasses import dataclass, field -from typing import Optional +from typing import Callable, Optional import flet as ft @@ -24,12 +27,28 @@ class MatplotlibChartCanvas(ft.LayoutControl): """ Display widget for matplotlib WebAgg-style image streams. - Receives full and incremental "diff" PNG frames and composites them in - CPU memory, holding at most one decoded image for display at a time. - Avoids the per-frame `Picture.toImage` allocations that the generic - `flet.canvas.Canvas` capture path uses, which on Flutter web - (CanvasKit/WASM) accumulate and aren't promptly reclaimed by the JS GC - during animation, causing browser memory growth. + Receives either raw RGBA full frames (local transports) or full and + incremental "diff" PNG frames (remote WebSocket) and displays them, + holding at most one decoded image at a time. Frames flow over a + dedicated [ft.DataChannel] rather than the regular Flet protocol, so + the frame bytes skip MsgPack encode/decode and travel at + memory-bandwidth-class speed in embedded native mode (per-channel + PythonBridge) and at near-bandwidth speed in web/dev modes (raw-byte + frames muxed over the protocol transport). + + Wire format on the data channel (one byte of opcode followed by the + payload): + + | opcode | payload | meaning | + |--------|-------------------------------|-----------------------------------------| + | 0x01 | PNG bytes | apply_full — replace backdrop | + | 0x02 | PNG bytes | apply_diff — composite onto backbuffer | + | 0x03 | (empty) | clear — drop backdrop + backbuffer | + | 0x04 | [w u32 LE][h u32 LE][RGBA] | raw full frame, premultiplied RGBA8888 | + + The reverse-direction `resize` event (Dart → Python, small JSON-shaped + payload) stays on the existing Flet protocol channel — no reason to + move tiny control events off it. """ resize_interval: ft.Number = 10 @@ -42,6 +61,83 @@ class MatplotlibChartCanvas(ft.LayoutControl): Called when the size of this canvas has changed. """ + on_data_channel_open: Optional[ft.EventHandler[ft.DataChannelOpenEvent]] = None + """ + Framework hook — Dart fires this when it opens the data channel during + `initState`. The default handler captures the channel for use by + apply_full / apply_diff / clear. Override only if you need to do + something extra at attach-time. + """ + + def init(self) -> None: + # `init` is the @ft.control post-construct lifecycle hook (runs + # before `did_mount`). Wire up the default channel-capture handler. + self._channel: Optional[ft.DataChannel] = None + # FIFO of per-frame ack futures. Each `apply_*` enqueues a future + # and `awaits` it; `_on_dart_message` pops the head and resolves + # it when Dart's `[0xFF]` ack arrives. The await is what makes + # producer-side callers (e.g. MatplotlibChart._receive_loop) + # block — events queued during the wait are processed *after* + # the ack instead of being dropped by stale gate checks. + self._pending_acks: deque[asyncio.Future] = deque() + # Optional plain callback for observers that want to be notified + # on every frame ack (e.g. perf instrumentation). Fires alongside + # the future resolution; not load-bearing for backpressure. + self._on_frame_applied: Optional[Callable[[], None]] = None + if self.on_data_channel_open is None: + self.on_data_channel_open = self._capture_channel + + def _capture_channel(self, e: ft.DataChannelOpenEvent) -> None: + # Single-channel widget; no need to dispatch on e.channel_name. + self._channel = self.get_data_channel(e.channel_id) + self._channel.on_bytes(self._on_dart_message) + + def _on_dart_message(self, payload: bytes) -> None: + # Wire format on the reverse direction (Dart → Python): + # [0xFF] — frame_applied ack. Sent by Dart after each apply_full / + # apply_diff / clear completes on its end. Restores the + # round-trip backpressure that `_invoke_method` used to + # provide implicitly in 0.85. + if not payload or payload[0] != 0xFF: + return + # Resolve the head future so the matching `apply_*` await returns. + if self._pending_acks: + fut = self._pending_acks.popleft() + if not fut.done(): + fut.set_result(None) + # Then fire the observer callback (if any). + cb = self._on_frame_applied + if cb is not None: + with contextlib.suppress(Exception): + cb() + + def set_on_frame_applied(self, cb: Optional[Callable[[], None]]) -> None: + """Register a side-channel callback invoked on every frame ack. + + Useful for instrumentation. Backpressure is handled by awaiting + the result of `apply_full` / `apply_diff` / `clear` directly — + this callback is a fire-and-forget observer, not part of the + gating path. + """ + self._on_frame_applied = cb + + async def _send_and_wait(self, packet: bytes) -> None: + """Send a channel packet and await Dart's ack. + + Awaiting blocks the caller until `[0xFF]` arrives on the channel, + re-creating the 0.85 `_invoke_method` round-trip semantics: + events that arrive in the producer's queue during the wait stay + queued (instead of being processed eagerly against a stale + `_waiting` flag). + """ + if self._channel is None: + return + loop = asyncio.get_running_loop() + fut: asyncio.Future = loop.create_future() + self._pending_acks.append(fut) + self._channel.send(packet) + await fut + async def apply_full(self, image_bytes: bytes) -> None: """ Replace the current displayed image with a full PNG frame. @@ -49,7 +145,7 @@ async def apply_full(self, image_bytes: bytes) -> None: Args: image_bytes: PNG bytes of the complete frame. """ - await self._invoke_method("apply_full", arguments={"bytes": image_bytes}) + await self._send_and_wait(b"\x01" + image_bytes) async def apply_diff(self, image_bytes: bytes) -> None: """ @@ -63,10 +159,49 @@ async def apply_diff(self, image_bytes: bytes) -> None: Args: image_bytes: PNG bytes of the diff frame. """ - await self._invoke_method("apply_diff", arguments={"bytes": image_bytes}) + await self._send_and_wait(b"\x02" + image_bytes) async def clear(self) -> None: """ Clear the displayed image and discard the backbuffer. """ - await self._invoke_method("clear") + await self._send_and_wait(b"\x03") + + @staticmethod + def encode_raw_frame(width: int, height: int, rgba) -> bytes: + """ + Encode a raw full frame into a 0x04 wire packet. + + Args: + width: Frame width in physical pixels. + height: Frame height in physical pixels. + rgba: Premultiplied RGBA8888 pixels, `width * height * 4` bytes + (bytes-like; a memoryview aliasing a live buffer is copied + here exactly once). + """ + pkt = bytearray(9 + len(rgba)) + pkt[0] = 0x04 + pkt[1:5] = width.to_bytes(4, "little") + pkt[5:9] = height.to_bytes(4, "little") + pkt[9:] = rgba + return bytes(pkt) + + async def apply_raw(self, width: int, height: int, rgba: bytes) -> None: + """ + Replace the displayed image with a raw premultiplied-RGBA full frame. + + Args: + width: Frame width in physical pixels. + height: Frame height in physical pixels. + rgba: Premultiplied RGBA8888 pixels, `width * height * 4` bytes. + """ + await self._send_and_wait(self.encode_raw_frame(width, height, rgba)) + + async def apply_raw_packet(self, packet: bytes) -> None: + """ + Send a pre-encoded 0x04 raw-frame packet (avoids a second copy). + + Args: + packet: Complete wire packet produced by `encode_raw_frame`. + """ + await self._send_and_wait(packet) diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/matplotlib_chart_canvas.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/matplotlib_chart_canvas.dart index 2970c752f0..9fd1cf6696 100644 --- a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/matplotlib_chart_canvas.dart +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/matplotlib_chart_canvas.dart @@ -8,7 +8,13 @@ import 'package:flutter/material.dart'; /// Display widget for matplotlib WebAgg-style image streams. /// -/// Two rendering strategies, picked at runtime by platform: +/// Raw RGBA full frames (opcode 0x04, sent on local transports) take the +/// same path in both strategies: one `ui.decodeImageFromPixels` upload, +/// swap the displayed image, dispose the old one — no PNG decode, no +/// compositing, at most one live image, so it is safe on web/WASM too. +/// +/// PNG full/diff frames (remote WebSocket) use two rendering strategies, +/// picked at runtime by platform: /// /// - **GPU + flatten** (native): keeps an `_backdrop` plus a list of pending /// diff `ui.Image`s, paints all of them per frame, and bakes them into a @@ -35,22 +41,9 @@ class MatplotlibChartCanvasControl extends StatefulWidget { } // --------------------------------------------------------------------------- -// Shared helpers +// Shared base // --------------------------------------------------------------------------- -Uint8List _extractBytes(dynamic args) { - final v = args is Map ? args["bytes"] : args; - if (v is Uint8List) return v; - if (v is ByteData) { - return v.buffer.asUint8List(v.offsetInBytes, v.lengthInBytes); - } - if (v is List) return Uint8List.fromList(v); - if (v is List && v.every((e) => e is int)) { - return Uint8List.fromList(v.cast()); - } - throw ArgumentError("Expected bytes for image data, got ${v.runtimeType}"); -} - abstract class _MatplotlibChartCanvasStateBase extends State { // Serialize concurrent apply_full / apply_diff calls so backdrop mutations @@ -60,15 +53,30 @@ abstract class _MatplotlibChartCanvasStateBase Size _lastSize = Size.zero; int _lastResize = DateTime.now().millisecondsSinceEpoch; + DataChannel? _channel; + StreamSubscription? _channelSub; + @override - void initState() { - super.initState(); - widget.control.addInvokeMethodListener(_invokeMethod); + void didChangeDependencies() { + super.didChangeDependencies(); + // Open the data channel lazily on first dependency lookup — we need + // BuildContext to reach FletBackend, which isn't available in initState. + if (_channel != null) return; + _channel = FletBackend.of(context).openDataChannel(); + _channelSub = _channel!.messages.listen(_onChannelFrame); + // Announce the channel to Python via the standard convention event. + widget.control.triggerEvent("data_channel_open", { + "channel_name": "frames", + "channel_id": _channel!.id, + }); } @override void dispose() { - widget.control.removeInvokeMethodListener(_invokeMethod); + _channelSub?.cancel(); + _channelSub = null; + _channel?.close(); + _channel = null; disposeResources(); super.dispose(); } @@ -78,25 +86,53 @@ abstract class _MatplotlibChartCanvasStateBase Future applyFull(Uint8List bytes); Future applyDiff(Uint8List bytes); + Future applyRaw(Uint8List payload); Future clearAll(); CustomPainter buildPainter(); - Future _invokeMethod(String name, dynamic args) async { - switch (name) { - case "apply_full": - await _enqueue(() => applyFull(_extractBytes(args))); - return; - case "apply_diff": - await _enqueue(() => applyDiff(_extractBytes(args))); - return; - case "clear": - await _enqueue(clearAll); - return; + // 1-byte ack sent back to Python after each apply completes. Restores + // round-trip backpressure: matplotlib's producer side keeps `_waiting` + // set until this ack arrives, so frames don't pile up in the Dart-side + // queue during interactive drags. + static final Uint8List _frameAppliedAck = Uint8List.fromList([0xFF]); + + /// Inbound DataChannel frame. Wire format: + /// [0x01][PNG bytes] → apply_full + /// [0x02][PNG bytes] → apply_diff + /// [0x03] → clear + /// [0x04][w u32 LE][h u32 LE][RGBA8888] → apply_raw (premultiplied) + void _onChannelFrame(Uint8List bytes) { + if (bytes.isEmpty) return; + // Zero-copy slice of the same underlying buffer. + final payload = Uint8List.sublistView(bytes, 1); + switch (bytes[0]) { + case 0x01: + _enqueueAndAck(() => applyFull(payload)); + break; + case 0x02: + _enqueueAndAck(() => applyDiff(payload)); + break; + case 0x03: + _enqueueAndAck(clearAll); + break; + case 0x04: + _enqueueAndAck(() => applyRaw(payload)); + break; default: - throw Exception("Unknown MatplotlibChartCanvas method: $name"); + debugPrint( + "MatplotlibChartCanvas: unknown data-channel opcode 0x${bytes[0].toRadixString(16)}"); + // Ack anyway so a newer Python side never hangs its receive loop + // waiting on a frame this (older) client can't apply. + _channel?.send(_frameAppliedAck); } } + void _enqueueAndAck(Future Function() task) { + _enqueue(task).whenComplete(() { + _channel?.send(_frameAppliedAck); + }); + } + Future _enqueue(Future Function() task) { final prev = _applyChain ?? Future.value(); final next = prev.then((_) => task()); @@ -133,6 +169,48 @@ abstract class _MatplotlibChartCanvasStateBase } } +/// A parsed raw-frame payload: `[w u32 LE][h u32 LE][RGBA8888]`. +class _RawFrame { + final int width; + final int height; + final Uint8List pixels; // owned copy + _RawFrame({required this.width, required this.height, required this.pixels}); +} + +/// Parses and validates a 0x04 raw-frame payload. Returns null (and logs) +/// on malformed input — the caller skips the frame; the ack still goes out +/// via `_enqueueAndAck`, so Python never stalls on a bad frame. +_RawFrame? _parseRawFrame(Uint8List payload) { + if (payload.length < 8) return null; + final bd = ByteData.sublistView(payload, 0, 8); + final w = bd.getUint32(0, Endian.little); + final h = bd.getUint32(4, Endian.little); + if (w == 0 || h == 0 || payload.length - 8 != w * h * 4) { + debugPrint( + "MatplotlibChartCanvas: bad raw frame ${payload.length - 8} != $w*$h*4"); + return null; + } + // Owned copy: the transport may reuse the inbound buffer, Safari's WASM + // runtime can free views across async gaps (same reason _decodeImage + // copies), and decodeImageFromPixels implementations may read from the + // underlying buffer after this call returns. + final pixels = Uint8List.fromList(Uint8List.sublistView(payload, 8)); + return _RawFrame(width: w, height: h, pixels: pixels); +} + +/// Uploads premultiplied RGBA8888 pixels as a [ui.Image]. +Future _imageFromRgba(Uint8List rgba, int width, int height) { + final completer = Completer(); + ui.decodeImageFromPixels( + rgba, + width, + height, + ui.PixelFormat.rgba8888, + completer.complete, + ); + return completer.future; +} + /// Decodes PNG bytes to a [ui.Image], staying GPU-resident. Future _decodeImage(Uint8List bytes) async { if (bytes.isEmpty) { @@ -204,6 +282,17 @@ class _GpuMatplotlibChartCanvasState if (mounted) setState(() {}); } + @override + Future applyRaw(Uint8List payload) async { + final f = _parseRawFrame(payload); + if (f == null) return; + final image = await _imageFromRgba(f.pixels, f.width, f.height); + // Raw frames are always full frames — replace and drop pending diffs. + _replaceBackdrop(image); + _disposeDiffs(); + if (mounted) setState(() {}); + } + @override Future clearAll() async { _replaceBackdrop(null); @@ -326,7 +415,22 @@ class _CpuMatplotlibChartCanvasState _bbWidth = decoded.width; _bbHeight = decoded.height; - final image = await _makeImage(decoded.bytes, decoded.width, decoded.height); + final image = + await _imageFromRgba(decoded.bytes, decoded.width, decoded.height); + _swapDisplay(image); + } + + @override + Future applyRaw(Uint8List payload) async { + final f = _parseRawFrame(payload); + if (f == null) return; + // Keep the backbuffer coherent so a later PNG diff (mixed-mode safety + // net) still composites correctly. Raw pixels are already premultiplied, + // matching rawRgba readbacks. + _backbuffer = f.pixels; + _bbWidth = f.width; + _bbHeight = f.height; + final image = await _imageFromRgba(f.pixels, f.width, f.height); _swapDisplay(image); } @@ -349,7 +453,7 @@ class _CpuMatplotlibChartCanvasState _bbWidth = decoded.width; _bbHeight = decoded.height; final image = - await _makeImage(decoded.bytes, decoded.width, decoded.height); + await _imageFromRgba(decoded.bytes, decoded.width, decoded.height); _swapDisplay(image); return; } @@ -365,7 +469,7 @@ class _CpuMatplotlibChartCanvasState } } - final image = await _makeImage(_backbuffer!, _bbWidth, _bbHeight); + final image = await _imageFromRgba(_backbuffer!, _bbWidth, _bbHeight); _swapDisplay(image); } @@ -401,18 +505,6 @@ class _CpuMatplotlibChartCanvasState } } - Future _makeImage(Uint8List rgba, int width, int height) { - final completer = Completer(); - ui.decodeImageFromPixels( - rgba, - width, - height, - ui.PixelFormat.rgba8888, - completer.complete, - ); - return completer.future; - } - void _swapDisplay(ui.Image newImage) { final old = _displayImage; _displayImage = newImage; diff --git a/sdk/python/packages/flet-cli/pyproject.toml b/sdk/python/packages/flet-cli/pyproject.toml index 4b65881aa8..8653b82135 100644 --- a/sdk/python/packages/flet-cli/pyproject.toml +++ b/sdk/python/packages/flet-cli/pyproject.toml @@ -14,9 +14,13 @@ dependencies = [ "tomli >= 1.1.0 ; python_version < '3.11'", "cookiecutter >=2.6.0", "binaryornot <0.5", - "chardet <6" + "chardet <6", + "rich >=13.0.0" ] +[project.optional-dependencies] +mcp = ["flet-mcp"] + [project.urls] Homepage = "https://flet.dev" Repository = "https://github.com/flet-dev/flet" diff --git a/sdk/python/packages/flet-cli/src/flet_cli/cli.py b/sdk/python/packages/flet-cli/src/flet_cli/cli.py index 1a7b3e1a8e..390c0f8969 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/cli.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/cli.py @@ -1,8 +1,10 @@ import argparse +import json import sys import flet.version import flet_cli.commands.build +import flet_cli.commands.clean import flet_cli.commands.create import flet_cli.commands.debug import flet_cli.commands.devices @@ -12,6 +14,29 @@ import flet_cli.commands.publish import flet_cli.commands.run import flet_cli.commands.serve +import flet_cli.commands.test +from flet_cli.utils.linux_deps import linux_dependencies + + +def _version_info() -> dict: + """Build the machine-readable `flet --version --json` document. + + Exposes Flet/Flutter versions and the Linux build dependencies. The + supported Python/Pyodide set is no longer surfaced here — it now comes from + python-build's manifest (see `flet_cli.utils.python_versions`). + """ + return { + "flet": flet.version.flet_version, + "flutter": flet.version.flutter_version, + "linux_dependencies": list(linux_dependencies), + } + + +def _render_version(as_json: bool) -> str: + """Render `flet --version` output as JSON or the human-readable text block.""" + if as_json: + return json.dumps(_version_info(), indent=2) + return f"Flet: {flet.version.flet_version}\nFlutter: {flet.version.flutter_version}" # Source https://stackoverflow.com/a/26379693 @@ -68,16 +93,17 @@ def get_parser() -> argparse.ArgumentParser: formatter_class=argparse.RawDescriptionHelpFormatter ) - # add version flag + # add version flags parser.add_argument( "--version", "-V", - action="version", - version=( - f"Flet: {flet.version.flet_version}\n" - f"Flutter: {flet.version.flutter_version}\n" - f"Pyodide: {flet.version.pyodide_version}" - ), + action="store_true", + help="show version information and exit", + ) + parser.add_argument( + "--json", + action="store_true", + help="with --version, output version information as JSON", ) sp = parser.add_subparsers(dest="command") @@ -86,7 +112,9 @@ def get_parser() -> argparse.ArgumentParser: flet_cli.commands.create.Command.register_to(sp, "create") flet_cli.commands.run.Command.register_to(sp, "run") flet_cli.commands.build.Command.register_to(sp, "build") + flet_cli.commands.clean.Command.register_to(sp, "clean") flet_cli.commands.debug.Command.register_to(sp, "debug") + flet_cli.commands.test.Command.register_to(sp, "test") flet_cli.commands.pack.Command.register_to(sp, "pack") flet_cli.commands.publish.Command.register_to(sp, "publish") flet_cli.commands.serve.Command.register_to(sp, "serve") @@ -94,6 +122,16 @@ def get_parser() -> argparse.ArgumentParser: flet_cli.commands.devices.Command.register_to(sp, "devices") flet_cli.commands.doctor.Command.register_to(sp, "doctor") + # Register MCP command only if flet-mcp is installed + try: + from importlib import import_module + + import_module("flet_mcp") + mcp_cmd = import_module("flet_cli.commands.mcp") + mcp_cmd.Command.register_to(sp, "mcp") + except ImportError: + pass + # set "run" as the default subparser set_default_subparser(parser, name="run", index=1) @@ -111,6 +149,11 @@ def main(): # parse arguments args = parser.parse_args() + # handle `flet --version [--json]` (no subcommand/handler is set) + if getattr(args, "version", False): + print(_render_version(args.json)) + sys.exit(0) + # execute command args.handler(args) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/build.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/build.py index fb45b8e5a4..d9a6364b2d 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/build.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/build.py @@ -1,9 +1,13 @@ import argparse +import os +import shutil +from pathlib import Path from rich.console import Group from rich.live import Live from flet_cli.commands.build_base import BaseBuildCommand, console +from flet_cli.utils.android import flutter_target_platforms class Command(BaseBuildCommand): @@ -13,7 +17,7 @@ class Command(BaseBuildCommand): Android (APK/AAB), and iOS (IPA and simulator .app), with a wide range of customization options for metadata, assets, splash screens, and signing. - Detailed guide with usage examples: https://flet.dev/docs/publish + Detailed usage guide: https://flet.dev/docs/publish """ def __init__(self, parser: argparse.ArgumentParser) -> None: @@ -116,9 +120,24 @@ def add_flutter_command_args(self, args: list[str]): ["build", self.platforms[self.target_platform]["flutter_build_command"]] ) - if self.target_platform in "apk" and self.template_data["split_per_abi"]: + if self.target_platform == "apk" and self.template_data["split_per_abi"]: args.append("--split-per-abi") + if ( + self.target_platform in ("apk", "aab") + and self.template_data["options"]["target_arch"] + ): + args.extend( + [ + "--target-platform", + ",".join( + flutter_target_platforms( + self.template_data["options"]["target_arch"] + ) + ), + ] + ) + if self.target_platform in ["ipa"]: if self.template_data["ios_provisioning_profile"]: args.extend( @@ -166,6 +185,22 @@ def run_flutter(self): f"{self.platforms[self.target_platform]['status_text']}[/cyan]..." ) + # Clear the build output directories of artifacts from previous runs. Flutter + # only ever adds files to them, and copy_build_output harvests them wholesale — + # so without this, a previous build with different options (e.g. --arch, + # --split-per-abi, or a renamed product) would leak its artifacts into the + # user's output directory. + assert self.flutter_dir + flutter_dir = self.flutter_dir.resolve() + for output in self.platforms[self.target_platform]["outputs"]: + output_dir = Path( + os.path.dirname(self.resolve_output_path(output)) + ).resolve() + # only delete directories that are strictly inside the generated Flutter + # project (and never the project directory itself). + if output_dir != flutter_dir and output_dir.is_relative_to(flutter_dir): + shutil.rmtree(output_dir, ignore_errors=True) + self._run_flutter_command() console.log( diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py index a96b081df5..5eb5ef62cd 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py @@ -1,6 +1,8 @@ import argparse +import base64 import copy import glob +import json import os import platform import shutil @@ -15,6 +17,7 @@ import flet.version import flet_cli.utils.processes as processes from flet.utils import copy_tree, slugify +from flet.utils.deprecated import deprecated_warning from flet_cli.commands.flutter_base import ( BaseFlutterCommand, console, @@ -23,6 +26,10 @@ verbose2_style, warning_style, ) +from flet_cli.utils.android import ( + ANDROID_ARCH_TO_FLUTTER_TARGET_PLATFORM, + excluded_android_abis, +) from flet_cli.utils.cli import parse_cli_bool_value from flet_cli.utils.hash_stamp import HashStamp from flet_cli.utils.merge import merge_dict @@ -32,12 +39,28 @@ get_project_dependencies, ) from flet_cli.utils.pyproject_toml import load_pyproject_toml +from flet_cli.utils.python_versions import ( + UnsupportedPythonVersionError, + resolve_python_version, +) DEFAULT_TEMPLATE_URL = ( "https://github.com/flet-dev/flet/releases/download/" "v{version}/flet-build-template.zip" ) +# Android (serious_python native-mmap packaging): pure Python ships in stored zips +# read via zipimport, which breaks packages that read bundled data through a real +# filesystem path (__file__ / pkg_resources) instead of importlib.resources. Such +# packages are shipped extracted to disk via --android-extract-packages or +# [tool.flet.android].extract_packages. +# +# The default set is empty: the common offenders read their data via +# importlib.resources, which is zip-safe (e.g. certifi.where() works from the zip — +# importlib.resources.as_file() extracts cacert.pem to a temp file on demand). Add +# real offenders here as they are found. +ANDROID_DEFAULT_EXTRACT_PACKAGES: list[str] = [] + class BaseBuildCommand(BaseFlutterCommand): """ @@ -66,6 +89,7 @@ def __init__(self, parser: argparse.ArgumentParser) -> None: self.flutter_dir: Optional[Path] = None self.flutter_packages_dir = None self.flutter_packages_temp_dir = None + self.site_packages_skipped = False self.platforms = { "windows": { "package_platform": "Windows", @@ -244,10 +268,13 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: parser.add_argument( "--arch", dest="target_arch", + action="extend", nargs="+", default=[], help="Build for specific CPU architectures " - "(used in macOS and Android builds only). Example: `--arch arm64 x64`", + "(used in macOS and Android builds only). " + "Android: arm64-v8a, armeabi-v7a, x86_64; macOS: arm64, x64. " + "Example: `--arch arm64-v8a`", ) parser.add_argument( "--exclude", @@ -263,7 +290,8 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: dest="clear_cache", action="store_true", default=None, - help="Remove any existing build cache before starting the build process", + help="Remove any existing build cache before starting the build process. " + "Deprecated: use the `flet clean` command instead", ) parser.add_argument( "--project", @@ -400,7 +428,8 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: dest="web_renderer", type=str.lower, choices=["auto", "canvaskit", "skwasm"], - help="Flutter web renderer to use (web only) [env: FLET_WEB_RENDERER=]", + help="Flutter web renderer to use (web only), default: canvaskit " + "[env: FLET_WEB_RENDERER=]", ) parser.add_argument( "--route-url-strategy", @@ -448,16 +477,30 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: parser.add_argument( "--compile-app", dest="compile_app", - action="store_true", + action=argparse.BooleanOptionalAction, default=None, - help="Pre-compile app's `.py` files to `.pyc`", + help="Pre-compile app's `.py` files to `.pyc` (on by default; " + "use --no-compile-app to disable)", ) parser.add_argument( "--compile-packages", dest="compile_packages", - action="store_true", + action=argparse.BooleanOptionalAction, default=None, - help="Pre-compile site packages' `.py` files to `.pyc`", + help="Pre-compile site packages' `.py` files to `.pyc` (on by default; " + "use --no-compile-packages to disable)", + ) + parser.add_argument( + "--swift-package-manager", + dest="swift_package_manager", + action=argparse.BooleanOptionalAction, + default=None, + help="Integrate the embedded Python runtime via Swift Package Manager " + "(default) or CocoaPods for iOS/macOS builds. On by default, matching " + "Flutter 3.44+ which uses SPM by default (other non-SPM plugins still " + "build with CocoaPods alongside it). Use --no-swift-package-manager (or " + "`swift_package_manager = false` under [tool.flet]) only if you've " + "disabled Swift Package Manager in Flutter.", ) parser.add_argument( "--cleanup-app", @@ -497,10 +540,28 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: parser.add_argument( "--source-packages", dest="source_packages", + action="extend", nargs="+", default=[], help="The list of Python packages to install from source distributions", ) + parser.add_argument( + "--android-extract-packages", + dest="android_extract_packages", + nargs="+", + default=[], + help="Android only: Python packages (relative paths) to ship extracted " + "to disk instead of inside the app zip — for packages that read bundled " + "data via __file__ / pkg_resources rather than importlib.resources", + ) + parser.add_argument( + "--python-version", + dest="python_version", + type=str, + default=None, + help="Python version to bundle (e.g. 3.13). Defaults to the latest " + "supported version, or is parsed from project.requires-python.", + ) parser.add_argument( "--info-plist", dest="info_plist", @@ -552,6 +613,7 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: "--permissions", dest="permissions", type=str.lower, + action="extend", nargs="+", default=[], choices=["location", "camera", "microphone", "photo_library"], @@ -647,6 +709,22 @@ def handle(self, options: argparse.Namespace) -> None: """ super().handle(options) + + if getattr(self.options, "clear_cache", None): + deprecated_warning( + name="--clear-cache", + reason="Use the `flet clean` command instead.", + version="0.86.0", + delete_version="0.89.0", + type="flag", + ) + console.print( + "Warning: the `--clear-cache` flag is deprecated since version " + "0.86.0 and will be removed in version 0.89.0. " + "Use the `flet clean` command instead.", + style=warning_style, + ) + if "target_platform" in self.options: self.target_platform = self.options.target_platform @@ -693,6 +771,29 @@ def initialize_command(self): self.pubspec_path = str(self.flutter_dir.joinpath("pubspec.yaml")) self.get_pyproject = load_pyproject_toml(self.python_app_path) + try: + self.python_release = resolve_python_version( + self.options.python_version, self.get_pyproject + ) + except UnsupportedPythonVersionError as e: + self.cleanup(1, str(e)) + + # Changing the bundled Python version invalidates the compiled bytecode + # baked into the previous build's native bundles (stdlib/site-packages + # .pyc). Reusing the build directory would mix versions and crash at + # runtime with "bad magic number". Force a clean rebuild on a switch. + version_marker = self.build_dir / ".python-version" + if self.build_dir.exists() and version_marker.exists(): + previous = version_marker.read_text(encoding="utf-8").strip() + if previous and previous != self.python_release.short: + console.log( + f"Bundled Python version changed ({previous} -> " + f"{self.python_release.short}); cleaning the build directory." + ) + shutil.rmtree(self.build_dir, ignore_errors=True) + self.build_dir.mkdir(parents=True, exist_ok=True) + version_marker.write_text(self.python_release.short, encoding="utf-8") + def validate_target_platform(self): """ Validate whether current host OS can build the selected target platform. @@ -794,6 +895,13 @@ def setup_template_data(self): or self.get_pyproject("project.name") or self.python_app_path.name ) + # Under integration test, `flutter test -d ` launches the built + # binary by the project name (the Flutter pubspec `name`), but the + # Windows/Linux runner sets the executable's OUTPUT_NAME to artifact_name. + # When they differ (e.g. `artifact = "my-app"` vs project `my_app`) the + # test host can't find the binary. Pin them equal in test mode. + if getattr(self, "test_mode", False): + artifact_name = project_name product_name = ( self.options.product_name or self.get_pyproject("tool.flet.product") @@ -1086,6 +1194,40 @@ def _xml_attr_value(v): or self.get_pyproject(f"tool.flet.{self.config_platform}.target_arch") or self.get_pyproject("tool.flet.target_arch") ) + target_arch = ( + target_arch + if isinstance(target_arch, list) + else [target_arch] + if isinstance(target_arch, str) + else [] + ) + if self.package_platform == "Android": + invalid_archs = [ + arch + for arch in target_arch + if arch not in ANDROID_ARCH_TO_FLUTTER_TARGET_PLATFORM + ] + if invalid_archs: + self.cleanup( + 1, + f"Invalid Android architecture(s): {', '.join(invalid_archs)}.\n" + f"Supported: " + f"{', '.join(ANDROID_ARCH_TO_FLUTTER_TARGET_PLATFORM)}.\n" + f"Docs: https://flet.dev/docs/publish/android#supported-target-architectures", + ) + python_abis = list(self.python_release.android_abis) + unsupported_archs = [a for a in target_arch if a not in python_abis] + if unsupported_archs: + self.cleanup( + 1, + f"Architecture(s) not supported by Python " + f"{self.python_release.short}: {', '.join(unsupported_archs)}.\n" + f"Supported: {', '.join(python_abis)}.\n" + f"Docs: https://flet.dev/docs/publish/android#supported-target-architectures", + ) + if not target_arch: + # Build only for the ABIs the bundled Python supports. + target_arch = python_abis ios_export_method = ( self.options.ios_export_method @@ -1127,6 +1269,7 @@ def _xml_attr_value(v): self.target_platform in ["ipa"] and not ios_provisioning_profile and not self.debug_platform + and not getattr(self, "test_mode", False) ): console.print( Panel( @@ -1147,10 +1290,15 @@ def _xml_attr_value(v): or self.get_pyproject("tool.flet.web.route_url_strategy") or "path" ), + # "canvaskit" (dart2js), not "auto": with "auto" Chromium browsers + # select the dart2wasm/skwasm build, where every JS <-> Dart byte + # buffer crossing pays a WasmGC boundary conversion instead of a + # memcpy. Pyodide apps stream bytes constantly (protocol frames, + # DataChannels) — measured ~6-7x slower frame display vs canvaskit. "web_renderer": ( self.options.web_renderer or self.get_pyproject("tool.flet.web.renderer") - or "auto" + or "canvaskit" ), "pwa_background_color": ( self.options.pwa_background_color @@ -1167,8 +1315,16 @@ def _xml_attr_value(v): "no_cdn": ( self.options.no_cdn or self.get_pyproject("tool.flet.web.cdn") == False # noqa: E712 ), + # Surface the resolved Pyodide release to the cookiecutter + # context so the web template's index.html can wire the + # correct jsdelivr URL when CDN mode is on. + "pyodide_version": self.python_release.pyodide, "base_url": f"/{base_url}/" if base_url else "/", "split_per_abi": split_per_abi, + # Enabled by `flet test` to scaffold integration-test wiring + # (integration_test/ + flutter_test dev deps). Default False so + # normal `flet build`/`flet debug` output is unaffected. + "test_mode": getattr(self, "test_mode", False), "project_name": project_name, "project_name_slug": project_name_slug, "artifact_name": artifact_name, @@ -1197,11 +1353,11 @@ def _xml_attr_value(v): "options": { "package_platform": self.package_platform, "config_platform": self.config_platform, - "target_arch": ( - target_arch - if isinstance(target_arch, list) - else [target_arch] - if isinstance(target_arch, str) + "python_version": self.python_release.short, + "target_arch": target_arch, + "android_excluded_abis": ( + excluded_android_abis(target_arch) + if self.package_platform == "Android" else [] ), "info_plist": info_plist, @@ -1221,9 +1377,77 @@ def _xml_attr_value(v): ), }, "flutter": {"dependencies": list(self.flutter_dependencies.keys())}, + "boot_screen": self._resolve_boot_screen(), "pyproject": self.get_pyproject(), } + def _resolve_boot_screen(self): + """ + Resolve the boot screen configuration from pyproject.toml. + + Merges the global `[tool.flet.boot_screen]` with the platform-specific + `[tool.flet..boot_screen]` (platform wins per key), resolves + the selected screen `name` (default "flet") and its options table. + + Falls back to the legacy `[tool.flet[.].app.boot_screen]` / + `app.startup_screen` (`show`/`message`) settings, mapping them onto the + built-in "flet" screen with a deprecation warning. + + Returns a dict with `name` and `options_b64` (base64-encoded JSON of the + options table) for the cookiecutter template. + """ + config_platform = self.config_platform + + def merged(key): + result = {} + merge_dict( + result, copy.deepcopy(self.get_pyproject(f"tool.flet.{key}") or {}) + ) + merge_dict( + result, + copy.deepcopy( + self.get_pyproject(f"tool.flet.{config_platform}.{key}") or {} + ), + ) + return result + + boot_screen = merged("boot_screen") + + if boot_screen: + name = boot_screen.get("name", "flet") + options = boot_screen.get(name) or {} + else: + # backward compatibility with the legacy app.boot_screen / + # app.startup_screen settings + name = "flet" + options = {} + legacy_boot = merged("app.boot_screen") + legacy_startup = merged("app.startup_screen") + if legacy_boot or legacy_startup: + console.log( + "[tool.flet.app.boot_screen] and " + "[tool.flet.app.startup_screen] are deprecated; use " + "[tool.flet.boot_screen] with a named screen instead.", + style=warning_style, + ) + if legacy_boot.get("show"): + options["spinner_size"] = 30 + message = legacy_boot.get("message") + if message: + options["prepare_message"] = message + if legacy_startup.get("show"): + options["spinner_size"] = 30 + message = legacy_startup.get("message") + if message: + options["startup_message"] = message + + return { + "name": name, + "options_b64": base64.b64encode(json.dumps(options).encode("utf-8")).decode( + "ascii" + ), + } + def create_flutter_project(self, second_pass=False): """ Render Flutter bootstrap project from template if template inputs changed. @@ -1332,6 +1556,8 @@ def create_flutter_project(self, second_pass=False): self.cleanup(1, f"{e}") # For local development, override flet dependency with path + repo_root = None + pubspec = None if is_local_dev: repo_root = flet.version.find_repo_root(Path(__file__).resolve().parent) if repo_root: @@ -1341,7 +1567,47 @@ def create_flutter_project(self, second_pass=False): pubspec.setdefault("dependency_overrides", {})["flet"] = { "path": flet_pkg_path } - self.save_yaml(self.pubspec_path, pubspec) + + # In test mode, inject the integration-test driver (and flutter_test) + # as dev dependencies. They are intentionally NOT in the template + # pubspec: that keeps it valid YAML for the release patch tooling and + # ensures a normal `flet build` never pulls them. flet_integration_test + # is publish_to:none, so for local dev it resolves to the in-repo + # package by path, and for an end user it is a git dependency pinned to + # this flet version's tag. + if getattr(self, "test_mode", False): + if pubspec is None: + pubspec = self.load_yaml(self.pubspec_path) + dev_deps = pubspec.setdefault("dev_dependencies", {}) + dev_deps["flutter_test"] = {"sdk": "flutter"} + if is_local_dev and repo_root: + fit_pkg_path = str(repo_root / "packages" / "flet_integration_test") + dev_deps["flet_integration_test"] = {"path": fit_pkg_path} + pubspec.setdefault("dependency_overrides", {})[ + "flet_integration_test" + ] = {"path": fit_pkg_path} + else: + dev_deps["flet_integration_test"] = { + "git": { + "url": "https://github.com/flet-dev/flet.git", + "ref": f"v{flet.version.flet_version}", + "path": "packages/flet_integration_test", + } + } + + # Only the web (Pyodide) build loads the packaged app as a Flutter + # asset; on native platforms serious_python places it inside the + # bundle, and a missing app/app.zip asset would fail the build. + if self.config_platform == "web": + if pubspec is None: + pubspec = self.load_yaml(self.pubspec_path) + assets = pubspec.setdefault("flutter", {}).setdefault("assets", []) + for asset in ["app/app.zip", "app/app.zip.hash"]: + if asset not in assets: + assets.append(asset) + + if pubspec is not None: + self.save_yaml(self.pubspec_path, pubspec) pyproject_pubspec = self.get_pyproject("tool.flet.flutter.pubspec") @@ -1384,11 +1650,25 @@ def register_flutter_extensions(self): assert self.template_data assert self.build_dir - if self.flutter_packages_temp_dir.exists(): - # copy packages from temp to permanent location + # Replace the permanent flutter-packages copy with this build's set. The + # temp dir is populated by serious_python's package step and is ABSENT + # when the app has no Flutter extensions — so always clear the old copy + # first, otherwise an extension removed since the previous build (e.g. + # dropping flet-video) would linger here and stay in the built app. + # + # Skip this when the package step ran with --skip-site-packages: in that + # mode serious_python does not repopulate the temp dir, so an absent temp + # dir means "unchanged" rather than "no extensions". Wiping here would + # delete the previous build's extensions and never restore them, breaking + # the Flutter build (unresolved web plugins). A removed extension changes + # the package requirements, flips the package hash, and takes the full + # (non-skip) path above instead. + if not self.site_packages_skipped: if self.flutter_packages_dir.exists(): shutil.rmtree(self.flutter_packages_dir, ignore_errors=True) - shutil.move(self.flutter_packages_temp_dir, self.flutter_packages_dir) + if self.flutter_packages_temp_dir.exists(): + # copy packages from temp to permanent location + shutil.move(self.flutter_packages_temp_dir, self.flutter_packages_dir) if self.flutter_packages_dir.exists(): self.update_status("[bold blue]Registering Flutter user extensions...") @@ -1849,6 +2129,25 @@ def fallback_image(self, pubspec, yaml_path: str, images: list, images_dir: str) d[pp[-1]] = f"{images_dir}/{image}" return + def _darwin_spm_active(self) -> bool: + """Whether to stage serious_python for Swift Package Manager (vs CocoaPods). + + On by default, matching Flutter 3.44+ (SPM enabled by default). Because + `serious_python_darwin` ships a `Package.swift`, Flutter always builds it + as an SPM plugin when SPM is enabled — even in a hybrid app where other, + non-SPM plugins (e.g. `flet-video`/media_kit) build with CocoaPods at the + same time. So serious_python must stage for SPM to match; it is NOT tied + to whether the app also pulls in non-SPM plugins. Users force CocoaPods + with `--no-swift-package-manager` (or `swift_package_manager = false` under + `[tool.flet]`) only when they've disabled SPM in Flutter itself. Flet does + not change Flutter's global SPM configuration. + """ + if self.package_platform not in ("iOS", "Darwin"): + return False + return self.get_bool_setting( + self.options.swift_package_manager, "swift_package_manager", True + ) + def package_python_app(self): """ Package Python app and dependencies into Flutter-consumable app archive. @@ -1879,14 +2178,24 @@ def package_python_app(self): str(self.package_app_path), "--platform", self.package_platform, + "--python-version", + self.python_release.short, ] if self.template_data["options"]["target_arch"]: + # serious_python's --arch is a Dart multi-option: values must be + # comma-separated or the flag repeated. Space-separated values + # after the first are silently treated as positional arguments. package_args.extend( - ["--arch"] + self.template_data["options"]["target_arch"] + ["--arch", ",".join(self.template_data["options"]["target_arch"])] ) - package_env = {} + # Only the short version is passed; serious_python derives the full + # version, python-build date, and dart_bridge version from its own + # committed snapshot of the manifest. + package_env = { + "SERIOUS_PYTHON_VERSION": self.python_release.short, + } # requirements requirements_txt = self.python_app_path.joinpath("requirements.txt") @@ -1919,7 +2228,13 @@ def package_python_app(self): if not dev_path.is_absolute(): dev_path = (self.python_app_path / dev_path).resolve() if dev_path.exists(): - toml_dependencies[i] = f"{package_name} @ file://{dev_path}" + # Use Path.as_uri() so Windows drive paths render as + # `file:///D:/a/...` rather than `file://D:\a\...`, + # which pip otherwise treats as a UNC path and fails + # to resolve. + toml_dependencies[i] = ( + f"{package_name} @ {dev_path.as_uri()}" + ) else: toml_dependencies[i] = ( f"{package_name} @ {package_location}" @@ -1949,6 +2264,23 @@ def package_python_app(self): package_env["SERIOUS_PYTHON_SITE_PACKAGES"] = str( self.build_dir / "site-packages" ) + # app staging dir: serious_python's `package` places the processed + # app here (no app.zip on native); the platform native build copies + # it into the bundle (Android zips it as a stored asset). + package_env["SERIOUS_PYTHON_APP"] = str(self.build_dir / "python-app") + + # Swift Package Manager (darwin): tell serious_python's package command to + # do the host-side SPM staging (the podspec prepare_command doesn't run + # under SPM) and write the SP_NATIVE_SET cache-bust key to this file. + # serious_python defaults to SPM staging, so be explicit either way — set + # it false for the CocoaPods cases (e.g. an app using flet-video). + if self.package_platform in ("iOS", "Darwin"): + spm = self._darwin_spm_active() + package_env["SERIOUS_PYTHON_DARWIN_SPM"] = "true" if spm else "false" + if spm: + package_env["SERIOUS_PYTHON_SPM_KEY_FILE"] = str( + self.build_dir / ".serious_python_spm_key" + ) # flutter-packages variable if self.flutter_packages_temp_dir.exists(): @@ -1984,11 +2316,31 @@ def package_python_app(self): source_packages ) - if self.get_bool_setting(self.options.compile_app, "compile.app", False): + # android-extract-packages: path-hungry packages shipped extracted to disk + # instead of inside the zip (serious_python Android native-mmap packaging). + # A built-in default set covers commonly-broken packages; the user list + # (CLI / pyproject) is merged on top. Consumed by the serious_python_android + # Gradle split during `flutter build`, so the env var is set on build_env + # (see _run_flutter_command), not on the package step. + self.android_extract_packages: list[str] = [] + if self.package_platform == "Android": + user_extract_packages = ( + self.options.android_extract_packages + or self.get_pyproject( + f"tool.flet.{self.config_platform}.extract_packages" + ) + or self.get_pyproject("tool.flet.extract_packages") + or [] + ) + self.android_extract_packages = list( + dict.fromkeys(ANDROID_DEFAULT_EXTRACT_PACKAGES + user_extract_packages) + ) + + if self.get_bool_setting(self.options.compile_app, "compile.app", True): package_args.append("--compile-app") if self.get_bool_setting( - self.options.compile_packages, "compile.packages", False + self.options.compile_packages, "compile.packages", True ): package_args.append("--compile-packages") @@ -2055,6 +2407,11 @@ def package_python_app(self): if not dev_packages_configured: if not hash.has_changed(): package_args.append("--skip-site-packages") + # serious_python skips copying Flutter packages to the temp dir + # under --skip-site-packages, so register_flutter_extensions must + # keep (not wipe) the permanent flutter-packages copy from the + # previous build. + self.site_packages_skipped = True else: if self.flutter_packages_dir.exists(): shutil.rmtree(self.flutter_packages_dir, ignore_errors=True) @@ -2075,13 +2432,36 @@ def package_python_app(self): hash.commit() - # make sure app/app.zip exists - app_zip_path = self.flutter_dir.joinpath("app", "app.zip") - if not os.path.exists(app_zip_path): - self.cleanup(1, "Flet app package app/app.zip was not created.") + # verify the package output: web ships app/app.zip; native platforms + # stage the unpacked app to build/app for the native build to bundle. + if self.package_platform == "Emscripten": + app_zip_path = self.flutter_dir.joinpath("app", "app.zip") + if not os.path.exists(app_zip_path): + self.cleanup(1, "Flet app package app/app.zip was not created.") + else: + app_staging_dir = self.build_dir / "python-app" + if not app_staging_dir.exists(): + self.cleanup( + 1, f"Flet app package was not staged to {app_staging_dir}." + ) console.log(f"Packaged Python app {self.emojis['checkmark']}") + # Drop the matching Pyodide runtime into the Flutter project's web/ + # directory so it ships in `flutter build web` output. Cached + # per-version under ~/.flet/pyodide// so subsequent builds + # are no-ops. + if self.package_platform == "Emscripten": + from flet_cli.utils.pyodide import ensure_pyodide + + self.update_status("[bold blue]Preparing Pyodide runtime...") + pyodide_dest = self.flutter_dir / "web" / "pyodide" + ensure_pyodide(self.python_release.pyodide, pyodide_dest) + console.log( + f"Pyodide {self.python_release.pyodide} ready " + f"{self.emojis['checkmark']}" + ) + def get_bool_setting(self, cli_option, pyproj_setting, default_value): """ Resolve a boolean setting with precedence: CLI option, pyproject, default. @@ -2131,6 +2511,60 @@ def run_flutter(self): self._run_flutter_command() + def _serious_python_build_env(self) -> dict: + """ + serious_python environment for the platform NATIVE build (the Gradle / + CMake / podspec steps run by `flutter build`). + + These tell the native build where the `package` step staged the app and + site-packages and which embedded Python runtime to bundle. `flet build` + applies them via `_run_flutter_command`; `flet test` applies the SAME set + to the `flutter test` it spawns (see test.py `_flutter_path_env`) so both + bundle an identical app. In particular, without `SERIOUS_PYTHON_APP` the + Android `packageApp` Gradle task early-returns and a stale `app.zip` (e.g. + an old-Python `main.pyc`) survives in the APK — `ImportError: bad magic + number`. Built defensively so it is safe to call before the full build + pipeline has populated every attribute. + """ + + env: dict = {} + python_release = getattr(self, "python_release", None) + if python_release is not None: + # Only the short version is passed; serious_python derives the rest + # from its committed manifest snapshot. + env["SERIOUS_PYTHON_VERSION"] = python_release.short + + build_dir = getattr(self, "build_dir", None) + package_platform = getattr(self, "package_platform", None) + if build_dir is not None and package_platform != "Emscripten": + env["SERIOUS_PYTHON_SITE_PACKAGES"] = str(build_dir / "site-packages") + # app staging dir: read by the platform native build (CMake / podspec + # / Android Gradle) at `flutter build` time to place the unpacked app + # into the bundle. + env["SERIOUS_PYTHON_APP"] = str(build_dir / "python-app") + + # Swift Package Manager (darwin): export the cache-bust key the package + # step computed so the plugin's Package.swift re-resolves when the staged + # native set changes (SwiftPM caches its graph on manifest text + env). + if ( + build_dir is not None + and package_platform in ("iOS", "Darwin") + and self._darwin_spm_active() + ): + spm_key_file = build_dir / ".serious_python_spm_key" + if spm_key_file.exists(): + env["SP_NATIVE_SET"] = spm_key_file.read_text().strip() + + # Path-hungry packages to ship extracted to disk: consumed by the + # serious_python_android Gradle split during `flutter build`. + if package_platform == "Android" and getattr( + self, "android_extract_packages", None + ): + env["SERIOUS_PYTHON_ANDROID_EXTRACT_PACKAGES"] = ",".join( + self.android_extract_packages + ) + return env + def _run_flutter_command(self): """ Build final Flutter CLI command, configure environment, and run it. @@ -2152,13 +2586,10 @@ def _run_flutter_command(self): ] ) - build_env = {} - - # site-packages variable - if self.package_platform != "Emscripten": - build_env["SERIOUS_PYTHON_SITE_PACKAGES"] = str( - self.build_dir / "site-packages" - ) + # serious_python env for the native build, shared verbatim with `flet + # test` (which spawns its own `flutter test`) so both bundle an identical + # app — see `_serious_python_build_env`. + build_env = self._serious_python_build_env() if self.package_platform == "Emscripten" and not self.template_data["no_wasm"]: build_args.append("--wasm") @@ -2232,6 +2663,32 @@ def _run_flutter_command(self): console.log(build_result.stderr, style=error_style) self.cleanup(build_result.returncode if build_result.returncode else 1) + def resolve_output_path(self, build_output: str) -> str: + """ + Resolve a platform `outputs` glob to an absolute path inside the + Flutter project, substituting the `{arch}` and name placeholders. + + Args: + build_output: An entry of `self.platforms[...]["outputs"]`. + """ + + assert self.flutter_dir + assert self.template_data + + arch = platform.machine().lower() + if arch in {"x86_64", "amd64"}: + arch = "x64" + elif arch in {"arm64", "aarch64"}: + arch = "arm64" + + return ( + str(self.flutter_dir.joinpath(build_output)) + .replace("{arch}", arch) + .replace("{artifact_name}", self.template_data["artifact_name"]) + .replace("{project_name}", self.template_data["project_name"]) + .replace("{product_name}", self.template_data["product_name"]) + ) + def copy_build_output(self): """ Copy generated platform artifacts into the requested output directory. @@ -2247,11 +2704,6 @@ def copy_build_output(self): self.update_status( f"[bold blue]Copying build to [cyan]{self.rel_out_dir}[/cyan] directory...", ) - arch = platform.machine().lower() - if arch in {"x86_64", "amd64"}: - arch = "x64" - elif arch in {"arm64", "aarch64"}: - arch = "arm64" def make_ignore_fn(out_dir, out_glob): """ @@ -2270,13 +2722,7 @@ def ignore(path, names): return ignore for build_output in self.platforms[self.target_platform]["outputs"]: - build_output_dir = ( - str(self.flutter_dir.joinpath(build_output)) - .replace("{arch}", arch) - .replace("{artifact_name}", self.template_data["artifact_name"]) - .replace("{project_name}", self.template_data["project_name"]) - .replace("{product_name}", self.template_data["product_name"]) - ) + build_output_dir = self.resolve_output_path(build_output) if self.verbose > 0: console.log( diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/clean.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/clean.py new file mode 100644 index 0000000000..0100aadca3 --- /dev/null +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/clean.py @@ -0,0 +1,76 @@ +import argparse +import shutil +from pathlib import Path + +from rich.console import Console +from rich.style import Style + +from flet_cli.commands.base import BaseCommand + +error_style = Style(color="red1", bold=True) +success_style = Style(color="green", bold=True) +console = Console(log_path=False) + + +class Command(BaseCommand): + """ + Delete the build output directory of a Flet app. + + Removes the `build` directory (created by `flet build` and `flet debug`) + located in the given app directory, including the Flutter bootstrap + project, cached artifacts, and generated output. + """ + + def add_arguments(self, parser: argparse.ArgumentParser) -> None: + """ + Register command-line options for cleaning a project's build directory. + + Args: + parser: Argument parser configured by the command runner. + """ + + parser.add_argument( + "python_app_path", + type=str, + nargs="?", + default=".", + help="Path to a directory with a Flet Python program " + "whose `build` directory should be deleted", + ) + + def handle(self, options: argparse.Namespace) -> None: + """ + Delete the `build` directory of the specified Flet app. + + Args: + options: Parsed command-line options. + """ + + verbose = options.verbose + + app_path = Path(options.python_app_path).resolve() + if not app_path.is_dir(): + console.print( + f"Path to Flet app does not exist or is not a directory: {app_path}", + style=error_style, + ) + exit(1) + + build_dir = app_path.joinpath("build") + if not build_dir.exists(): + console.print(f"Nothing to clean: no `build` directory at {build_dir}.") + return + + if verbose > 0: + console.print(f"[cyan]Deleting[/cyan] {build_dir}") + + try: + shutil.rmtree(build_dir) + except OSError as e: + console.print( + f"Error deleting build directory {build_dir}: {e}", + style=error_style, + ) + exit(1) + + console.print(f"Removed build directory: {build_dir}", style=success_style) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/create.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/create.py index 9af5bef439..a257686339 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/create.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/create.py @@ -24,6 +24,8 @@ class Command(BaseCommand): Create a new Flet project using a predefined template. It sets up the initial directory structure, metadata, and required files to help you get started quickly. + + Detailed guide with usage examples: https://flet.dev/docs/getting-started/create-flet-app """ def add_arguments(self, parser: argparse.ArgumentParser) -> None: @@ -162,3 +164,7 @@ def handle(self, options: argparse.Namespace) -> None: else "" ) console.print(f"flet run {app_dir}\n") + + # print testing step + console.print("[cyan]Run the integration tests:[/cyan]\n") + console.print(f"flet test {app_dir}\n") diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/debug.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/debug.py index fff1b7b8d3..acdcccb53d 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/debug.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/debug.py @@ -12,6 +12,8 @@ class Command(BaseBuildCommand): """ Run a Flet Python app in debug mode on a specified platform (desktop, web, mobile). + + Detailed usage guide: https://flet.dev/blog/flet-debug-the-new-cli-for-testing-flet-apps-on-mobile-devices """ def __init__(self, parser: argparse.ArgumentParser) -> None: diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/mcp.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/mcp.py new file mode 100644 index 0000000000..76f4490a98 --- /dev/null +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/mcp.py @@ -0,0 +1,67 @@ +import argparse +from pathlib import Path + +from flet_cli.commands.base import BaseCommand + + +class Command(BaseCommand): + """Flet MCP server for LLM agents.""" + + def add_arguments(self, parser: argparse.ArgumentParser) -> None: + sub = parser.add_subparsers(dest="mcp_command") + + # `flet mcp build` sub-subcommand + build_parser = sub.add_parser("build", help="Build MCP index data") + build_parser.add_argument( + "--examples", + type=Path, + help="Path to examples directory", + ) + build_parser.add_argument( + "--docs", + type=Path, + help="Path to mkdocs search_index.json " + "(deferred — pending Docusaurus rework)", + ) + build_parser.add_argument( + "--output", + type=Path, + help="Output directory (default: flet_mcp/data/)", + ) + + # `flet mcp` (serve) options — applied to the mcp parser itself + parser.add_argument( + "--transport", + choices=["stdio", "streamable-http"], + default="stdio", + help="MCP transport mode", + ) + parser.add_argument( + "--port", + type=int, + default=8000, + help="Port for HTTP transport mode", + ) + + def handle(self, options: argparse.Namespace) -> None: + if options.mcp_command == "build": + self._handle_build(options) + else: + self._handle_serve(options) + + def _handle_serve(self, options: argparse.Namespace) -> None: + from flet_mcp.server import mcp + + if options.transport == "streamable-http": + mcp.run(transport="streamable-http", port=options.port) + else: + mcp.run(transport="stdio") + + def _handle_build(self, options: argparse.Namespace) -> None: + from flet_mcp.build.indexer import build_all + + build_all( + examples_dir=options.examples, + docs_index=options.docs, + output_dir=options.output, + ) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/publish.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/publish.py index 921e470aec..b745fc647f 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/publish.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/publish.py @@ -13,12 +13,19 @@ get_poetry_dependencies, get_project_dependencies, ) +from flet_cli.utils.pyodide import ensure_pyodide from flet_cli.utils.pyproject_toml import load_pyproject_toml +from flet_cli.utils.python_versions import ( + UnsupportedPythonVersionError, + resolve_python_version, +) class Command(BaseCommand): """ Compile and package a Flet app as a standalone static web application. + + Detailed usage guide: https://flet.dev/docs/publish/web/static-website """ def add_arguments(self, parser: argparse.ArgumentParser) -> None: @@ -42,7 +49,17 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: action="store_true", default=False, help="Allow micropip to install pre-release Python packages. " - "Use this if your app depends on a prerelease version of a package", + "Use this if your app depends on a prerelease version of a package. " + "Unrelated to --python-version (this flag is about micropip " + "packages, not the Python interpreter itself).", + ) + parser.add_argument( + "--python-version", + dest="python_version", + type=str, + default=None, + help="Python version to bundle (e.g. 3.13). Defaults to the latest " + "supported version, or is parsed from project.requires-python.", ) parser.add_argument( "-a", @@ -96,8 +113,9 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: dest="web_renderer", type=str.lower, choices=["auto", "canvaskit", "skwasm"], - default="auto", - help="Flutter web renderer to use [env: FLET_WEB_RENDERER=]", + default=None, + help="Flutter web renderer to use, default: canvaskit " + "[env: FLET_WEB_RENDERER=]", ) parser.add_argument( "--route-url-strategy", @@ -172,6 +190,15 @@ def handle(self, options: argparse.Namespace) -> None: project_dir = Path(script_dir) get_pyproject = load_pyproject_toml(project_dir) + try: + python_release = resolve_python_version( + options.python_version, get_pyproject + ) + except UnsupportedPythonVersionError as e: + print(e) + sys.exit(2) + print(f"Using Python {python_release.short} (Pyodide {python_release.pyodide})") + if get_pyproject("tool.flet.app.path"): script_dir = script_dir.joinpath(get_pyproject("tool.flet.app.path")) script_path = script_dir.joinpath( @@ -198,6 +225,11 @@ def handle(self, options: argparse.Namespace) -> None: sys.exit(1) copy_tree(web_path, dist_dir) + # Drop in the Pyodide runtime that matches the resolved Python version + # (cached under ~/.flet/pyodide//). + print(f"Preparing Pyodide {python_release.pyodide} runtime...") + ensure_pyodide(python_release.pyodide, Path(dist_dir) / "pyodide") + # copy assets assets_dir = options.assets_dir if assets_dir and not Path(assets_dir).is_absolute(): @@ -322,10 +354,15 @@ def filter_tar(tarinfo: tarfile.TarInfo): pyodide=True, pyodide_pre=options.pre, pyodide_script_path=str(script_path), + pyodide_version=python_release.pyodide, + # "canvaskit" default for the same reason as `flet build web`: + # "auto" puts Chromium on dart2wasm/skwasm, whose JS <-> Dart + # typed-data boundary costs are a large per-frame tax for + # byte-streaming Pyodide apps. web_renderer=WebRenderer( options.web_renderer or get_pyproject("tool.flet.web.renderer") - or "auto" + or "canvaskit" ), route_url_strategy=RouteUrlStrategy( options.route_url_strategy diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/run.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/run.py index 2be23587a1..116a2a9d71 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/run.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/run.py @@ -28,6 +28,8 @@ class Command(BaseCommand): """ Run a Flet application in hot reload mode. + + Detailed usage guide: https://flet.dev/docs/getting-started/running-app """ def add_arguments(self, parser: argparse.ArgumentParser) -> None: @@ -220,8 +222,67 @@ def handle(self, options: argparse.Namespace) -> None: else [] ) - flet_app_data_dir = project_dir / "storage" / "data" - flet_app_temp_dir = project_dir / "storage" / "temp" + # Dev-mode app storage under a hidden, Flet-namespaced `.flet/` dir so + # it stays out of the way and is git-ignored. Mirrors a built app: the + # data dir becomes the process cwd; data/cache/temp map to the three + # FLET_APP_STORAGE_* env vars. + flet_storage_dir = project_dir / ".flet" / "storage" + flet_app_data_dir = flet_storage_dir / "data" + flet_app_cache_dir = flet_storage_dir / "cache" + flet_app_temp_dir = flet_storage_dir / "temp" + for d in (flet_app_data_dir, flet_app_cache_dir, flet_app_temp_dir): + d.mkdir(parents=True, exist_ok=True) + # Self-ignore the whole `.flet/` dir in any repo, independent of the + # project's root .gitignore. + flet_dir = project_dir / ".flet" + flet_gitignore = flet_dir / ".gitignore" + if not flet_gitignore.exists(): + flet_gitignore.write_text("*\n", encoding="utf-8") + # Drop a short note explaining what this dir is, next to .gitignore. + flet_readme = flet_dir / "README.md" + if not flet_readme.exists(): + flet_readme.write_text( + "# `.flet/`\n" + "\n" + "This directory is created by `flet run` to hold per-project " + "development state. It is local to your machine, safe to delete " + "(it will be recreated on the next run), and git-ignored via the " + "`.gitignore` next to this file.\n" + "\n" + "While `flet run` is active, your app's working directory is " + "`storage/data` and the three storage locations are exposed to " + "your Python code through the `FLET_APP_STORAGE_*` environment " + "variables — matching how a packaged app behaves on a device.\n" + "\n" + "## `storage/`\n" + "\n" + "- **`data/`** (`FLET_APP_STORAGE_DATA`) — durable application " + "data: databases, settings, user files. This is also the " + "process current working directory, so relative paths " + '(e.g. `sqlite3.connect("my.db")`) land here. Persists across ' + "runs; the equivalent of this dir is preserved across app " + "updates on a device.\n" + "- **`cache/`** (`FLET_APP_STORAGE_CACHE`) — regenerable cache " + "data. The OS may purge the equivalent dir on a device under " + "storage pressure, so only store things you can rebuild.\n" + "- **`temp/`** (`FLET_APP_STORAGE_TEMP`) — throwaway scratch " + "space. Python's `tempfile` is pointed here too. May be cleared " + "at any time.\n", + encoding="utf-8", + ) + # On Windows a leading dot doesn't hide a dir (that's a POSIX + # convention); set the FILE_ATTRIBUTE_HIDDEN attribute explicitly so + # `.flet/` stays out of Explorer / file pickers like it does elsewhere. + if is_windows(): + try: + import ctypes + + FILE_ATTRIBUTE_HIDDEN = 0x02 + ctypes.windll.kernel32.SetFileAttributesW( + str(flet_dir), FILE_ATTRIBUTE_HIDDEN + ) + except Exception: + pass my_event_handler = Handler( args=[sys.executable, "-u"] @@ -240,6 +301,7 @@ def handle(self, options: argparse.Namespace) -> None: assets_dir=assets_dir, ignore_dirs=ignore_dirs, flet_app_data_dir=str(flet_app_data_dir), + flet_app_cache_dir=str(flet_app_cache_dir), flet_app_temp_dir=str(flet_app_temp_dir), ) @@ -284,6 +346,7 @@ def __init__( assets_dir, ignore_dirs, flet_app_data_dir, + flet_app_cache_dir, flet_app_temp_dir, ) -> None: super().__init__() @@ -307,6 +370,7 @@ def __init__( self.page_url_prefix = f"PAGE_URL_{time.time()}" self.page_url = None self.flet_app_data_dir = flet_app_data_dir + self.flet_app_cache_dir = flet_app_cache_dir self.flet_app_temp_dir = flet_app_temp_dir self.terminate = threading.Event() self.start_process() @@ -339,13 +403,37 @@ def start_process(self): p_env["FLET_DISPLAY_URL_PREFIX"] = self.page_url_prefix p_env["FLET_APP_STORAGE_DATA"] = self.flet_app_data_dir + p_env["FLET_APP_STORAGE_CACHE"] = self.flet_app_cache_dir p_env["FLET_APP_STORAGE_TEMP"] = self.flet_app_temp_dir + # Point Python's temp machinery at the project-local temp dir so + # tempfile.gettempdir() agrees with FLET_APP_STORAGE_TEMP and dev scratch + # stays inside the git-ignored .flet/. + p_env["TMPDIR"] = self.flet_app_temp_dir + p_env["TEMP"] = self.flet_app_temp_dir + p_env["TMP"] = self.flet_app_temp_dir + + # We launch the app with cwd = the data dir (matches a built app, where + # the app bundle is read-only and writes go to app-support). Keep the + # app importable by putting the original working directory — where + # `flet run` was invoked and where `-m` modules resolve — on PYTHONPATH. + invocation_cwd = os.getcwd() + existing_pythonpath = p_env.get("PYTHONPATH", "") + p_env["PYTHONPATH"] = ( + invocation_cwd + os.pathsep + existing_pythonpath + if existing_pythonpath + else invocation_cwd + ) + p_env["PYTHONIOENCODING"] = "utf-8" p_env["PYTHONWARNINGS"] = "default::DeprecationWarning" self.p = subprocess.Popen( - self.args, env=p_env, stdout=subprocess.PIPE, encoding="utf-8" + self.args, + env=p_env, + cwd=self.flet_app_data_dir, + stdout=subprocess.PIPE, + encoding="utf-8", ) self.is_running = True diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/test.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/test.py new file mode 100644 index 0000000000..fa5945158f --- /dev/null +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/test.py @@ -0,0 +1,294 @@ +import argparse +import os +import platform +import subprocess +import sys +from pathlib import Path +from typing import Optional + +from rich.console import Group +from rich.live import Live + +from flet_cli.commands.build_base import BaseBuildCommand, console + +# Maps the user-facing test platform to the build target_platform used to +# provision the Flutter test host, plus the default device id for desktop. +TEST_PLATFORMS = { + "windows": {"target_platform": "windows", "device_id": "windows"}, + "macos": {"target_platform": "macos", "device_id": "macos"}, + "linux": {"target_platform": "linux", "device_id": "linux"}, + "ios": {"target_platform": "ipa", "device_id": None}, + "android": {"target_platform": "apk", "device_id": None}, +} + + +def _default_desktop_platform() -> str: + name = platform.system().lower() + return "macos" if name == "darwin" else name # "windows" / "linux" + + +def _provision_steps(cmd: "BaseBuildCommand") -> Path: + """ + Drive the shared `flet build` provisioning pipeline (in `test_mode`) to + materialize a Flutter test host with the app's Python embedded as + `app/app.zip` and the `integration_test/` driver. Release build, icons, + splash and output-copy steps are intentionally skipped — `flutter test` + compiles its own debug binary. Returns the provisioned Flutter project dir. + """ + cmd.test_mode = True + cmd.initialize_command() + cmd.validate_target_platform() + cmd.validate_entry_point() + cmd.setup_template_data() + cmd.create_flutter_project() + cmd.package_python_app() + cmd.register_flutter_extensions() + if cmd.create_flutter_project(second_pass=True): + cmd.update_flutter_dependencies() + return cmd.flutter_dir + + +# Env vars set by `flet test` (and `provision_test_host`) for the pytest +# subprocess. `flutter test integration_test` (spawned by FletTestApp) runs the +# platform's native build, whose serious_python build phase bundles the staged +# app + site-packages — without these vars the embedded Python can't import its +# dependencies (e.g. ModuleNotFoundError: certifi) and, on Android, the +# `packageApp` Gradle task no-ops so a stale `app.zip` (old-Python `main.pyc`) +# survives in the APK (ImportError: bad magic number). `flet build`/`flet debug` +# set the SAME serious_python vars for their flutter build via +# `_serious_python_build_env` (build_base.py `_run_flutter_command`); we reuse it +# here so the two paths can't drift. +_TEST_ENV_KEYS = ( + "PATH", + "FLET_TEST_DISABLE_FVM", + "FLET_TEST_FLUTTER_EXE", + "SERIOUS_PYTHON_VERSION", + "SERIOUS_PYTHON_SITE_PACKAGES", + "SERIOUS_PYTHON_APP", + "SERIOUS_PYTHON_ANDROID_EXTRACT_PACKAGES", + "SP_NATIVE_SET", + "SERIOUS_PYTHON_FLUTTER_PACKAGES", +) + + +def _flutter_path_env(cmd: "BaseBuildCommand") -> dict: + """ + Build an environment for the pytest subprocess so the on-device test run + (`flutter test integration_test`, spawned by FletTestApp) finds the same + Flutter SDK we provisioned with (without `fvm`) and so the native build + bundles the app's site-packages. + """ + env = {**os.environ, **cmd.env} + if cmd.flutter_exe: + flutter_bin = str(Path(cmd.flutter_exe).parent) + env["PATH"] = os.pathsep.join([flutter_bin, env.get("PATH", "")]) + # Hand the resolved Flutter executable (e.g. `flutter.bat` on Windows) to + # FletTestApp: it spawns `flutter test` with create_subprocess_exec, which + # on Windows can't resolve a bare "flutter" (no PATHEXT lookup). + env["FLET_TEST_FLUTTER_EXE"] = str(cmd.flutter_exe) + env["FLET_TEST_DISABLE_FVM"] = "1" + # Same serious_python env `flet build` hands its native build, so the app + # `flutter test` builds is bundled identically (incl. SERIOUS_PYTHON_APP → + # a fresh app.zip with a matching-Python main.pyc). + env.update(cmd._serious_python_build_env()) + if getattr(cmd, "flutter_packages_temp_dir", None) is not None: + env["SERIOUS_PYTHON_FLUTTER_PACKAGES"] = str(cmd.flutter_packages_temp_dir) + return env + + +class Command(BaseBuildCommand): + """ + Run Flet integration tests for an app. + + Provisions a Flutter test host from the app (the same pipeline as + `flet build`, in test mode) so the app runs on-device with embedded Python, + then runs pytest. Tests in the `tests/` directory drive the app through the + `flet_app` fixture (find controls by key, tap, take/assert screenshots). + + Detailed usage guide: https://flet.dev/docs/getting-started/integration-testing + """ + + def __init__(self, parser: argparse.ArgumentParser) -> None: + super().__init__(parser) + self.test_platform_name: Optional[str] = None + self.device_id: Optional[str] = None + self.tests_dir = "tests" + self.update_goldens = False + self.pytest_args: list[str] = [] + self.flutter_test_host: Optional[str] = None + + def add_arguments(self, parser: argparse.ArgumentParser) -> None: + # `platform` is a positional, like `flet debug`. Register it first, then + # the inherited build args (which add the `python_app_path` positional), + # then our trailing `pytest_args` REMAINDER positional. + parser.add_argument( + "platform", + type=str.lower, + nargs="?", + choices=["macos", "linux", "windows", "ios", "android"], + help="The target platform to run the tests on " + "(defaults to the current desktop platform).", + ) + super().add_arguments(parser) + parser.add_argument( + "--device-id", + "-d", + dest="device_id", + help="Device ID to run the tests on (for iOS and Android).", + ) + parser.add_argument( + "--tests-dir", + dest="tests_dir", + default="tests", + help="Directory with the integration tests, relative to the app " + "directory (default: tests).", + ) + parser.add_argument( + "--update-goldens", + "-u", + dest="update_goldens", + action="store_true", + default=False, + help="Capture/update golden screenshots instead of comparing.", + ) + parser.add_argument( + "--flutter-test-host", + dest="flutter_test_host", + default=None, + help="Use an already-provisioned Flutter test host directory " + "instead of building one (e.g. a CI-cached host).", + ) + parser.add_argument( + "-k", + dest="pytest_keyword", + default=None, + help="Only run tests matching the given pytest keyword expression " + "(passed through to pytest -k).", + ) + + def handle(self, options: argparse.Namespace) -> None: + super().handle(options) + # `flet test` never produces a packaged artifact; build output dir is + # irrelevant (mirrors `flet debug`). + self.options.output_dir = None + + self.test_platform_name = options.platform or _default_desktop_platform() + self.target_platform = TEST_PLATFORMS[self.test_platform_name][ + "target_platform" + ] + self.device_id = ( + options.device_id or TEST_PLATFORMS[self.test_platform_name]["device_id"] + ) + self.tests_dir = options.tests_dir + self.update_goldens = options.update_goldens + self.flutter_test_host = options.flutter_test_host + + self.pytest_args = [] + if options.pytest_keyword: + self.pytest_args += ["-k", options.pytest_keyword] + + if self.test_platform_name in ("android", "ios") and not self.device_id: + console.print( + f"[red]A device id is required for {self.test_platform_name}. " + "Pass it with --device-id (use `flet devices` to list " + "connected devices).[/red]" + ) + sys.exit(1) + + if self.flutter_test_host: + flutter_dir = Path(self.flutter_test_host).resolve() + # Still need python_app_path/env for pytest; run a light init. + self.test_mode = True + self.status = console.status( + "[bold blue]Preparing tests...", spinner="bouncingBall" + ) + with Live(Group(self.status, self.progress), console=console) as self.live: + self.initialize_command() + self.validate_entry_point() + else: + self.status = console.status( + f"[bold blue]Provisioning {self.target_platform} test host...", + spinner="bouncingBall", + ) + with Live(Group(self.status, self.progress), console=console) as self.live: + flutter_dir = _provision_steps(self) + self.update_status("[bold blue]Test host ready. Starting tests...") + + exit_code = self._run_pytest(flutter_dir) + sys.exit(exit_code) + + def _run_pytest(self, flutter_dir: Path) -> int: + assert self.python_app_path + env = _flutter_path_env(self) + env["FLET_TEST_DEVICE_MODE"] = "1" + env["FLET_TEST_FLUTTER_APP_DIR"] = str(flutter_dir) + env["FLET_TEST_PLATFORM"] = self.test_platform_name or "" + if self.device_id: + env["FLET_TEST_DEVICE"] = self.device_id + if self.update_goldens: + env["FLET_TEST_GOLDEN"] = "1" + + pytest_args = list(self.pytest_args) + if self.verbose > 0: + # Stream the Flutter test process output (compilation/launch + # progress) and don't let pytest capture it. + env["FLET_TEST_VERBOSE"] = "1" + pytest_args += ["-s"] + + tests_path = Path(self.python_app_path) / self.tests_dir + args = [sys.executable, "-m", "pytest", str(tests_path), *pytest_args] + console.log(f"Running tests: {' '.join(args)}") + return subprocess.run(args, cwd=str(self.python_app_path), env=env).returncode + + +def provision_test_host( + project_dir: str, + platform_name: Optional[str] = None, + device_id: Optional[str] = None, + verbose: int = 0, +) -> Path: + """ + Provision (or reuse the cached) Flutter test host for the app at + `project_dir` and return its directory. Also wires up the current process + environment (PATH to the resolved Flutter SDK, FLET_TEST_DISABLE_FVM) so a + subsequent `flutter test` launched by FletTestApp works. + + Called by the pytest plugin so that `uv run pytest` works without first + running `flet test`. Cached by the build pipeline's input hash, so warm + runs are fast. + """ + parser = argparse.ArgumentParser() + cmd = Command(parser) + plat = platform_name or _default_desktop_platform() + + argv = [plat] + if device_id: + argv += ["-d", device_id] + options = parser.parse_args(argv) + options.python_app_path = str(Path(project_dir).resolve()) + options.output_dir = None + options.verbose = verbose + options.assume_yes = True + + cmd.options = options + cmd.no_rich_output = cmd.no_rich_output or options.no_rich_output + cmd.verbose = verbose + cmd.assume_yes = True + cmd.test_platform_name = plat + cmd.target_platform = TEST_PLATFORMS[plat]["target_platform"] + + cmd.status = console.status( + f"[bold blue]Provisioning {cmd.target_platform} test host...", + spinner="bouncingBall", + ) + with Live(Group(cmd.status, cmd.progress), console=console) as cmd.live: + flutter_dir = _provision_steps(cmd) + + # Make the SDK discoverable for the FletTestApp-spawned `flutter test` and + # propagate the SERIOUS_PYTHON_* vars so the native build bundles + # site-packages into the app. + env = _flutter_path_env(cmd) + for key in _TEST_ENV_KEYS: + if key in env: + os.environ[key] = env[key] + return flutter_dir diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/test_host.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/test_host.py new file mode 100644 index 0000000000..aa21af73d9 --- /dev/null +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/test_host.py @@ -0,0 +1,11 @@ +""" +Provisioning entry point for the Flet integration-test host. + +`provision_test_host` is defined in `flet_cli.commands.test` (alongside the +`flet test` command) and re-exported here so the flet pytest plugin can import +it from a stable, command-agnostic module without pulling in argparse wiring. +""" + +from flet_cli.commands.test import provision_test_host + +__all__ = ["provision_test_host"] diff --git a/sdk/python/packages/flet-cli/src/flet_cli/utils/android.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/android.py new file mode 100644 index 0000000000..256a97d796 --- /dev/null +++ b/sdk/python/packages/flet-cli/src/flet_cli/utils/android.py @@ -0,0 +1,53 @@ +"""Helpers for Android-specific build configuration.""" + +ANDROID_ARCH_TO_FLUTTER_TARGET_PLATFORM = { + "armeabi-v7a": "android-arm", + "arm64-v8a": "android-arm64", + "x86_64": "android-x64", +} +"""Android ABIs supported by Flutter, mapped to `flutter build --target-platform` +values. Order is meaningful: it defines the order in which +generated artifacts (e.g. Gradle packaging excludes) list ABIs.""" + + +def flutter_target_platforms(archs: list[str]) -> list[str]: + """ + Map Android ABI names to `flutter build --target-platform` values. + + Args: + archs: Android ABI names, e.g. `["arm64-v8a"]`. + + Returns: + The corresponding Flutter target platforms, e.g. `["android-arm64"]`. + + Raises: + ValueError: If any ABI is not supported by Flutter. + """ + + platforms = [] + for arch in archs: + platform = ANDROID_ARCH_TO_FLUTTER_TARGET_PLATFORM.get(arch) + if platform is None: + raise ValueError( + f"Unsupported Android architecture: {arch!r}. " + f"Supported: {', '.join(ANDROID_ARCH_TO_FLUTTER_TARGET_PLATFORM)}." + ) + platforms.append(platform) + return platforms + + +def excluded_android_abis(archs: list[str]) -> list[str]: + """ + Return the supported Android ABIs not requested in `archs`. + + Args: + archs: Requested Android ABI names; an empty list means "all ABIs" + and yields no exclusions. + + Returns: + ABIs to exclude from the generated artifact. + """ + + if not archs: + return [] + return [abi for abi in ANDROID_ARCH_TO_FLUTTER_TARGET_PLATFORM if abi not in archs] diff --git a/sdk/python/packages/flet-cli/src/flet_cli/utils/distros.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/distros.py index cdce7d1426..c5b500ed5d 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/utils/distros.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/utils/distros.py @@ -7,14 +7,17 @@ from rich.progress import Progress -def download_with_progress(url, dest_path, progress: Optional[Progress] = None): +def download_with_progress( + url, dest_path, progress: Optional[Progress] = None, description="Downloading..." +): """Downloads a file with a progress bar.""" with urllib.request.urlopen(url) as response: - total_size = int(response.info().get("Content-Length").strip()) + content_length = response.headers.get("Content-Length") + total_size = int(content_length) if content_length else None block_size = 8192 # 8 KB chunks if progress: - task = progress.add_task("Downloading...", total=total_size) + task = progress.add_task(description, total=total_size) with open(dest_path, "wb") as out_file: while chunk := response.read(block_size): out_file.write(chunk) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/utils/flutter.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/flutter.py index 92e143d548..8d8c1394d9 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/utils/flutter.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/utils/flutter.py @@ -1,6 +1,7 @@ import os import platform import shutil +import subprocess from pathlib import Path from typing import Optional @@ -9,6 +10,16 @@ from flet_cli.utils.distros import download_with_progress, extract_with_progress +FLUTTER_GIT_URL = "https://github.com/flutter/flutter.git" + + +def is_arm64_linux() -> bool: + """Whether the host is arm64 Linux, which has no prebuilt Flutter SDK.""" + return platform.system() == "Linux" and platform.machine().lower() in ( + "aarch64", + "arm64", + ) + def get_flutter_url(version): """Determines the Flutter archive URL based on the platform.""" @@ -65,26 +76,45 @@ def install_flutter(version, log, progress: Optional[Progress] = None): home_dir = Path.home() if not os.path.exists(install_dir): - url = get_flutter_url(version) - archive_name = os.path.basename(url) - archive_path = os.path.join(home_dir, archive_name) - - log(f"Downloading Flutter {version} from {url}...") - download_with_progress(url, archive_path, progress=progress) - - log(f"Extracting Flutter to {install_dir}...") - temp_extract_dir = os.path.join(home_dir, "flutter", f"{version}_temp") - os.makedirs(temp_extract_dir, exist_ok=True) - - extract_with_progress(archive_path, temp_extract_dir, progress=progress) - - # Move extracted 'flutter' directory contents to final destination - flutter_root = os.path.join(temp_extract_dir, "flutter") - shutil.move(flutter_root, install_dir) - - # Clean up - os.remove(archive_path) - shutil.rmtree(temp_extract_dir) + if is_arm64_linux(): + # Flutter publishes no prebuilt arm64 Linux SDK (its releases are + # x64-only), so clone the SDK at the version tag, then precache its + # engine artifacts. The prebuilt archives ship these under + # `bin/cache` (incl. the `sky_engine` package that `dart run` / + # `flutter build` resolve); a bare clone does not, so without the + # precache pub solving fails with "could not find package sky_engine". + # The downloaded artifacts are arch-appropriate (mirrors fvm/git). + os.makedirs(os.path.dirname(install_dir), exist_ok=True) + log(f"Cloning Flutter {version} for arm64 Linux from {FLUTTER_GIT_URL}...") + subprocess.run( + ["git", "clone", "--depth", "1", "--branch", version] + + [FLUTTER_GIT_URL, install_dir], + check=True, + ) + log(f"Precaching Flutter {version} engine artifacts...") + flutter_exe = os.path.join(install_dir, "bin", "flutter") + subprocess.run([flutter_exe, "precache", "--linux"], check=True) + else: + url = get_flutter_url(version) + archive_name = os.path.basename(url) + archive_path = os.path.join(home_dir, archive_name) + + log(f"Downloading Flutter {version} from {url}...") + download_with_progress(url, archive_path, progress=progress) + + log(f"Extracting Flutter to {install_dir}...") + temp_extract_dir = os.path.join(home_dir, "flutter", f"{version}_temp") + os.makedirs(temp_extract_dir, exist_ok=True) + + extract_with_progress(archive_path, temp_extract_dir, progress=progress) + + # Move extracted 'flutter' directory contents to final destination + flutter_root = os.path.join(temp_extract_dir, "flutter") + shutil.move(flutter_root, install_dir) + + # Clean up + os.remove(archive_path) + shutil.rmtree(temp_extract_dir) log(f"Flutter {version} installed at {install_dir}.") return install_dir diff --git a/sdk/python/packages/flet/src/flet/utils/linux_deps.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/linux_deps.py similarity index 100% rename from sdk/python/packages/flet/src/flet/utils/linux_deps.py rename to sdk/python/packages/flet-cli/src/flet_cli/utils/linux_deps.py diff --git a/sdk/python/packages/flet-cli/src/flet_cli/utils/pyodide.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/pyodide.py new file mode 100644 index 0000000000..4479dd0c51 --- /dev/null +++ b/sdk/python/packages/flet-cli/src/flet_cli/utils/pyodide.py @@ -0,0 +1,140 @@ +"""Download + cache the Pyodide runtime that matches a Python release. + +`pyodide-core-.tar.bz2` carries the runtime (pyodide.js / asm.wasm / +python_stdlib.zip / pyodide-lock.json / ...) but not the micropip+packaging +wheels that `loadPackage("micropip")` needs at runtime. We supplement the core +tarball with those two wheels (filenames resolved from pyodide-lock.json) so +the bundle works in `--no-cdn` deployments too. +""" + +from __future__ import annotations + +import json +import shutil +import tarfile +from collections.abc import Iterable +from pathlib import Path + +from rich.progress import Progress + +from flet_cli.utils.distros import download_with_progress +from flet_cli.utils.template_cache import get_cache_root + +_GITHUB_TARBALL_URL = "https://github.com/pyodide/pyodide/releases/download/{version}/pyodide-core-{version}.tar.bz2" +_CDN_FILE_URL = "https://cdn.jsdelivr.net/pyodide/v{version}/full/{filename}" + +# Wheels that pyodide loads from disk/CDN at runtime via loadPackage(). +# Without them in dest_dir, `--no-cdn` builds break. +_EXTRA_RUNTIME_PACKAGES = ("micropip", "packaging") + + +def _flet_cache_root() -> Path: + return get_cache_root() / "pyodide" + + +def _download(url: str, dest: Path, progress: Progress, description: str) -> None: + dest.parent.mkdir(parents=True, exist_ok=True) + download_with_progress(url, str(dest), progress, description=description) + + +def _resolve_runtime_wheel_filenames( + lock_json: Path, package_names: Iterable[str] +) -> list[str]: + with lock_json.open("r", encoding="utf-8") as f: + lock = json.load(f) + wanted = set(package_names) + filenames: list[str] = [] + for pkg in lock.get("packages", {}).values(): + name = pkg.get("name") + fn = pkg.get("file_name") + if name in wanted and isinstance(fn, str) and fn.endswith(".whl"): + filenames.append(fn) + return filenames + + +def _populate_cache(version: str, cache_dir: Path) -> None: + """Fetch core tarball + supplementary wheels into `cache_dir`.""" + + cache_dir.mkdir(parents=True, exist_ok=True) + tarball = cache_dir / f"pyodide-core-{version}.tar.bz2" + + with Progress(transient=True) as progress: + _download( + _GITHUB_TARBALL_URL.format(version=version), + tarball, + progress, + f"Downloading Pyodide {version}...", + ) + with tarfile.open(tarball, "r:bz2") as tf: + # The core tarball nests everything under a top-level "pyodide/" dir. + # Strip that prefix as we extract so files land directly in cache_dir. + for member in tf.getmembers(): + if member.isdir(): + continue + rel = Path(member.name) + if rel.parts and rel.parts[0] == "pyodide": + rel = Path(*rel.parts[1:]) + if not rel.parts: + continue + target = cache_dir / rel + target.parent.mkdir(parents=True, exist_ok=True) + extracted = tf.extractfile(member) + if extracted is None: + continue + with extracted as src, target.open("wb") as dst: + shutil.copyfileobj(src, dst) + tarball.unlink(missing_ok=True) + + lock_json = cache_dir / "pyodide-lock.json" + if not lock_json.exists(): + raise RuntimeError(f"pyodide-core-{version} did not contain pyodide-lock.json") + with Progress(transient=True) as progress: + for wheel in _resolve_runtime_wheel_filenames( + lock_json, _EXTRA_RUNTIME_PACKAGES + ): + wheel_path = cache_dir / wheel + if wheel_path.exists(): + continue + _download( + _CDN_FILE_URL.format(version=version, filename=wheel), + wheel_path, + progress, + f"Downloading {wheel}...", + ) + + +def _cache_matches_version(cache_dir: Path, version: str) -> bool: + lock_json = cache_dir / "pyodide-lock.json" + if not lock_json.exists(): + return False + try: + with lock_json.open("r", encoding="utf-8") as f: + lock = json.load(f) + except (OSError, json.JSONDecodeError): + return False + return lock.get("info", {}).get("version") == version + + +def ensure_pyodide(version: str, dest_dir: Path) -> None: + """Ensure a working Pyodide runtime of `version` exists at `dest_dir`. + + Cached per version under `~/.flet/cache/pyodide//`. Idempotent: if + `dest_dir/pyodide-lock.json` already pins `version`, no work is done. + """ + + dest_dir = Path(dest_dir) + if _cache_matches_version(dest_dir, version): + return + + cache_dir = _flet_cache_root() / version + if not _cache_matches_version(cache_dir, version): + # Wipe a partial cache from a prior failed run. + if cache_dir.exists(): + shutil.rmtree(cache_dir) + _populate_cache(version, cache_dir) + + dest_dir.mkdir(parents=True, exist_ok=True) + for src in cache_dir.iterdir(): + if not src.is_file(): + continue + shutil.copy2(src, dest_dir / src.name) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/utils/python_versions.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/python_versions.py new file mode 100644 index 0000000000..5bcfefb5dd --- /dev/null +++ b/sdk/python/packages/flet-cli/src/flet_cli/utils/python_versions.py @@ -0,0 +1,213 @@ +"""Supported Python versions for `flet build` / `flet publish`. + +The set of bundlable Python releases — and the matching CPython-standalone + +Pyodide artifacts — is defined by python-build's date-keyed ``manifest.json``, +the single source of truth shared with serious_python. This module pins one +python-build release date and fetches that release's manifest (cached under +``~/.flet/cache``, immutable per date), so nothing here is hand-mirrored. + +Pin (``PYTHON_BUILD_RELEASE_DATE``) overrides, for dev/CI: +* ``FLET_PYTHON_BUILD_RELEASE_DATE`` — use a different published release date. +* ``FLET_PYTHON_BUILD_MANIFEST`` — read a local ``manifest.json`` instead of + fetching (mirrors serious_python's ``gen_version_tables --manifest``). +""" + +import json +import os +import shutil +import urllib.request +from dataclasses import dataclass +from functools import lru_cache +from typing import Callable, Optional + +from packaging.specifiers import SpecifierSet +from packaging.version import Version + +from flet_cli.utils.template_cache import get_cache_root + +# python-build release this flet pins. Keep in sync with serious_python's +# `pythonReleaseDate` (lib/src/python_versions.dart) — both should track the +# same python-build release. +PYTHON_BUILD_RELEASE_DATE = "20260714" + +RELEASE_DATE_ENV = "FLET_PYTHON_BUILD_RELEASE_DATE" +MANIFEST_PATH_ENV = "FLET_PYTHON_BUILD_MANIFEST" + +_MANIFEST_URL = ( + "https://github.com/flet-dev/python-build/releases/download/{date}/manifest.json" +) + + +@dataclass(frozen=True) +class PythonRelease: + short: str + standalone: str + pyodide: str + # Android ABIs python-build publishes distributions for this minor + # (per the manifest's per-minor `android_abis`). + android_abis: tuple[str, ...] + # When True, this release is supported via `--python-version` (and an + # explicit `requires-python = "==X.Y.*"` specifier) but is not picked + # automatically by the default or by open-ended `requires-python` + # specifiers like `>=3.14`. Use for beta CPython lines. + prerelease: bool + + +def _resolve_release_date() -> str: + return os.environ.get(RELEASE_DATE_ENV) or PYTHON_BUILD_RELEASE_DATE + + +def _load_manifest() -> dict: + """Return the python-build manifest as a dict. + + Reads ``$FLET_PYTHON_BUILD_MANIFEST`` if set; otherwise fetches the pinned + release's ``manifest.json`` (cached immutably under + ``~/.flet/cache/python-build``). Falls back to a present cache when the + network is unavailable; raises with an actionable message if neither the + network nor a cache can supply it. + """ + local = os.environ.get(MANIFEST_PATH_ENV) + if local: + with open(local, encoding="utf-8") as f: + return json.load(f) + + date = _resolve_release_date() + url = _MANIFEST_URL.format(date=date) + cache_path = get_cache_root() / "python-build" / f"manifest-{date}.json" + + if not (cache_path.exists() and cache_path.stat().st_size > 0): + cache_path.parent.mkdir(parents=True, exist_ok=True) + tmp_path = cache_path.with_suffix(cache_path.suffix + ".tmp") + try: + with urllib.request.urlopen(url) as resp, open(tmp_path, "wb") as out: + shutil.copyfileobj(resp, out) + out.flush() + os.fsync(out.fileno()) + os.replace(tmp_path, cache_path) + except BaseException as e: + tmp_path.unlink(missing_ok=True) + if not (cache_path.exists() and cache_path.stat().st_size > 0): + raise RuntimeError( + f"Could not obtain the Python build manifest for release " + f"{date} from {url}: {e}. Check your network connection, or " + f"set ${MANIFEST_PATH_ENV} to a local manifest.json." + ) from e + + with cache_path.open(encoding="utf-8") as f: + return json.load(f) + + +@lru_cache(maxsize=1) +def _load_data() -> tuple[tuple[PythonRelease, ...], str]: + manifest = _load_manifest() + releases = tuple( + PythonRelease( + short=short, + standalone=info["full_version"], + pyodide=info["pyodide_version"], + android_abis=tuple(info["android_abis"]), + prerelease=bool(info.get("prerelease", False)), + ) + for short, info in manifest["pythons"].items() + ) + return releases, manifest["default_python_version"] + + +def get_supported_python_versions() -> list[PythonRelease]: + return list(_load_data()[0]) + + +def get_default_python_version() -> str: + return _load_data()[1] + + +def get_release(short: str) -> Optional[PythonRelease]: + for r in get_supported_python_versions(): + if r.short == short: + return r + return None + + +def supported_short_versions() -> list[str]: + return [r.short for r in get_supported_python_versions()] + + +class UnsupportedPythonVersionError(ValueError): + pass + + +def resolve_python_version( + cli_arg: Optional[str], + get_pyproject: Optional[Callable[[Optional[str]], object]] = None, +) -> PythonRelease: + """Resolve the Python release to bundle. + + Priority: `--python-version` CLI arg → `[project].requires-python` (parsed + as a PEP 440 SpecifierSet, highest matching supported short version wins) → + the manifest's default. + + Raises `UnsupportedPythonVersionError` if the CLI arg names an unsupported + version, or if `requires-python` excludes every supported version. + """ + + supported = get_supported_python_versions() + + if cli_arg: + release = get_release(cli_arg) + if release is None: + raise UnsupportedPythonVersionError( + f"Unsupported Python version: {cli_arg!r}. " + f"Supported: {', '.join(supported_short_versions())}." + ) + return release + + if get_pyproject is not None: + requires = get_pyproject("project.requires-python") + if isinstance(requires, str) and requires.strip(): + try: + spec = SpecifierSet(requires) + except Exception: + spec = None + if spec is not None: + # Prefer the highest stable row that satisfies the + # specifier, matched against the full standalone version so + # e.g. `>=3.13` matches the 3.13.x row, not just + # `Version("3.13")`. Pre-release rows are skipped here so + # `>=3.14` never silently jumps to a beta CPython line. + stable_matching = [ + r + for r in supported + if not r.prerelease and Version(r.standalone) in spec + ] + if stable_matching: + return max(stable_matching, key=lambda r: Version(r.standalone)) + + # Fall back: match pre-release rows against the short + # version (e.g. `3.15`) rather than the standalone (e.g. + # `3.15.0a2`). Without this, `>=3.15` would skip the 3.15 + # alpha because `3.15.0a2` sorts before `3.15.0`. Comparing + # by short version expresses "this Python line is supported" + # — which is what the registry represents — and preserves + # the "explicit opt-in" path for beta lines without exposing + # a CLI flag. + spec_with_pre = SpecifierSet(requires, prereleases=True) + prerelease_matching = [ + r + for r in supported + if r.prerelease and Version(r.short) in spec_with_pre + ] + if prerelease_matching: + return max( + prerelease_matching, + key=lambda r: Version(r.short), + ) + + raise UnsupportedPythonVersionError( + f"`requires-python = {requires!r}` does not match any " + f"supported Python version " + f"({', '.join(supported_short_versions())})." + ) + + fallback = get_release(get_default_python_version()) + assert fallback is not None + return fallback diff --git a/sdk/python/packages/flet-cli/tests/test_clean.py b/sdk/python/packages/flet-cli/tests/test_clean.py new file mode 100644 index 0000000000..32a98dd793 --- /dev/null +++ b/sdk/python/packages/flet-cli/tests/test_clean.py @@ -0,0 +1,53 @@ +import pytest + +from flet_cli.cli import get_parser + + +def _run_clean(args): + """Parse a `flet clean ...` invocation and run its handler.""" + parser = get_parser() + parsed = parser.parse_args(["clean", *args]) + parsed.handler(parsed) + + +def test_clean_deletes_existing_build_dir(tmp_path): + """`flet clean` removes the app's `build` directory and its contents.""" + build_dir = tmp_path / "build" + (build_dir / "flutter").mkdir(parents=True) + (build_dir / "flutter" / "pubspec.yaml").write_text("name: app\n") + + _run_clean([str(tmp_path)]) + + assert not build_dir.exists() + # the app directory itself is left untouched + assert tmp_path.is_dir() + + +def test_clean_is_noop_when_no_build_dir(tmp_path): + """`flet clean` exits successfully when there is no `build` directory.""" + _run_clean([str(tmp_path)]) + + assert not (tmp_path / "build").exists() + + +def test_clean_respects_path_argument(tmp_path): + """Only the targeted app's `build` directory is deleted.""" + app_a = tmp_path / "app_a" + app_b = tmp_path / "app_b" + (app_a / "build").mkdir(parents=True) + (app_b / "build").mkdir(parents=True) + + _run_clean([str(app_a)]) + + assert not (app_a / "build").exists() + assert (app_b / "build").exists() + + +def test_clean_errors_on_missing_app_path(tmp_path): + """`flet clean` exits with a non-zero code when the app path does not exist.""" + missing = tmp_path / "does-not-exist" + + with pytest.raises(SystemExit) as exc_info: + _run_clean([str(missing)]) + + assert exc_info.value.code == 1 diff --git a/sdk/python/packages/flet-cli/tests/test_python_versions.py b/sdk/python/packages/flet-cli/tests/test_python_versions.py new file mode 100644 index 0000000000..624e623791 --- /dev/null +++ b/sdk/python/packages/flet-cli/tests/test_python_versions.py @@ -0,0 +1,111 @@ +"""Tests for manifest-backed Python version resolution. + +These run fully offline: `FLET_PYTHON_BUILD_MANIFEST` points the loader at a +local fixture manifest instead of fetching python-build's release asset. +""" + +import json + +import pytest + +from flet_cli.utils import python_versions as pv + +_FIXTURE_MANIFEST = { + "release": "20260614", + "default_python_version": "3.14", + "dart_bridge_version": "1.2.3", + "pythons": { + "3.12": { + "full_version": "3.12.13", + "pyodide_version": "0.27.7", + "android_abis": ["arm64-v8a", "x86_64", "armeabi-v7a"], + "prerelease": False, + }, + "3.13": { + "full_version": "3.13.14", + "pyodide_version": "0.29.4", + "android_abis": ["arm64-v8a", "x86_64"], + "prerelease": False, + }, + "3.14": { + "full_version": "3.14.6", + "pyodide_version": "314.0.0", + "android_abis": ["arm64-v8a", "x86_64"], + "prerelease": False, + }, + # A pre-release line: opt-in only, never auto-resolved. + "3.15": { + "full_version": "3.15.0a1", + "pyodide_version": "315.0.0", + "android_abis": ["arm64-v8a", "x86_64"], + "prerelease": True, + }, + }, +} + + +@pytest.fixture(autouse=True) +def fixture_manifest(tmp_path, monkeypatch): + manifest_path = tmp_path / "manifest.json" + manifest_path.write_text(json.dumps(_FIXTURE_MANIFEST), encoding="utf-8") + monkeypatch.setenv(pv.MANIFEST_PATH_ENV, str(manifest_path)) + pv._load_data.cache_clear() + yield + pv._load_data.cache_clear() + + +def test_default_and_supported_versions(): + assert pv.get_default_python_version() == "3.14" + assert pv.supported_short_versions() == ["3.12", "3.13", "3.14", "3.15"] + + +def test_release_fields_mapped_from_manifest(): + r = pv.get_release("3.14") + assert r is not None + assert (r.short, r.standalone, r.pyodide, r.prerelease) == ( + "3.14", + "3.14.6", + "314.0.0", + False, + ) + assert pv.get_release("3.99") is None + + +def test_resolve_default_when_no_arg(): + assert pv.resolve_python_version(None).short == "3.14" + + +def test_resolve_explicit_cli_arg(): + assert pv.resolve_python_version("3.12").short == "3.12" + + +def test_resolve_unsupported_cli_arg_raises(): + with pytest.raises(pv.UnsupportedPythonVersionError): + pv.resolve_python_version("3.99") + + +def test_resolve_from_requires_python_picks_highest_stable(): + get_pyproject = lambda key: ">=3.13" # noqa: E731 + assert pv.resolve_python_version(None, get_pyproject).short == "3.14" + + +def test_resolve_from_requires_python_exact(): + get_pyproject = lambda key: "==3.12.*" # noqa: E731 + assert pv.resolve_python_version(None, get_pyproject).short == "3.12" + + +def test_requires_python_skips_prerelease_for_open_specifier(): + # `>=3.14` must not silently jump to the 3.15 pre-release line. + get_pyproject = lambda key: ">=3.14" # noqa: E731 + assert pv.resolve_python_version(None, get_pyproject).short == "3.14" + + +def test_requires_python_opts_into_prerelease_explicitly(): + get_pyproject = lambda key: "==3.15.*" # noqa: E731 + assert pv.resolve_python_version(None, get_pyproject).short == "3.15" + + +def test_requires_python_no_match_raises(): + get_pyproject = lambda key: ">=3.99" # noqa: E731 + with pytest.raises(pv.UnsupportedPythonVersionError): + pv.resolve_python_version(None, get_pyproject) diff --git a/sdk/python/packages/flet-desktop/pyproject.toml b/sdk/python/packages/flet-desktop/pyproject.toml index bc8ca4e9bb..104c90fdf9 100644 --- a/sdk/python/packages/flet-desktop/pyproject.toml +++ b/sdk/python/packages/flet-desktop/pyproject.toml @@ -7,7 +7,8 @@ license = "Apache-2.0" readme = "README.md" requires-python = ">=3.10" dependencies = [ - "flet" + "flet", + "rich >=13.0.0" ] [project.urls] diff --git a/sdk/python/packages/flet-desktop/src/flet_desktop/__init__.py b/sdk/python/packages/flet-desktop/src/flet_desktop/__init__.py index 3a62d0a61d..94b3d1c250 100644 --- a/sdk/python/packages/flet-desktop/src/flet_desktop/__init__.py +++ b/sdk/python/packages/flet-desktop/src/flet_desktop/__init__.py @@ -14,6 +14,8 @@ import zipfile from pathlib import Path +from rich.progress import Progress + import flet_desktop import flet_desktop.version from flet.utils import ( @@ -174,6 +176,19 @@ def __get_client_storage_dir(): ) +def __download_with_progress(url, dest_path, description): + """Download a file to dest_path, showing a rich progress bar.""" + with urllib.request.urlopen(url) as response, Progress(transient=True) as progress: + content_length = response.headers.get("Content-Length") + task = progress.add_task( + description, total=int(content_length) if content_length else None + ) + with open(dest_path, "wb") as f: + while chunk := response.read(8192): + f.write(chunk) + progress.update(task, advance=len(chunk)) + + def __download_flet_client(file_name): """ Download a Flet client archive from GitHub Releases. @@ -195,7 +210,7 @@ def __download_flet_client(file_name): logger.info(f"Downloading Flet v{ver} from {flet_url}") print(f"Preparing Flet v{ver} for the first use. This is a one-time operation...") temp_arch = Path(tempfile.gettempdir()).joinpath(f"{file_name}.{random_string(10)}") - urllib.request.urlretrieve(flet_url, str(temp_arch)) + __download_with_progress(flet_url, str(temp_arch), f"Downloading Flet v{ver}...") return str(temp_arch) diff --git a/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/pubspec.yaml b/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/pubspec.yaml index 1ca7a12bdf..83045edaf0 100644 --- a/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/pubspec.yaml +++ b/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: sdk: flutter collection: ^1.16.0 - torch_light: 1.1.0 + torch_light: 2.0.0 flet: path: ../../../../../../../packages/flet diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/pubspec.yaml b/sdk/python/packages/flet-map/src/flutter/flet_map/pubspec.yaml index 16d246490d..6573bafc11 100644 --- a/sdk/python/packages/flet-map/src/flutter/flet_map/pubspec.yaml +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: collection: ^1.16.0 flutter_map: ^8.3.0 - flutter_map_animations: 0.9.0 + flutter_map_animations: 0.10.0 latlong2: 0.9.1 flet: diff --git a/sdk/python/packages/flet-mcp/.gitignore b/sdk/python/packages/flet-mcp/.gitignore new file mode 100644 index 0000000000..5a3d1ff640 --- /dev/null +++ b/sdk/python/packages/flet-mcp/.gitignore @@ -0,0 +1,6 @@ +# Build artifacts (generated by `flet mcp build`) +src/flet_mcp/data/api.json +src/flet_mcp/data/mcp.db + +# Un-ignore the build subpackage (matched by sdk/python/.gitignore "build/" rule) +!src/flet_mcp/build/ diff --git a/sdk/python/packages/flet-mcp/README.md b/sdk/python/packages/flet-mcp/README.md new file mode 100644 index 0000000000..0a84cee946 --- /dev/null +++ b/sdk/python/packages/flet-mcp/README.md @@ -0,0 +1,196 @@ +# flet-mcp + +MCP (Model Context Protocol) server that gives LLM agents access to Flet examples, documentation, and API reference. + +## Installation + +```bash +pip install flet-mcp +``` + +## Building the data files + +The MCP server reads a Griffe-introspected `api.json` and (optionally) a +SQLite index of examples and docs. Build them from inside the flet SDK +workspace so every Flet extension package (`flet-audio`, `flet-map`, …) is +importable — the workspace declares them all as members, but you need the +`mcp-build` dependency group to pick up the build-time deps (`markdownify`, +`griffe`): + +```bash +cd sdk/python +uv sync --group mcp-build +uv run flet mcp build # api.json only +uv run flet mcp build --examples ./examples # add examples index +``` + +The icon search metadata (`data/icons.json`) is a *committed* file, not a +build product — it is generated from Google's fonts.google.com icon +metadata (names, synonym tags, popularity; Apache-2.0, the same data that +powers the fonts.google.com icon search) and only changes when Google +ships new icons. Refresh it with: + +```bash +uv run python -m flet_mcp.build.icons +``` + +> **Docs index is currently deferred.** The `--docs` flag still expects a mkdocs +> `search_index.json`, which the site no longer produces after the migration to +> Docusaurus + Algolia. The `DOCS` tool group stays off by default; rebuilding +> docs search against Docusaurus is tracked as follow-up work. + +Running the build from elsewhere (a downstream project's venv that only +installs core `flet`) works too, but the resulting `api.json` will be missing +controls from every extension package not installed in that venv — the +indexer logs a "Failed to load" line per missing package and skips it. + +## Usage + +### Start the MCP server + +```bash +# stdio transport (default, for use with Claude Desktop, Cursor, etc.) +flet mcp + +# HTTP transport +flet mcp --transport streamable-http --port 8000 +``` + +### Configure in Claude Desktop + +Add to your `claude_desktop_config.json`: + +```json +{ + "mcpServers": { + "flet": { + "command": "flet", + "args": ["mcp"] + } + } +} +``` + +### List available tools + +```bash +fastmcp list packages/flet-mcp/src/flet_mcp/server.py +``` + +### Call tools from the command line + +```bash +# Search examples +fastmcp call packages/flet-mcp/src/flet_mcp/server.py search_examples '{"query": "dropdown"}' + +# Get full example code +fastmcp call packages/flet-mcp/src/flet_mcp/server.py get_example '{"example_id": "controls_dropdown_styled"}' + +# Get API reference for any symbol (control, service, type, event, enum) +fastmcp call packages/flet-mcp/src/flet_mcp/server.py get_api '{"name": "TextField"}' + +# Find an icon +fastmcp call packages/flet-mcp/src/flet_mcp/server.py find_icon '{"query": "settings"}' + +# Search large enums +fastmcp call packages/flet-mcp/src/flet_mcp/server.py search_enum_members '{"name": "Icons", "query": "arrow"}' + +# Get CLI help +fastmcp call packages/flet-mcp/src/flet_mcp/server.py get_cli_help '{"command": "run"}' +``` + +### Use with Pydantic AI + +```python +from pydantic_ai import Agent +from pydantic_ai.toolsets import MCPToolset +from flet_mcp import mcp + +agent = Agent("anthropic:claude-sonnet-4-6", toolsets=[MCPToolset(mcp)]) +result = agent.run_sync("Create a Flet app with a login form") +``` + +### Use in-process via a FastMCP client + +The exported `mcp` is a `FastMCP` instance, so a custom agent can talk to it +in-process (no subprocess, no transport) by handing it to a `fastmcp.Client`. +Set the `FLET_MCP_ENABLE_*` env vars before importing `flet_mcp` so the desired +tool groups register. The client deserializes structured results onto `.data`: + +```python +import asyncio +from fastmcp import Client +from flet_mcp import mcp + +async def main(): + async with Client(mcp) as client: + api = (await client.call_tool("get_api", {"name": "TextField"})).data + print(api["kind"], api["package"], len(api["properties"])) + +asyncio.run(main()) +``` + +## Tools + +Tools are organized into groups that can be toggled at server startup. Defaults +focus on the hallucination-reduction starter set: **API** and **icons** are on; +**examples**, **docs**, and **CLI** are off. + +| Group | Default | Tools | +|---|---|---| +| `API` | on | `list_controls`, `get_api`, `get_enum`, `search_enum_members`, `enum_has_member` | +| `ICONS` | on | `find_icon` | +| `EXAMPLES` | off | `search_examples`, `get_example` | +| `DOCS` | off | `search_docs`, `get_doc` | +| `CLI` | off | `get_cli_help` | + +| Tool | Description | +|------|-------------| +| `list_controls` | Browse controls and services, with optional filtering | +| `get_api` | Get the API reference for a class by name — looks across controls, services, dataclass types (ButtonStyle, Padding, ...), and event classes. Async methods are marked `"async": true`; every entry carries a `"package"` field naming the pip-installable source package (`"flet"` = core, anything else needs adding to deps). | +| `get_enum` | Get enum members | +| `search_enum_members` | Search large enums (Icons, CupertinoIcons) | +| `enum_has_member` | Check if an enum value exists | +| `find_icon` | Search Material and Cupertino icons by keyword | +| `search_examples` | Search example projects by keyword | +| `get_example` | Get full source code for an example | +| `search_docs` | Search documentation by keyword | +| `get_doc` | Get full content of a doc section | +| `get_cli_help` | Get structured CLI command options | + +### Toggling groups + +Each group is gated by an environment variable read at server startup: + +| Variable | Default | Effect | +|---|---|---| +| `FLET_MCP_ENABLE_API` | `1` | Register the API tool group | +| `FLET_MCP_ENABLE_ICONS` | `1` | Register `find_icon` | +| `FLET_MCP_ENABLE_EXAMPLES` | `0` | Register example search/get tools | +| `FLET_MCP_ENABLE_DOCS` | `0` | Register docs search/get tools | +| `FLET_MCP_ENABLE_CLI` | `0` | Register `get_cli_help` | + +Accepted truthy values: `1`, `true`, `yes` (case-insensitive). The active +groups are also surfaced in the server's `initialize` instructions, so MCP +clients that forward those instructions to the model (e.g. Pydantic AI's +`MCPToolset(..., include_instructions=True)`) keep the model's guidance +in sync with what's actually registered. + +Examples: + +```bash +# Default starter surface (API + icons only) +flet mcp + +# Add examples and docs once their indexes have been built +FLET_MCP_ENABLE_EXAMPLES=1 FLET_MCP_ENABLE_DOCS=1 flet mcp + +# Narrow further: API tools only, drop icons +FLET_MCP_ENABLE_ICONS=0 flet mcp +``` + +Note: enabling `EXAMPLES` only registers the tools — you also need to populate +the SQLite index by running `flet mcp build --examples `. Without an index +the tools register cleanly but return empty results. `DOCS` is deferred (see +"Building the data files" above): the tools register and degrade gracefully to +empty results, but no docs index is built yet. diff --git a/sdk/python/packages/flet-mcp/pyproject.toml b/sdk/python/packages/flet-mcp/pyproject.toml new file mode 100644 index 0000000000..ff7d44d3fd --- /dev/null +++ b/sdk/python/packages/flet-mcp/pyproject.toml @@ -0,0 +1,31 @@ +[project] +name = "flet-mcp" +version = "0.1.0" +description = "Flet MCP server for LLM agents" +authors = [{ name = "Appveyor Systems Inc.", email = "hello@flet.dev" }] +license = "Apache-2.0" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "fastmcp >=2.0.0", +] + +[project.optional-dependencies] +build = [ + "markdownify >=0.14.1", + "griffe >=1.6.2", + "flet", + "flet-cli", +] + +[project.urls] +Homepage = "https://flet.dev" +Repository = "https://github.com/flet-dev/flet" +Documentation = "https://flet.dev/docs" + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.package-data] +flet_mcp = ["data/*"] diff --git a/sdk/python/packages/flet-mcp/src/flet_mcp/__init__.py b/sdk/python/packages/flet-mcp/src/flet_mcp/__init__.py new file mode 100644 index 0000000000..66213528cb --- /dev/null +++ b/sdk/python/packages/flet-mcp/src/flet_mcp/__init__.py @@ -0,0 +1,3 @@ +from flet_mcp.server import mcp + +__all__ = ["mcp"] diff --git a/sdk/python/packages/flet-mcp/src/flet_mcp/api_store.py b/sdk/python/packages/flet-mcp/src/flet_mcp/api_store.py new file mode 100644 index 0000000000..4fcc1b574a --- /dev/null +++ b/sdk/python/packages/flet-mcp/src/flet_mcp/api_store.py @@ -0,0 +1,611 @@ +"""Load and query the Griffe-generated API reference (api.json).""" + +from __future__ import annotations + +import importlib.resources +import json +import re +from pathlib import Path +from typing import Any + +# Member docstrings are trimmed to their first sentence in listings (full +# docstrings often embed multi-paragraph examples — Page's methods alone +# carry ~9k chars of doc text). The full text stays reachable per member +# via `get(name, member=...)`. +_SUMMARY_MAX_CHARS = 160 + +# Controls use properties/events/methods; dataclass types and event +# classes keep their members under "fields" (same entry shape). +_MEMBER_SECTIONS = ("properties", "fields", "events", "methods") + +_MEMBER_KIND = { + "properties": "property", + "fields": "field", + "events": "event", + "methods": "method", +} + +# Buckets in preference order for ambiguous names, and the `kind` value +# stamped onto entries from buckets that don't carry their own. +_BUCKET_RANK = {"controls": 0, "types": 1, "events": 2, "enums": 3} +_BUCKET_KIND = {"types": "type", "events": "event"} + +# Sphinx roles in docstrings (":attr:`style`", ":class:`~flet.Text`") are +# docs-site markup — render them as plain backticked names. +_RST_ROLE = re.compile(r":\w+(?::\w+)?:`~?([^`]+)`") + +# Material icon style-variant suffixes: collapsed in member search so +# ADD / ADD_OUTLINED / ADD_ROUNDED / ADD_SHARP don't spend four result +# slots on one icon. +_STYLE_SUFFIXES = ("_OUTLINED", "_ROUNDED", "_SHARP") + + +def clean_rst(text: str) -> str: + return _RST_ROLE.sub(r"`\1`", text) + + +def first_sentence(text: str, limit: int = _SUMMARY_MAX_CHARS) -> str: + """First sentence (or line) of a docstring, capped at `limit` chars.""" + if not text: + return text + text = clean_rst(text) + head = text.split("\n\n", 1)[0].split("\n", 1)[0] + dot = head.find(". ") + if dot != -1: + head = head[: dot + 1] + if len(head) > limit: + head = head[: limit - 1].rstrip() + "…" + return head + + +def _compact_member(entry: dict[str, Any]) -> dict[str, Any]: + doc = entry.get("docstring") + if not doc: + return entry + summary = first_sentence(doc) + if summary == doc: + return entry + return {**entry, "docstring": summary} + + +# ── Text rendering ────────────────────────────────────────────────────── +# +# The default `get_api` response is signature-style text, not JSON: one +# line per member. Same information, ~44% fewer chars and far fewer +# tokens than the JSON encoding (keys/quoting repeat per member). +# `format="json"` on the tool returns the dict shape instead. + + +def _optional_inner(type_str: str) -> str | None: + """`Optional[X]` -> `X`, else None.""" + if type_str.startswith("Optional[") and type_str.endswith("]"): + return type_str[len("Optional[") : -1] + return None + + +def _event_payload(type_str: str) -> str | None: + """The event object type a handler receives, or None if the type + string doesn't match the known handler shapes (caller falls back to + the raw string — never guess): + + * `Optional[ControlEventHandler[X]]` -> `ControlEvent` + * `Optional[EventHandler[XEvent]]` -> `XEvent` + * `Optional[EventHandler[XEvent[Subject]]]` -> `XEvent` + """ + s = _optional_inner(type_str) or type_str + wrapper, bracket, rest = s.partition("[") + if not bracket or not rest.endswith("]"): + return None + wrapper = wrapper.removeprefix("ft.") + inner = rest[:-1] + if wrapper == "ControlEventHandler": + return "ControlEvent" + if wrapper == "EventHandler": + return inner.split("[", 1)[0] + return None + + +def _fmt_default(default: Any) -> str | None: + if default in (None, "None", ""): + return None + text = str(default) + # Unwrap dataclass `field(...)` declarations — the metadata is + # serialization plumbing, only the actual default value informs. + if text.startswith("field("): + if m := re.search(r"default_factory=(\w+)", text): + factory = m.group(1) + return {"list": "[]", "dict": "{}"}.get(factory, f"{factory}()") + if m := re.search(r"default=([^,)]+)", text): + return _fmt_default(m.group(1).strip()) + return None + return text + + +def _member_line(section: str, entry: dict[str, Any]) -> str: + """One text line for a property/event/method entry (docstring already + compacted by `_compact_member`).""" + name = entry.get("name", "") + if section == "methods": + params = ", ".join(p.get("name", "") for p in entry.get("params") or []) + sig = f"{name}({params})" + ret = entry.get("return_type") + if ret: + sig += f" -> {ret}" + if entry.get("async"): + sig = "async " + sig + elif section == "events": + payload = _event_payload(entry.get("type", "")) + sig = f"{name}({payload})" if payload else f"{name}: {entry.get('type', '')}" + else: + type_str = entry.get("type", "") + inner = _optional_inner(type_str) + sig = f"{name}: {inner}?" if inner else f"{name}: {type_str}" + default = _fmt_default(entry.get("default")) + if default: + sig += f" = {default}" + dep = entry.get("deprecated") + if dep: + reason = dep.get("reason") if isinstance(dep, dict) else str(dep) + sig += f" [DEPRECATED: {reason}]" + doc = entry.get("docstring") + if doc: + sig += f" — {doc}" + return sig + + +def render_text(hit: dict[str, Any]) -> str: + """Render a `get()` result as signature-style text (see the `get_api` + tool docstring for the layout conventions the model relies on).""" + name = hit.get("name", "") + + # Single-member drill-down (`get_api(name, member=...)`). + if "member" in hit and "member_kind" in hit: + entry = hit["member"] + section = next( + (s for s, k in _MEMBER_KIND.items() if k == hit["member_kind"]), + "properties", + ) + lines = [f"{name}.{entry.get('name')} ({hit['member_kind']})"] + lines.append(_member_line(section, {**entry, "docstring": None})) + if entry.get("type"): + lines.append(f"type: {entry['type']}") + if entry.get("docstring"): + lines.append(clean_rst(entry["docstring"])) + return "\n".join(lines) + + lines = [] + header = f"{name} ({hit.get('kind', '')})" + summary = hit.get("summary") or first_sentence(hit.get("docstring") or "") + if summary: + header += f" — {clean_rst(summary)}" + lines.append(header) + dep = hit.get("deprecated") + if dep: + reason = dep.get("reason") if isinstance(dep, dict) else str(dep) + lines.append(f"DEPRECATED: {reason}") + pkg = hit.get("package") + if pkg and pkg != "flet": + lines.append(f"package: {pkg} (add this pip package to the project)") + if hit.get("bases"): + lines.append("bases: " + ", ".join(hit["bases"])) + if hit.get("note"): + lines.append(f"note: {hit['note']}") + + if hit.get("kind") == "large_enum": + lines.append(f"total members: {hit.get('total_members')}") + samples = [ + m.get("name") if isinstance(m, dict) else str(m) + for m in hit.get("sample_members") or [] + ] + lines.append("sample members: " + ", ".join(samples)) + elif hit.get("members") is not None: + lines.append("members:") + for m in hit.get("members") or []: + if isinstance(m, dict): + line = f" {m.get('name')} = {m.get('value')}" + if m.get("docstring"): + line += f" — {first_sentence(m['docstring'])}" + lines.append(line) + else: + lines.append(f" {m}") + + for section in _MEMBER_SECTIONS: + entries = hit.get(section) + if not entries: + continue + lines.append(f"{section}:") + for entry in entries: + lines.append(" " + _member_line(section, entry)) + + # Inherited matches from a query= base-class walk. + for block in hit.get("inherited") or []: + lines.append(f"from {block.get('from')}:") + for section in _MEMBER_SECTIONS: + for entry in block.get(section) or []: + lines.append(" " + _member_line(section, entry)) + return "\n".join(lines) + + +class ApiStore: + """Lazy-loading store for the bundled api.json data. + + The api.json file uses lists for controls/events/types/enums, + each entry having a "name" key. This store builds name-keyed dicts + for fast lookup. + """ + + def __init__(self) -> None: + self._raw: dict[str, Any] | None = None + self._controls: dict[str, dict] | None = None + self._events: dict[str, dict] | None = None + self._types: dict[str, dict] | None = None + self._enums: dict[str, dict] | None = None + self._by_name: dict[str, list[tuple[str, dict]]] | None = None + + def _load(self) -> dict[str, Any]: + if self._raw is None: + ref = importlib.resources.files("flet_mcp").joinpath("data/api.json") + self._raw = json.loads(Path(str(ref)).read_text(encoding="utf-8")) + # Build name-keyed dicts from lists + self._controls = {c["name"]: c for c in self._raw.get("controls", [])} + self._events = {e["name"]: e for e in self._raw.get("events", [])} + self._types = {t["name"]: t for t in self._raw.get("types", [])} + self._enums = {e["name"]: e for e in self._raw.get("enums", [])} + # Names are NOT unique across (or even within) buckets — e.g. + # the Text control vs the canvas Text shape. Keep every entry + # per name so `get` can rank candidates instead of letting the + # last dict insert silently win. + self._by_name = {} + for bucket in ("controls", "types", "events", "enums"): + for e in self._raw.get(bucket, []): + self._by_name.setdefault(e["name"], []).append((bucket, e)) + return self._raw + + def _candidates(self, name: str) -> list[tuple[str, dict[str, Any]]]: + """Entries matching `name`, best first. A dotted name + ("canvas.Text", "flet_map.Camera") filters candidates by module + segment, so shadowed symbols stay reachable. Preference for bare + names: non-canvas modules first (the canvas shapes namespace + shadows core controls like Text/Image), then bucket order.""" + self._load() + if name in self._by_name: + cands = self._by_name[name] + elif "." in name: + prefix, cls = name.rsplit(".", 1) + cands = [ + (b, e) + for (b, e) in self._by_name.get(cls, []) + if f".{prefix}." in f".{e.get('module') or ''}." + ] + else: + return [] + + def rank(item: tuple[str, dict[str, Any]]) -> tuple[bool, int]: + bucket, entry = item + in_canvas = ".canvas." in f".{entry.get('module') or ''}." + return (in_canvas, _BUCKET_RANK[bucket]) + + return sorted(cands, key=rank) + + @staticmethod + def _qualified_hint(entry: dict[str, Any], name: str) -> str: + """A dotted name that selects `entry` unambiguously in `get`.""" + parts = (entry.get("module") or "").split(".") + if "canvas" in parts: + return f"canvas.{name}" + return f"{parts[0]}.{name}" if parts and parts[0] else name + + # ------------------------------------------------------------------ + # Controls + # ------------------------------------------------------------------ + + def list_controls( + self, + category: str | None = None, + kind: str | None = None, + limit: int = 50, + ) -> list[dict[str, Any]]: + """List controls, optionally filtered by category or kind.""" + self._load() + results: list[dict[str, Any]] = [] + for name, ctrl in self._controls.items(): + if kind and ctrl.get("kind") != kind: + continue + if category and category not in ctrl.get("categories", []): + continue + results.append( + { + "name": name, + "kind": ctrl.get("kind"), + "summary": ctrl.get("summary", ""), + "categories": ctrl.get("categories", []), + } + ) + if len(results) >= limit: + break + return results + + # ------------------------------------------------------------------ + # Unified lookup (controls/services/types/events) + # ------------------------------------------------------------------ + + def get( + self, + name: str, + member: str | None = None, + query: str | None = None, + ) -> dict[str, Any] | None: + """Look up `name` across controls, services, types, events, and enums. + + Every match carries a `kind` field — `"control"`, `"service"`, `"type"`, + `"event"`, or `"enum"` (`"large_enum"` for Icons/CupertinoIcons) — so the + caller can distinguish them without inspecting the response shape. + Controls and services already carry `kind`; the other buckets are + augmented here. Returns `None` only when the name matches nothing. + + Member docstrings (properties/events/methods) are trimmed to their + first sentence. Pass `member` for one member's full entry, or `query` + for a case-insensitive substring filter over member names (`member` + wins if both are given). Enum responses use the same truncation as + `get_enum` for large enums; `member`/`query` don't apply to enums — + use search_enum_members / enum_has_member there. + + Names are not globally unique (e.g. the Text control vs the canvas + Text shape): the best candidate wins and the response notes the + alternatives, each reachable via a dotted name ("canvas.Text"). + """ + cands = self._candidates(name) + if not cands: + return None + bucket, entry = cands[0] + + if bucket == "enums": + if member is not None or query is not None: + return { + "error": ( + f"'{name}' is an enum — use search_enum_members or " + "enum_has_member to look up its members" + ) + } + enum = self.get_enum(entry["name"]) + return {"kind": enum.get("kind", "enum"), **enum} + + hit = entry if bucket == "controls" else {"kind": _BUCKET_KIND[bucket], **entry} + if member is not None: + return self._get_member(hit, name, member) + out = self._compact(hit) + if query is not None: + out = self._filter_members(out, name, query) + if "error" not in out and len(cands) > 1: + alternates = "; ".join( + f"{e.get('module')}.{e.get('name')} — get_api" + f"('{self._qualified_hint(e, e.get('name'))}')" + for _, e in cands[1:] + ) + combined = f"Other symbols share this name: {alternates}." + if out.get("note"): + combined += " " + out["note"] + out = {**out, "note": combined} + # Keep the note leading so it survives downstream capping. + out = {"note": out.pop("note"), **out} + return out + + def _filter_members( + self, compacted: dict[str, Any], name: str, query: str + ) -> dict[str, Any]: + """Keep only members whose name contains `query` (case-insensitive). + + Base classes are searched too (transitively): api.json stores only + a class's *own* members, so e.g. TextField's border properties live + on FormFieldControl — without the walk, a query would return a + misleading "no members" for members the control actually inherits. + Inherited matches land under an `inherited` key, grouped by the + defining class. + """ + q = query.lower() + + def _matches(hit: dict[str, Any]) -> tuple[dict[str, list], int]: + found: dict[str, list] = {} + count = 0 + for section in _MEMBER_SECTIONS: + kept = [ + _compact_member(e) + for e in hit.get(section) or [] + if q in e.get("name", "").lower() + ] + found[section] = kept + count += len(kept) + return found, count + + out = dict(compacted) + own, matched = _matches(compacted) + out.update(own) + + inherited: list[dict[str, Any]] = [] + visited: set[str] = set() + queue = list(compacted.get("bases") or []) + while queue: + base_name = queue.pop(0) + if base_name in visited: + continue + visited.add(base_name) + base = self._controls.get(base_name) or self._types.get(base_name) + if base is None: + continue + base_found, base_count = _matches(base) + if base_count: + inherited.append({"from": base_name, **base_found}) + matched += base_count + queue.extend(base.get("bases") or []) + if inherited: + out["inherited"] = inherited + + if not matched: + bases_hint = ( + f" (own and inherited via {', '.join(sorted(visited))})" + if visited + else "" + ) + return { + "error": (f"'{name}' has no members matching '{query}'{bases_hint}"), + "available_members": [ + e.get("name") + for section in _MEMBER_SECTIONS + for e in compacted.get(section) or [] + ], + } + out["note"] = ( + f"Showing only members matching '{query}' (including inherited). " + f"Call get_api({name!r}) for the full listing." + ) + return out + + def _compact(self, hit: dict[str, Any]) -> dict[str, Any]: + """Trim member docstrings to their first sentence, with a note + pointing at the per-member drill-down when anything was cut.""" + out = dict(hit) + trimmed = False + for section in _MEMBER_SECTIONS: + entries = out.get(section) + if not entries: + continue + compacted = [_compact_member(e) for e in entries] + if any(c is not e for c, e in zip(compacted, entries)): + trimmed = True + out[section] = compacted + if trimmed: + # Lead with the note so it survives any downstream size capping + # (agent frameworks may truncate the serialized result tail). + note = ( + "Member docstrings are trimmed to their first sentence. " + f"Call get_api({out.get('name')!r}, member=) for one " + "member's full docs and examples, or query= to " + "list matching members only." + ) + out = {"note": note, **out} + return out + + def _get_member( + self, hit: dict[str, Any], name: str, member: str + ) -> dict[str, Any]: + for section in _MEMBER_SECTIONS: + for entry in hit.get(section) or []: + if entry.get("name") == member: + return { + "name": name, + "kind": hit.get("kind"), + "member_kind": _MEMBER_KIND[section], + "member": entry, + } + available = [ + e.get("name") + for section in _MEMBER_SECTIONS + for e in hit.get(section) or [] + ] + return { + "error": f"'{name}' has no member '{member}'", + "available_members": available, + } + + # ------------------------------------------------------------------ + # Enums + # ------------------------------------------------------------------ + + def get_enum(self, name: str) -> dict[str, Any] | None: + """Return enum data. Large enums are truncated with a hint to search.""" + self._load() + enum = self._enums.get(name) + if enum is None: + return None + + if enum.get("kind") == "large_enum": + members = enum.get("members", []) + return { + "name": name, + "kind": "large_enum", + "total_members": len(members), + "sample_members": members[:10], + "note": ( + f"This enum has {len(members)} members. Use find_icon() " + "to search icons by concept, or search_enum_members() " + "for literal name lookup." + ), + } + + return enum + + def search_enum_members(self, name: str, query: str, limit: int = 10) -> list[str]: + """Search enum members by case-insensitive substring match. + + Ranked: exact match, then prefix matches, then substring matches + (shortest/alphabetical within each tier) — so "remove" surfaces + REMOVE before BOOKMARK_REMOVE. Material style variants + (_OUTLINED/_ROUNDED/_SHARP) are collapsed into their base member + when the base also matches, so they don't exhaust the limit. + """ + self._load() + enum = self._enums.get(name) + if enum is None: + return [] + + q = query.lower() + names = [ + m["name"] if isinstance(m, dict) else str(m) + for m in enum.get("members", []) + ] + matched = [n for n in names if q in n.lower()] + + def tier(n: str) -> int: + ln = n.lower() + if ln == q: + return 0 + return 1 if ln.startswith(q) else 2 + + matched.sort(key=lambda n: (tier(n), len(n), n)) + present = set(matched) + results: list[str] = [] + for n in matched: + base = next((n[: -len(s)] for s in _STYLE_SUFFIXES if n.endswith(s)), None) + if base and base in present: + continue + results.append(n) + if len(results) >= limit: + break + return results + + def enum_member_names(self, name: str) -> list[str]: + """All member names of an enum (untruncated — also for large + enums). Used to seed the icon search index from bundled data.""" + self._load() + enum = self._enums.get(name) + if enum is None: + return [] + return [ + m["name"] if isinstance(m, dict) else str(m) + for m in enum.get("members", []) + ] + + def enum_has_member(self, name: str, member: str) -> bool: + """Check whether an enum contains a specific member.""" + self._load() + enum = self._enums.get(name) + if enum is None: + return False + members = enum.get("members", []) + member_lower = member.lower() + return any( + (m["name"] if isinstance(m, dict) else str(m)).lower() == member_lower + for m in members + ) + + # ------------------------------------------------------------------ + # CLI + # ------------------------------------------------------------------ + + def get_cli_help(self, command: str | None = None) -> Any: + """Return CLI help. None -> list commands; otherwise command help text.""" + self._load() + cli = self._raw.get("cli", {}) + if command is None: + return list(cli.keys()) + return cli.get(command) diff --git a/sdk/python/packages/flet-mcp/src/flet_mcp/build/__init__.py b/sdk/python/packages/flet-mcp/src/flet_mcp/build/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/packages/flet-mcp/src/flet_mcp/build/api.py b/sdk/python/packages/flet-mcp/src/flet_mcp/build/api.py new file mode 100644 index 0000000000..759ecb081a --- /dev/null +++ b/sdk/python/packages/flet-mcp/src/flet_mcp/build/api.py @@ -0,0 +1,608 @@ +"""API reference builder using Griffe. + +Scans Flet packages with Griffe to extract controls, events, types, enums, +and CLI help, then writes a consolidated api.json file. +""" + +from __future__ import annotations + +import json +import logging +import re +from pathlib import Path +from typing import Any + +import griffe + +logger = logging.getLogger(__name__) + +DEFAULT_PACKAGES: list[str] = [ + "flet", + "flet_ads", + "flet_audio", + "flet_audio_recorder", + "flet_camera", + "flet_charts", + "flet_code_editor", + "flet_color_pickers", + "flet_datatable2", + "flet_flashlight", + "flet_geolocator", + "flet_lottie", + "flet_map", + "flet_permission_handler", + "flet_rive", + "flet_secure_storage", + "flet_video", + "flet_webview", +] + +_CONTROL_BASE_NAMES = {"BaseControl", "LayoutControl", "AdaptiveControl", "Service"} + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + + +def _first_line(docstring: griffe.Docstring | None) -> str: + if docstring is None: + return "" + text = docstring.value.strip() + return text.split("\n", 1)[0].strip() + + +def _full_docstring(docstring: griffe.Docstring | None) -> str: + if docstring is None: + return "" + return docstring.value.strip() + + +def _annotation_str(annotation: Any) -> str: + if annotation is None: + return "" + return str(annotation) + + +def _default_str(default: Any) -> str: + if default is None: + return "" + return str(default) + + +def _package_from_module(module: str) -> str: + """Return the pip-installable package name for a module path. + + The first segment of the dotted path is the import name (e.g. `flet_video`); + Flet's pip distribution names just swap underscores for hyphens. Core flet + stays `"flet"` — the agent uses that as a sentinel for "no extra dep + needed". + """ + top = module.split(".", 1)[0] + return top.replace("_", "-") + + +# Populated once per build_api() call: simple class name -> list of direct +# base simple-names. Used by _is_control_class to walk the inheritance chain +# through intermediate bases (DialogControl, BasePage, ...) without having +# to enumerate every transitive base in _CONTROL_BASE_NAMES. +_class_bases: dict[str, list[str]] = {} + + +def _collect_class_bases(module: griffe.Module) -> None: + """Pre-pass: index every class's direct base simple-names into _class_bases.""" + for obj in module.members.values(): + if isinstance(obj, griffe.Module): + _collect_class_bases(obj) + elif isinstance(obj, griffe.Class): + _class_bases[obj.name] = [str(b).rsplit(".", 1)[-1] for b in obj.bases] + + +def _is_control_class(cls: griffe.Class) -> bool: + """Check whether cls (transitively) inherits a known control base.""" + visited: set[str] = set() + stack: list[str] = [str(b).rsplit(".", 1)[-1] for b in cls.bases] + while stack: + base_name = stack.pop() + if base_name in _CONTROL_BASE_NAMES: + return True + if base_name in visited: + continue + visited.add(base_name) + # Walk up: if we indexed this base earlier, queue its own bases. + stack.extend(_class_bases.get(base_name, ())) + return False + + +def _is_service(cls: griffe.Class) -> bool: + return any("Service" in str(base) for base in cls.bases) + + +def _is_enum(cls: griffe.Class) -> bool: + for base in cls.bases: + base_name = str(base).rsplit(".", 1)[-1] + if base_name == "Enum" or base_name.endswith("Enum"): + return True + return False + + +def _is_event_class(cls: griffe.Class) -> bool: + return any("Event" in str(base).rsplit(".", 1)[-1] for base in cls.bases) + + +_DEPRECATION_KW_RE = re.compile(r"(reason|version|delete_version)=['\"]([^'\"]*)['\"]") + + +def _deprecation_info(cls: griffe.Class) -> dict | None: + """Extract @deprecated / @deprecated_class metadata if present. + + Returns a dict with whichever of `reason`/`version`/`delete_version` were + given as keyword args, or `None` if the class isn't deprecated. + """ + for dec in cls.decorators: + s = str(dec.value) + if "deprecated" not in s: + continue + info = {k: v for k, v in _DEPRECATION_KW_RE.findall(s)} + return info or {"reason": "deprecated"} + return None + + +def _is_dataclass(cls: griffe.Class) -> bool: + # Flet wraps most styling/value classes (ButtonStyle, Padding, ...) with the + # @value decorator, which expands to @dataclass under the hood. + for dec in cls.decorators: + dec_str = str(dec.value) + if "dataclass" in dec_str or dec_str.rsplit(".", 1)[-1] == "value": + return True + return False + + +def _has_control_decorator(cls: griffe.Class) -> tuple[list[str], list[str]]: + """Return (categories, tags) from @control decorator if present.""" + categories: list[str] = [] + tags: list[str] = [] + for dec in cls.decorators: + dec_str = str(dec.value) + if "control" not in dec_str: + continue + # Try to extract keyword args from the decorator's AST node + try: + node = dec.value + # Griffe stores decorator values as Expressions or AST nodes + if hasattr(node, "keywords"): + for kw in node.keywords: + if kw.arg == "categories" and hasattr(kw.value, "elts"): + categories = [ + str(getattr(e, "value", e)) for e in kw.value.elts + ] + elif kw.arg == "tags" and hasattr(kw.value, "elts"): + tags = [str(getattr(e, "value", e)) for e in kw.value.elts] + except Exception: + pass + # Fallback: parse from string representation + if not categories and "categories=" in dec_str: + categories = _parse_tuple_from_str(dec_str, "categories") + if not tags and "tags=" in dec_str: + tags = _parse_tuple_from_str(dec_str, "tags") + return categories, tags + + +def _parse_tuple_from_str(dec_str: str, key: str) -> list[str]: + """Parse a keyword arg tuple from decorator string representation. + + e.g. 'control("TextField", categories=("input", "form"))' -> ["input", "form"] + """ + import re + + pattern = rf"{key}\s*=\s*\(([^)]*)\)" + match = re.search(pattern, dec_str) + if not match: + return [] + inner = match.group(1) + return [s.strip().strip("\"'") for s in inner.split(",") if s.strip().strip("\"'")] + + +def _extract_properties(cls: griffe.Class) -> list[dict[str, Any]]: + """Extract dataclass-style fields as properties.""" + props: list[dict[str, Any]] = [] + for name, member in cls.members.items(): + if name.startswith("_"): + continue + if isinstance(member, griffe.Attribute): + annotation = _annotation_str(member.annotation) + is_event = ( + "EventHandler" in annotation or "ControlEventHandler" in annotation + ) + props.append( + { + "name": name, + "type": annotation, + "default": _default_str(member.value), + "docstring": _full_docstring(member.docstring), + "is_event": is_event, + } + ) + return props + + +def _extract_methods(cls: griffe.Class) -> list[dict[str, Any]]: + """Extract public methods.""" + methods: list[dict[str, Any]] = [] + for name, member in cls.members.items(): + if name.startswith("_"): + continue + if isinstance(member, griffe.Function): + args = [] + for param in member.parameters: + if param.name == "self": + continue + args.append( + { + "name": param.name, + "type": _annotation_str(param.annotation), + "default": _default_str(param.default), + } + ) + entry: dict[str, Any] = { + "name": name, + "args": args, + "return_type": _annotation_str(member.annotation), + "docstring": _full_docstring(member.docstring), + } + if "async" in member.labels: + entry["async"] = True + methods.append(entry) + return methods + + +def _extract_enum_members(cls: griffe.Class) -> list[dict[str, str]]: + members: list[dict[str, str]] = [] + for name, member in cls.members.items(): + if name.startswith("_"): + continue + if isinstance(member, griffe.Attribute): + entry: dict[str, str] = {"name": name, "value": _default_str(member.value)} + doc = _full_docstring(member.docstring) + if doc: + entry["docstring"] = doc + members.append(entry) + return members + + +# --------------------------------------------------------------------------- +# Module walker +# --------------------------------------------------------------------------- + + +def _walk_module( + module: griffe.Module, + controls: list[dict], + events: list[dict], + types: list[dict], + enums: list[dict], +) -> None: + """Recursively walk a griffe Module and classify its members.""" + for name, obj in module.members.items(): + if isinstance(obj, griffe.Module): + _walk_module(obj, controls, events, types, enums) + + elif isinstance(obj, griffe.Class): + try: + if _is_enum(obj): + members = _extract_enum_members(obj) + module_path = obj.canonical_path.rsplit(".", 1)[0] + entry: dict[str, Any] = { + "name": obj.name, + "module": module_path, + "package": _package_from_module(module_path), + "docstring": _full_docstring(obj.docstring), + "members": members, + } + if len(members) > 50: + entry["kind"] = "large_enum" + enums.append(entry) + + elif _is_control_class(obj): + categories, tags = _has_control_decorator(obj) + props = _extract_properties(obj) + event_fields = [p for p in props if p.get("is_event")] + regular_props = [p for p in props if not p.get("is_event")] + # Remove is_event flag from output + for p in regular_props: + p.pop("is_event", None) + for e in event_fields: + e.pop("is_event", None) + + kind = "service" if _is_service(obj) else "control" + module_path = obj.canonical_path.rsplit(".", 1)[0] + entry: dict[str, Any] = { + "name": obj.name, + "module": module_path, + "package": _package_from_module(module_path), + "kind": kind, + "summary": _first_line(obj.docstring), + "bases": [str(b) for b in obj.bases], + "categories": categories, + "tags": tags, + "properties": regular_props, + "events": event_fields, + "methods": _extract_methods(obj), + } + if dep := _deprecation_info(obj): + entry["deprecated"] = dep + controls.append(entry) + + elif _is_event_class(obj): + fields = _extract_properties(obj) + for f in fields: + f.pop("is_event", None) + module_path = obj.canonical_path.rsplit(".", 1)[0] + entry = { + "name": obj.name, + "module": module_path, + "package": _package_from_module(module_path), + "docstring": _full_docstring(obj.docstring), + "fields": fields, + } + if dep := _deprecation_info(obj): + entry["deprecated"] = dep + events.append(entry) + + elif _is_dataclass(obj): + fields = _extract_properties(obj) + for f in fields: + f.pop("is_event", None) + class_methods = [] + for mname, member in obj.members.items(): + if mname.startswith("_"): + continue + if isinstance(member, griffe.Function) and ( + "classmethod" in member.labels + or "staticmethod" in member.labels + ): + args = [] + for param in member.parameters: + if param.name in ("self", "cls"): + continue + args.append( + { + "name": param.name, + "type": _annotation_str(param.annotation), + "default": _default_str(param.default), + } + ) + entry: dict[str, Any] = { + "name": mname, + "args": args, + "return_type": _annotation_str(member.annotation), + "docstring": _full_docstring(member.docstring), + } + if "async" in member.labels: + entry["async"] = True + class_methods.append(entry) + module_path = obj.canonical_path.rsplit(".", 1)[0] + entry = { + "name": obj.name, + "module": module_path, + "package": _package_from_module(module_path), + "docstring": _full_docstring(obj.docstring), + "fields": fields, + "methods": class_methods, + } + if dep := _deprecation_info(obj): + entry["deprecated"] = dep + types.append(entry) + except Exception as exc: + logger.warning("Error processing class %s: %s", name, exc) + + +# --------------------------------------------------------------------------- +# CLI help extraction +# --------------------------------------------------------------------------- + + +def _extract_cli_help() -> dict[str, Any]: + """Try to extract structured CLI help from flet_cli.""" + import argparse as _argparse + + cli_help: dict[str, Any] = {} + + def _parse_parser(parser: _argparse.ArgumentParser) -> dict[str, Any]: + """Extract structured option data from an ArgumentParser.""" + options: list[dict[str, Any]] = [] + for action in parser._actions: + if isinstance(action, _argparse._HelpAction): + continue + if isinstance(action, _argparse._SubParsersAction): + continue + + opt: dict[str, Any] = {} + + if action.option_strings: + opt["name"] = action.option_strings[-1] # --long form + if len(action.option_strings) > 1: + opt["alias"] = action.option_strings[0] # -short form + else: + opt["name"] = action.dest + opt["positional"] = True + + # Type + if isinstance( + action, (_argparse._StoreTrueAction, _argparse._StoreFalseAction) + ): + opt["type"] = "bool" + elif isinstance(action, _argparse._CountAction): + opt["type"] = "count" + elif action.type is not None: + opt["type"] = action.type.__name__ + else: + opt["type"] = "str" + + if action.nargs in ("*", "+"): + opt["multiple"] = True + + if action.default is not None and action.default != _argparse.SUPPRESS: + opt["default"] = action.default + + if action.required: + opt["required"] = True + + if action.choices: + opt["choices"] = list(action.choices) + + if action.help and action.help != _argparse.SUPPRESS: + opt["help"] = action.help + + options.append(opt) + + result: dict[str, Any] = {"options": options} + if parser.description: + result["description"] = parser.description + return result + + try: + from flet_cli.cli import get_parser + + parser = get_parser() + cli_help["flet"] = _parse_parser(parser) + for action in parser._subparsers._actions: + if hasattr(action, "choices") and action.choices: + for cmd_name, cmd_parser in action.choices.items(): + try: + cmd_data = _parse_parser(cmd_parser) + if cmd_parser.description: + cmd_data["description"] = cmd_parser.description + cli_help[cmd_name] = cmd_data + except Exception: + pass + except Exception as exc: + logger.warning("Could not extract CLI help: %s", exc) + return cli_help + + +# --------------------------------------------------------------------------- +# Icon enum injection +# --------------------------------------------------------------------------- + + +def _inject_icon_enums(enums: list[dict]) -> None: + """Add Icons and CupertinoIcons as large_enum entries from JSON files.""" + try: + import importlib.resources + + material_path = ( + importlib.resources.files("flet") / "controls" / "material" / "icons.json" + ) + cupertino_path = ( + importlib.resources.files("flet") + / "controls" + / "cupertino" + / "cupertino_icons.json" + ) + + with importlib.resources.as_file(material_path) as p: + material_icons: dict[str, int] = json.loads(p.read_text("utf-8")) + with importlib.resources.as_file(cupertino_path) as p: + cupertino_icons: dict[str, int] = json.loads(p.read_text("utf-8")) + + enums.append( + { + "name": "Icons", + "module": "flet.controls.material.icons", + "package": "flet", + "docstring": "Material Design icon constants.", + "kind": "large_enum", + "members": [ + {"name": name, "value": str(val)} + for name, val in material_icons.items() + ], + } + ) + enums.append( + { + "name": "CupertinoIcons", + "module": "flet.controls.cupertino.cupertino_icons", + "package": "flet", + "docstring": "Cupertino (iOS-style) icon constants.", + "kind": "large_enum", + "members": [ + {"name": name, "value": str(val)} + for name, val in cupertino_icons.items() + ], + } + ) + logger.info( + "Injected Icons (%d members) and CupertinoIcons (%d members)", + len(material_icons), + len(cupertino_icons), + ) + except Exception as exc: + logger.warning("Could not inject icon enums: %s", exc) + + +# --------------------------------------------------------------------------- +# Public API +# --------------------------------------------------------------------------- + + +def build_api(output_path: Path, packages: list[str] | None = None) -> dict[str, Any]: + """Build the API reference JSON from installed Flet packages. + + Parameters: + output_path: Where to write the resulting api.json. + packages: List of package names to scan. Defaults to all known Flet packages. + + Returns: + A stats dict with counts per category. + """ + if packages is None: + packages = DEFAULT_PACKAGES + + controls: list[dict] = [] + events: list[dict] = [] + types: list[dict] = [] + enums: list[dict] = [] + + loaded: list[griffe.Module] = [] + for pkg in packages: + try: + loaded.append(griffe.load(pkg)) + except Exception as exc: + logger.warning("Failed to load package %s: %s", pkg, exc) + + # Pass 1: build the class-name -> bases registry so _is_control_class + # can walk transitive inheritance (DialogControl -> AdaptiveControl, etc.) + _class_bases.clear() + for module in loaded: + _collect_class_bases(module) + + # Pass 2: classify + extract each class. + for module in loaded: + _walk_module(module, controls, events, types, enums) + + # Inject Icons and CupertinoIcons from JSON files (not Python Enums) + _inject_icon_enums(enums) + + cli_help = _extract_cli_help() + + api_data: dict[str, Any] = { + "controls": controls, + "events": events, + "types": types, + "enums": enums, + "cli": cli_help, + } + + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text(json.dumps(api_data, indent=2), encoding="utf-8") + + stats = { + "controls": len(controls), + "events": len(events), + "types": len(types), + "enums": len(enums), + "cli_commands": len(cli_help), + } + logger.info("API build stats: %s", stats) + return stats diff --git a/sdk/python/packages/flet-mcp/src/flet_mcp/build/docs.py b/sdk/python/packages/flet-mcp/src/flet_mcp/build/docs.py new file mode 100644 index 0000000000..c331421ec6 --- /dev/null +++ b/sdk/python/packages/flet-mcp/src/flet_mcp/build/docs.py @@ -0,0 +1,132 @@ +"""Docs indexer. Parses search_index.json produced by mkdocs and indexes +the entries into an SQLite FTS5 database.""" + +from __future__ import annotations + +import json +import logging +import re +import sqlite3 +from pathlib import Path + +from markdownify import markdownify + +logger = logging.getLogger(__name__) + +_HTML_TAG_RE = re.compile(r"<[^>]+>") +_WHITESPACE_RE = re.compile(r"\s{3,}") +_LOCATION_SPLIT_RE = re.compile(r"[/\-_\.#]") +# mkdocstrings labels like class-attribute, instance-attribute +_MKDOCS_LABEL_RE = re.compile( + r"\s*(?:class-attribute|instance-attribute|property|cached-property|" + r"writable|static-method|class-method|module-attribute)", + re.IGNORECASE, +) + + +def _create_tables(conn: sqlite3.Connection) -> None: + conn.executescript( + """ + CREATE TABLE IF NOT EXISTS docs ( + location TEXT PRIMARY KEY, + location_text TEXT, + title TEXT, + content TEXT + ); + CREATE VIRTUAL TABLE IF NOT EXISTS docs_fts USING fts5( + title, location_text, content, + tokenize='porter unicode61' + ); + """ + ) + + +def _html_to_markdown(html: str) -> str: + """Convert HTML to markdown and clean up.""" + md = markdownify(html, strip=["img"]) + md = _HTML_TAG_RE.sub("", md) + md = _WHITESPACE_RE.sub("\n\n", md) + return md.strip() + + +def _strip_html(text: str) -> str: + text = _MKDOCS_LABEL_RE.sub("", text) + return _HTML_TAG_RE.sub("", text).strip() + + +def _location_to_text(location: str) -> str: + """Turn a location string into a space-separated searchable string. + + Example: + "ads/bannerad/#flet_ads.banner_ad.BannerAd.on_paid" + -> "ads bannerad flet_ads banner_ad BannerAd on_paid" + """ + parts = _LOCATION_SPLIT_RE.split(location) + return " ".join(p for p in parts if p) + + +def index_docs(conn: sqlite3.Connection, search_index_path: Path) -> int: + """Index mkdocs search_index.json into *conn*. + + Returns the number of doc entries indexed. + """ + _create_tables(conn) + + raw = json.loads(search_index_path.read_text(encoding="utf-8")) + entries: list[dict] = raw.get("docs", []) + + count = 0 + root_title: str = "" + section_title: str = "" + for entry in entries: + location: str = entry.get("location", "") + title: str = entry.get("title", "") + text: str = entry.get("text", "") + + has_anchor = "#" in location + clean_title = _strip_html(title) + + # ---- new page (no anchor) ---- + if not has_anchor: + root_title = clean_title + section_title = "" + if not text: + continue + + # ---- empty-text anchor = section group heading ---- + if has_anchor and not text: + anchor = location.split("#", 1)[1] if "#" in location else "" + # Only track well-known API doc section groups as intermediate titles + if anchor.endswith(("-properties", "-methods", "-events")): + section_title = clean_title + else: + # Reset section title — this is a peer heading, not a group + section_title = "" + continue + + # ---- entry with content: build composite title ---- + parts = [root_title] + if section_title: + parts.append(section_title) + parts.append(clean_title) + composite_title = " - ".join(parts) + + # ---- process content ---- + location_text = _location_to_text(location) + content = _html_to_markdown(text) + + # ---- insert ---- + conn.execute( + "INSERT OR REPLACE INTO docs (location, location_text, title, content) " + "VALUES (?, ?, ?, ?)", + (location, location_text, composite_title, content), + ) + conn.execute( + "INSERT INTO docs_fts (title, location_text, content) VALUES (?, ?, ?)", + (composite_title, location_text, content), + ) + + count += 1 + + conn.commit() + return count diff --git a/sdk/python/packages/flet-mcp/src/flet_mcp/build/examples.py b/sdk/python/packages/flet-mcp/src/flet_mcp/build/examples.py new file mode 100644 index 0000000000..276659a92e --- /dev/null +++ b/sdk/python/packages/flet-mcp/src/flet_mcp/build/examples.py @@ -0,0 +1,172 @@ +"""Examples indexer. Walks a directory tree looking for pyproject.toml files +with [tool.flet.metadata] and indexes them into an SQLite database.""" + +from __future__ import annotations + +import json +import logging +import re +import sqlite3 +import sys +from pathlib import Path + +if sys.version_info >= (3, 11): + import tomllib +else: + import tomli as tomllib + +logger = logging.getLogger(__name__) + +_CODE_EXTENSIONS = {".py", ".toml"} +_TEXT_EXTENSIONS = {".py", ".toml", ".md", ".txt"} + + +def _create_tables(conn: sqlite3.Connection) -> None: + conn.executescript( + """ + CREATE TABLE IF NOT EXISTS examples ( + id TEXT PRIMARY KEY, + location TEXT, + metadata TEXT + ); + CREATE TABLE IF NOT EXISTS example_files ( + example_id TEXT, + filename TEXT, + content TEXT, + FOREIGN KEY (example_id) REFERENCES examples(id) + ); + CREATE VIRTUAL TABLE IF NOT EXISTS examples_fts USING fts5( + title, description, tags, controls, + layout_pattern, features, search_text, code, + tokenize='porter unicode61' + ); + """ + ) + + +def _derive_id(relative_path: Path) -> str: + return re.sub(r"[\\/]", "_", str(relative_path)) + + +def _read_text_files(directory: Path) -> dict[str, str]: + """Read all indexable text files in *directory* (non-recursive).""" + files: dict[str, str] = {} + for p in sorted(directory.iterdir()): + if p.is_file() and p.suffix in _TEXT_EXTENSIONS: + try: + files[p.name] = p.read_text(encoding="utf-8", errors="replace") + except OSError as exc: + logger.warning("Cannot read %s: %s", p, exc) + return files + + +def index_examples(conn: sqlite3.Connection, examples_dir: Path) -> int: + """Index Flet example projects found under *examples_dir*. + + Returns the number of examples indexed. + """ + _create_tables(conn) + + count = 0 + for pyproject_path in sorted(examples_dir.rglob("pyproject.toml")): + try: + with open(pyproject_path, "rb") as f: + data = tomllib.load(f) + except Exception as exc: + logger.warning("Failed to parse %s: %s", pyproject_path, exc) + continue + + flet_meta = data.get("tool", {}).get("flet", {}).get("metadata") + if flet_meta is None: + continue + + project = data.get("project", {}) + project_dir = pyproject_path.parent + relative = project_dir.relative_to(examples_dir) + + example_id = _derive_id(relative) + location = str(relative) + title = flet_meta.get("title") or project.get("name", example_id) + description = project.get("description", "") + tags: list[str] = project.get("keywords", []) + platforms: list[str] = ( + data.get("tool", {}) + .get("flet", {}) + .get("platforms", ["web", "ios", "android", "macos", "windows", "linux"]) + ) + controls: list[str] = flet_meta.get("controls", []) + layout: str = flet_meta.get("layout_pattern", "") + complexity: str = flet_meta.get("complexity", "basic") + features: list[str] = flet_meta.get("features", []) + + # ---- read files in the example directory ---- + text_files = _read_text_files(project_dir) + + # ---- build search_text ---- + search_text = ( + f"{title}\n\n" + f"{description}\n\n" + f"tags: {', '.join(tags)}\n" + f"platforms: {', '.join(platforms)}\n" + f"controls: {', '.join(controls)}\n" + f"complexity: {complexity}\n" + f"layout_pattern: {layout}\n" + f"features: {', '.join(features)}" + ) + + # ---- build code blob ---- + code_parts: list[str] = [] + for fname, content in text_files.items(): + if Path(fname).suffix in _CODE_EXTENSIONS: + code_parts.append(content) + code = "\n\n".join(code_parts) + + # ---- metadata JSON ---- + metadata = json.dumps( + { + "title": title, + "description": description, + "tags": tags, + "platforms": platforms, + "controls": controls, + "layout_pattern": layout, + "complexity": complexity, + "features": features, + } + ) + + # ---- insert rows ---- + conn.execute( + "INSERT OR REPLACE INTO examples (id, location, metadata) VALUES (?, ?, ?)", + (example_id, location, metadata), + ) + + for fname, content in text_files.items(): + conn.execute( + "INSERT INTO example_files " + "(example_id, filename, content) VALUES (?, ?, ?)", + (example_id, fname, content), + ) + + conn.execute( + "INSERT INTO examples_fts " + "(title, description, tags, controls, " + "layout_pattern, features, search_text, code) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + ( + title, + description, + ", ".join(tags), + ", ".join(controls), + layout, + ", ".join(features), + search_text, + code, + ), + ) + + count += 1 + logger.debug("Indexed example %s (%s)", example_id, title) + + conn.commit() + return count diff --git a/sdk/python/packages/flet-mcp/src/flet_mcp/build/icons.py b/sdk/python/packages/flet-mcp/src/flet_mcp/build/icons.py new file mode 100644 index 0000000000..af7f6b3ca9 --- /dev/null +++ b/sdk/python/packages/flet-mcp/src/flet_mcp/build/icons.py @@ -0,0 +1,74 @@ +"""Refresh the Material icon search metadata (data/icons.json). + +Google publishes the search metadata that powers fonts.google.com/icons — +per icon: human synonym `tags` ("remove" carries minus/negative/delete…), +`categories`, and `popularity`. We transform it into the keyword map +`IconStore` consumes, keyed by the UPPER_SNAKE names used by flet's +`Icons` enum. Apache-2.0, same as the icon set itself. + +Unlike api.json, `data/icons.json` is a *committed* package file (it +changes only when Google ships new icons), so the regular MCP build +stays network-free. Refresh it explicitly with: + + uv run python -m flet_mcp.build.icons + +Cupertino icons have no published tag metadata; they are searched by +name tokens only (a curated/LLM-generated tag pass is a possible +follow-up). +""" + +from __future__ import annotations + +import json +import logging +import urllib.request +from pathlib import Path + +logger = logging.getLogger(__name__) + +METADATA_URL = "https://fonts.google.com/metadata/icons" + +# The endpoint prefixes its JSON with an anti-XSSI guard line. +_XSSI_GUARD = ")]}'" + +_DATA_PATH = Path(__file__).resolve().parent.parent / "data" / "icons.json" + + +def fetch_metadata() -> dict: + with urllib.request.urlopen(METADATA_URL, timeout=30) as resp: + text = resp.read().decode("utf-8") + if text.startswith(_XSSI_GUARD): + text = text[len(_XSSI_GUARD) :] + return json.loads(text) + + +def build_icons(output_path: Path = _DATA_PATH) -> dict: + """Fetch Google's icon metadata and write icons.json: + {"material": {NAME: {"tags": [...], "popularity": N}}}.""" + meta = fetch_metadata() + material: dict[str, dict] = {} + for icon in meta.get("icons", []): + name = str(icon.get("name", "")).upper() + if not name: + continue + tags = sorted( + {str(t).strip().lower() for t in icon.get("tags", []) if str(t).strip()} + ) + material[name] = { + "tags": tags, + "popularity": int(icon.get("popularity", 0)), + } + # Trailing newline keeps the end-of-file pre-commit hook happy on + # regeneration. + output_path.write_text( + json.dumps({"material": material}, ensure_ascii=False, indent=1) + "\n", + encoding="utf-8", + ) + logger.info("Wrote %d material icon entries to %s", len(material), output_path) + return {"icons": len(material)} + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + stats = build_icons() + print(f"icons.json refreshed: {stats['icons']} material icons tagged") diff --git a/sdk/python/packages/flet-mcp/src/flet_mcp/build/indexer.py b/sdk/python/packages/flet-mcp/src/flet_mcp/build/indexer.py new file mode 100644 index 0000000000..b40a0a53ce --- /dev/null +++ b/sdk/python/packages/flet-mcp/src/flet_mcp/build/indexer.py @@ -0,0 +1,109 @@ +"""Build orchestrator for the Flet MCP data pipeline. + +Coordinates indexing of examples, docs, and API reference into the +data directory consumed by the MCP server. +""" + +from __future__ import annotations + +import logging +import sqlite3 +import time +from pathlib import Path + +from flet_mcp.build.api import build_api +from flet_mcp.build.docs import index_docs +from flet_mcp.build.examples import index_examples + +logger = logging.getLogger(__name__) + +_DATA_DIR = Path(__file__).resolve().parent.parent / "data" + + +def _print_summary(metrics: list[tuple[str, str, float]]) -> None: + """Print a summary table of build steps. + + Each entry is (step_name, result_text, elapsed_seconds). + """ + try: + from rich.console import Console + from rich.table import Table + + console = Console() + table = Table(title="MCP Build Summary") + table.add_column("Step", style="bold") + table.add_column("Result", justify="right") + table.add_column("Time", justify="right", style="dim") + + for step, result, elapsed in metrics: + table.add_row(step, result, f"{elapsed:.2f}s") + + console.print(table) + except ImportError: + # Fallback to plain output + print("\n--- MCP Build Summary ---") + for step, result, elapsed in metrics: + print(f" {step:<20s} {result:>30s} ({elapsed:.2f}s)") + print() + + +def build_all( + examples_dir: Path | None = None, + docs_index: Path | None = None, + output_dir: Path | None = None, +) -> None: + """Run the full MCP build pipeline. + + Parameters: + examples_dir: Root directory containing Flet example projects. + docs_index: Path to the mkdocs search_index.json file. + output_dir: Where to write mcp.db and api.json. + Defaults to the `flet_mcp/data/` package directory. + + Note: the icon search metadata (`data/icons.json`) is a committed + package file, not a build product — refresh it explicitly with + `python -m flet_mcp.build.icons`. + """ + if output_dir is None: + output_dir = _DATA_DIR + output_dir.mkdir(parents=True, exist_ok=True) + + db_path = output_dir / "mcp.db" + api_path = output_dir / "api.json" + + # Remove existing DB so we start fresh + if db_path.exists(): + db_path.unlink() + + metrics: list[tuple[str, str, float]] = [] + conn = sqlite3.connect(str(db_path)) + + try: + # ---- Examples ---- + if examples_dir is not None: + t0 = time.perf_counter() + n = index_examples(conn, examples_dir) + elapsed = time.perf_counter() - t0 + metrics.append(("Examples", f"{n} indexed", elapsed)) + logger.info("Indexed %d examples in %.2fs", n, elapsed) + + # ---- Docs ---- + if docs_index is not None: + t0 = time.perf_counter() + n = index_docs(conn, docs_index) + elapsed = time.perf_counter() - t0 + metrics.append(("Docs", f"{n} indexed", elapsed)) + logger.info("Indexed %d doc entries in %.2fs", n, elapsed) + + # ---- API reference ---- + t0 = time.perf_counter() + stats = build_api(api_path) + elapsed = time.perf_counter() - t0 + parts = [f"{v} {k}" for k, v in stats.items()] + metrics.append(("API", ", ".join(parts), elapsed)) + logger.info("Built API reference in %.2fs: %s", elapsed, stats) + + finally: + conn.close() + + _print_summary(metrics) diff --git a/sdk/python/packages/flet-mcp/src/flet_mcp/data/.gitkeep b/sdk/python/packages/flet-mcp/src/flet_mcp/data/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/packages/flet-mcp/src/flet_mcp/data/icons.json b/sdk/python/packages/flet-mcp/src/flet_mcp/data/icons.json new file mode 100644 index 0000000000..bcb18ef972 --- /dev/null +++ b/sdk/python/packages/flet-mcp/src/flet_mcp/data/icons.json @@ -0,0 +1,84638 @@ +{ + "material": { + "10K": { + "tags": [ + "10000", + "10k", + "achievement", + "alphabet", + "character", + "competition", + "digit", + "display", + "distance", + "event", + "exercise", + "font", + "goal", + "k", + "letter", + "letters", + "measurement", + "metric", + "metric prefix", + "milestone", + "number", + "numbers", + "numerical", + "pixel", + "pixels", + "quantity", + "race", + "resolution", + "running", + "sport", + "symbol", + "ten", + "text", + "thousand", + "type", + "value", + "video" + ], + "popularity": 1367 + }, + "10MP": { + "tags": [ + "10", + "10mp", + "camera", + "camera specifications", + "capture", + "detail", + "digital", + "digits", + "display", + "equipment", + "file size", + "font", + "high resolution", + "image", + "image size", + "indicator", + "label", + "lens", + "letters", + "megapixel", + "megapixels", + "mp", + "numbers", + "numerical", + "photo", + "photo quality", + "photography", + "photography gear", + "photography settings", + "picture", + "pixel", + "pixels", + "quality", + "resolution", + "sensor", + "symbol", + "technology", + "ten", + "text", + "type" + ], + "popularity": 708 + }, + "11MP": { + "tags": [ + "11", + "camera", + "detail", + "digital", + "digits", + "display", + "eleven", + "font", + "image", + "indicator", + "information", + "letter", + "letters", + "measurement", + "megapixel", + "megapixels", + "metric", + "mp", + "number", + "numbers", + "numeric", + "options", + "photo", + "photography", + "pixel", + "pixels", + "quality", + "resolution", + "settings", + "symbol", + "text", + "type" + ], + "popularity": 640 + }, + "123": { + "tags": [ + "1", + "123", + "2", + "3", + "arrange", + "arrow", + "ascending", + "ascending sort", + "count", + "data", + "digit", + "digit order", + "filter", + "increasing", + "increasing order", + "items", + "line", + "list", + "number order", + "numbers", + "numerical", + "one two three", + "order", + "organize", + "pointing up", + "sequence", + "sort", + "sort ascending", + "symbol", + "three lines", + "up arrow" + ], + "popularity": 6706 + }, + "12MP": { + "tags": [ + "12", + "12 megapixels", + "12mp", + "camera", + "camera icon", + "camera quality", + "definition", + "digit", + "digital camera", + "digits", + "font", + "high resolution", + "image", + "image quality", + "imaging", + "information", + "label", + "letters", + "media settings", + "megapixel", + "megapixels", + "mp", + "number", + "numbers", + "numerical", + "photo resolution", + "photo settings", + "photography", + "photography settings", + "picture settings", + "pixel", + "pixels", + "quality", + "resolution", + "symbol", + "text", + "type", + "video camera icon", + "video quality", + "video quality.", + "video resolution" + ], + "popularity": 796 + }, + "13MP": { + "tags": [ + "13", + "13 megapixel", + "camera", + "camera information", + "camera resolution", + "camera settings", + "digital image", + "digits", + "file size", + "font", + "high resolution", + "image", + "image details", + "image metadata", + "image settings", + "image size", + "letters", + "megapixel", + "megapixels", + "mp", + "numbers", + "photo details", + "photo quality", + "photo size", + "photography", + "picture quality", + "picture size", + "pixel", + "pixels", + "quality", + "resolution", + "resolution indicator", + "symbol", + "technical details", + "text", + "thirteen", + "thirteen megapixels", + "type" + ], + "popularity": 605 + }, + "14MP": { + "tags": [ + "14", + "14mp", + "camera", + "camera settings", + "clarity", + "detail", + "digital", + "digits", + "font", + "fourteen megapixels", + "graphic", + "high resolution", + "icon", + "image", + "image quality", + "image size", + "lens", + "letters", + "megapixel", + "megapixels", + "mp", + "numbers", + "photo", + "photo quality", + "photography", + "picture", + "pixel", + "pixels", + "quality", + "resolution", + "sensor", + "specification", + "symbol", + "technical", + "text", + "type", + "ui" + ], + "popularity": 583 + }, + "15MP": { + "tags": [ + "15", + "15mp", + "attributes", + "camera", + "data", + "details", + "digital", + "digits", + "display", + "fifteen", + "file", + "font", + "image", + "indicator", + "information", + "label", + "letter", + "letters", + "megapixel", + "megapixels", + "metadata", + "metric", + "mp", + "number", + "numbers", + "numeral", + "photo", + "photography", + "pixel", + "pixels", + "properties", + "quality", + "resolution", + "sensor", + "setting", + "specification", + "symbol", + "text", + "type", + "unit", + "value" + ], + "popularity": 608 + }, + "16MP": { + "tags": [ + "16", + "16 megapixels", + "camera", + "camera mode", + "camera resolution", + "camera settings", + "camera specs", + "digital image", + "digital photography", + "digits", + "font", + "image", + "image details", + "image information", + "image quality", + "image resolution", + "letters", + "megapixel", + "megapixel count", + "megapixels", + "mp", + "mp indicator.", + "numbers", + "photo information", + "photo resolution", + "photo settings", + "photo specs", + "photography", + "picture information", + "picture quality", + "pixel", + "pixels", + "quality", + "resolution", + "resolution indicator", + "sixteen", + "sixteen megapixels", + "sixteen mp", + "symbol", + "text", + "type" + ], + "popularity": 600 + }, + "17MP": { + "tags": [ + "17", + "camera", + "counting", + "designation", + "digits", + "double digit", + "font", + "identifier", + "image", + "index", + "label", + "letters", + "marker", + "measurement", + "megapixel", + "megapixels", + "mp", + "number 17", + "numbering", + "numbers", + "numbers 17", + "numeral", + "numeric", + "one", + "pixel", + "pixels", + "quality", + "quantity", + "reference", + "resolution", + "seven", + "seventeen", + "symbol", + "tag", + "text", + "type", + "unit", + "value" + ], + "popularity": 585 + }, + "18_UP_RATING": { + "tags": [ + "18 plus", + "18+", + "access restriction", + "adult content", + "age limit", + "age rating", + "age restriction", + "age verification", + "censorship", + "certification", + "circle", + "content rating", + "content warning", + "eighteen plus", + "eighteen+", + "explicit content", + "filtering", + "mature content", + "number 18", + "parental advisory", + "rating", + "restricted content", + "sensitive content", + "text", + "warning" + ], + "popularity": 878 + }, + "18MP": { + "tags": [ + "18", + "18mp", + "alphanumeric.", + "camera", + "camera information", + "camera sensor", + "camera settings", + "detail", + "digital camera", + "digits", + "eighteen", + "eighteen megapixels", + "eighteen mp", + "font", + "high resolution", + "image", + "image information", + "image quality", + "letters", + "megapixel", + "megapixels", + "mp", + "number", + "numbers", + "numerical", + "photo quality", + "photography", + "picture quality", + "pixel", + "pixels", + "quality", + "resolution", + "sensor", + "symbol", + "text", + "type" + ], + "popularity": 702 + }, + "19MP": { + "tags": [ + "19", + "19mp", + "camera", + "data", + "detail", + "digital", + "digits", + "feature", + "font", + "image", + "indicator", + "information", + "label", + "letter", + "letters", + "measurement", + "megapixel", + "megapixels", + "metric", + "mp", + "nineteen", + "number", + "numbers", + "numerical.", + "photo", + "photography", + "picture", + "pixel", + "pixels", + "quality", + "resolution", + "setting", + "specification", + "symbol", + "technical", + "text", + "type", + "value" + ], + "popularity": 582 + }, + "1K": { + "tags": [ + "1000", + "1k", + "abbreviation", + "alphabet", + "amount", + "character", + "count", + "counter", + "data", + "digit", + "display", + "figure", + "font", + "indicator", + "k", + "label", + "letters", + "measure", + "metric", + "number", + "numbers", + "numeric", + "numerical", + "pixel", + "pixels", + "quantity", + "rating", + "resolution", + "result", + "score", + "statistic", + "symbol", + "text", + "thousand", + "total", + "type", + "unit", + "value", + "video" + ], + "popularity": 965 + }, + "1K_PLUS": { + "tags": [ + "+", + "1000", + "1k", + "achievement", + "addition", + "alphabet", + "character", + "count", + "digit", + "display", + "figure", + "followers", + "font", + "growth", + "increase", + "letters", + "likes", + "metric", + "milestone", + "more", + "number", + "numbers", + "numeral", + "numerical", + "one thousand.", + "pixel", + "pixels", + "plus", + "plus sign", + "popularity", + "positive", + "quantity", + "resolution", + "social media", + "statistic", + "subscribers", + "success", + "symbol", + "text", + "thousand", + "thousand plus", + "type", + "value", + "video", + "views" + ], + "popularity": 889 + }, + "1X_MOBILEDATA": { + "tags": [ + "1x", + "1x signal", + "alphabet", + "cell signal", + "cellular", + "cellular data", + "character", + "connection status", + "connectivity", + "connectivity indicator", + "data connection", + "data technology", + "data type", + "digit", + "font", + "internet", + "letters", + "limited connectivity", + "low speed", + "mobile", + "mobile data", + "mobile internet", + "mobile network", + "mobiledata", + "network", + "network speed", + "network status", + "network type", + "numbers", + "phone", + "reception", + "signal", + "slow connection", + "speed", + "symbol", + "telecommunications", + "text", + "type", + "wifi", + "wireless", + "wireless data", + "wireless signal" + ], + "popularity": 1821 + }, + "20MP": { + "tags": [ + "20", + "camera", + "detail", + "digital", + "digits", + "display", + "font", + "image", + "indicator", + "info", + "information", + "label", + "letters", + "megapixel", + "megapixels", + "metric", + "mp", + "numbers", + "numeric", + "parameter", + "photo", + "photography", + "photography feature", + "photography parameter", + "photography setting", + "picture", + "pixel", + "pixels", + "quality", + "resolution", + "setting", + "size", + "specification", + "symbol", + "text", + "twenty", + "type", + "value" + ], + "popularity": 633 + }, + "21MP": { + "tags": [ + "21", + "21mp", + "camera", + "camera setting", + "clarity", + "detail", + "detailed", + "digits", + "font", + "high detail", + "high resolution", + "image", + "image size", + "indicator", + "label", + "letters", + "megapixel", + "megapixels", + "mp", + "numbers", + "photo quality", + "photo setting", + "photography", + "picture quality", + "pixel", + "pixels", + "quality", + "resolution", + "setting", + "symbol", + "text", + "twenty-one", + "type" + ], + "popularity": 594 + }, + "22MP": { + "tags": [ + "22", + "camera", + "center", + "circle", + "compass", + "connection", + "coordinates", + "crosshair", + "data", + "destination", + "digits", + "direction", + "discovery", + "earth", + "explore", + "find", + "font", + "geography", + "global", + "globe", + "gps", + "image", + "international", + "internet", + "letters", + "location", + "map", + "marker", + "megapixel", + "megapixels", + "mp", + "navigation", + "network", + "numbers", + "pin", + "pixel", + "pixels", + "place", + "point", + "position", + "quality", + "resolution", + "round", + "sphere", + "symbol", + "text", + "travel", + "type", + "web", + "world" + ], + "popularity": 603 + }, + "23MP": { + "tags": [ + "23", + "23mp", + "camera", + "clarity", + "detail", + "digital", + "digits", + "font", + "high resolution", + "image", + "information", + "letters", + "megapixel", + "megapixels", + "mp", + "numbers", + "numeric", + "photo", + "photography", + "picture", + "pixel", + "pixels", + "quality", + "resolution", + "sensor", + "setting", + "spec", + "symbol", + "technical", + "text", + "type", + "typography" + ], + "popularity": 680 + }, + "24MP": { + "tags": [ + "24", + "camera", + "data", + "detail", + "digital", + "digits", + "display", + "file", + "font", + "format", + "image", + "information", + "label", + "letters", + "measurement", + "megapixel", + "megapixels", + "metric", + "mp", + "number", + "numbers", + "option", + "photo", + "photography", + "pixel", + "pixels", + "quality", + "resolution", + "setting", + "size", + "specification", + "symbol", + "technical", + "text", + "twentyfour", + "type" + ], + "popularity": 1039 + }, + "2K": { + "tags": [ + "2000", + "2k", + "abbreviation", + "alphabet", + "character", + "characters", + "digit", + "display", + "font", + "high quality", + "higher resolution", + "k", + "letter", + "letters", + "media", + "media controls", + "movie", + "number", + "numbers", + "numerical", + "option", + "pixel", + "pixels", + "playback", + "player", + "quality", + "resolution", + "screen", + "settings", + "streaming", + "symbol", + "television", + "text", + "toggle", + "type", + "video", + "video quality", + "video resolution", + "video settings" + ], + "popularity": 888 + }, + "2K_PLUS": { + "tags": [ + "+", + "2000 plus", + "2000+", + "2k", + "2k plus", + "2k+", + "alphabet", + "character", + "clarity", + "definition", + "digit", + "digital", + "display", + "font", + "format", + "hd", + "high definition", + "letters", + "media controls", + "movie quality", + "numbers", + "picture quality", + "playback", + "plus", + "quality settings", + "resolution", + "screen resolution", + "streaming", + "streaming quality", + "symbol", + "text", + "tv quality", + "two thousand k", + "two thousand plus", + "type", + "uhd", + "ultra hd", + "video quality", + "video settings", + "video standard" + ], + "popularity": 679 + }, + "2MP": { + "tags": [ + "2", + "2mp", + "camera", + "camera sensor", + "detail", + "digit", + "digital", + "font", + "frame", + "image", + "information", + "letters", + "measurement", + "megapixel", + "megapixels", + "metric", + "mp", + "number", + "number 2", + "numbers", + "photo", + "photography", + "pixel", + "pixels", + "quality", + "rectangle", + "resolution", + "size", + "specification", + "square", + "symbol", + "text", + "two", + "type", + "unit", + "video", + "videography" + ], + "popularity": 600 + }, + "30FPS": { + "tags": [ + "30fps", + "alphabet", + "camera", + "character", + "digit", + "film", + "font", + "fps", + "frame rate", + "frame rate setting", + "frames", + "letters", + "media information", + "media settings", + "multimedia", + "numbers", + "playback", + "quality", + "recording", + "resolution", + "settings", + "symbol", + "text", + "thirty fps", + "thirty frames per second", + "type", + "video", + "video capture", + "video control", + "video display", + "video frame rate", + "video information", + "video options", + "video playback quality", + "video quality", + "video settings", + "video speed" + ], + "popularity": 1395 + }, + "30FPS_SELECT": { + "tags": [ + "30", + "30fps", + "camera", + "capture", + "choose", + "digital video", + "digits", + "fps", + "frame", + "frame rate", + "frame.", + "frames per second", + "frequency", + "image", + "media", + "motion", + "numbers", + "option", + "per", + "playback", + "quality", + "rate", + "record", + "recording", + "second", + "seconds", + "select", + "selection", + "setting", + "settings", + "speed", + "stream", + "streaming", + "video", + "video option", + "video quality", + "video rate", + "video setting", + "video speed" + ], + "popularity": 1136 + }, + "360": { + "tags": [ + "360", + "360 degrees", + "around", + "arrow", + "av", + "camera", + "circle", + "circular", + "complete", + "control", + "degree", + "digital", + "direction", + "full view", + "immersive", + "interactive", + "movement", + "multimedia", + "navigation", + "panoramic", + "perspective", + "photo", + "rotate", + "rotation", + "sphere", + "spin", + "turn", + "user interface", + "video", + "view", + "virtual reality", + "visual", + "vr", + "web" + ], + "popularity": 9510 + }, + "3D_ROTATION": { + "tags": [ + "3", + "3d", + "alphabet", + "angle", + "application", + "arrow", + "arrows", + "av", + "axis", + "button", + "camera", + "character", + "control", + "d", + "digit", + "font", + "graphic", + "letters", + "manipulation", + "menu", + "model", + "numbers", + "object", + "option", + "orientation", + "perspective", + "rendering", + "revolve", + "rotate", + "rotation", + "shape", + "software", + "spatial", + "spin", + "symbol", + "text", + "three-dimensional", + "tilt", + "tool", + "transform", + "turning", + "type", + "view", + "virtual_reality", + "visualization", + "vr" + ], + "popularity": 15371 + }, + "3G_MOBILEDATA": { + "tags": [ + "3g", + "alphabet", + "bandwidth", + "bars", + "broadband", + "cellular", + "character", + "communication", + "computer", + "connection", + "connectivity", + "data", + "device", + "digit", + "digital", + "download", + "font", + "full bars", + "high speed", + "internet", + "letters", + "mobile", + "mobile data", + "mobiledata", + "network", + "numbers", + "online", + "phone", + "signal", + "speed", + "strong signal", + "symbol", + "tablet", + "technology", + "telecommunications", + "text", + "transfer", + "type", + "upload", + "wifi", + "wireless" + ], + "popularity": 1191 + }, + "3K": { + "tags": [ + "3000", + "3k", + "alphabet", + "character", + "cinema", + "definition", + "digit", + "digital", + "display", + "film", + "font", + "high quality video", + "letters", + "media", + "movie", + "numbers", + "pixel", + "pixels", + "playback setting", + "resolution", + "screen", + "stream quality", + "streaming", + "streaming service", + "symbol", + "technology", + "television", + "text", + "three k", + "tv show", + "type", + "video", + "video playback", + "video player", + "video quality", + "video resolution", + "video setting" + ], + "popularity": 721 + }, + "3K_PLUS": { + "tags": [ + "+", + "3000", + "3000 plus", + "3000+", + "3k", + "3k plus", + "3k+", + "achievement", + "addition", + "alphabet", + "amount", + "character", + "counter", + "data", + "digit", + "display", + "font", + "greater than", + "indicator", + "k.", + "letters", + "limit", + "metric", + "milestone", + "more", + "number", + "numbers", + "numeral", + "pixel", + "pixels", + "plus", + "quantity", + "resolution", + "statistic", + "symbol", + "text", + "thousand", + "three", + "three thousand", + "threshold", + "type", + "value", + "video", + "volume" + ], + "popularity": 673 + }, + "3MP": { + "tags": [ + "3", + "3mp", + "camera", + "clarity", + "definition", + "digit", + "digital media", + "display", + "file format", + "file information", + "font", + "format indicator", + "high definition", + "image", + "image quality", + "letters", + "media", + "media file", + "megapixel", + "megapixels", + "mp", + "numbers", + "option", + "photography", + "picture quality", + "pixel", + "pixels", + "preference", + "quality", + "quality setting", + "resolution", + "setting", + "standard definition", + "symbol", + "text", + "type", + "video", + "video file", + "video resolution" + ], + "popularity": 618 + }, + "3P": { + "tags": [ + "3", + "3p", + "account", + "avatar", + "avatar group", + "bubble", + "business", + "chat", + "collaboration", + "comment", + "communicate", + "community", + "community icon", + "company", + "face", + "figures", + "group", + "group icon", + "human", + "members", + "message", + "multiple people", + "networking", + "organization", + "party", + "people", + "person", + "profile", + "profile group", + "silhouettes", + "social", + "speech", + "staff", + "staff icon", + "team", + "team icon", + "three people", + "triple person", + "user", + "users", + "users group", + "users icon" + ], + "popularity": 8392 + }, + "4G_MOBILEDATA": { + "tags": [ + "4g", + "alphabet", + "bandwidth", + "cellular", + "cellular data", + "character", + "communication", + "connection", + "connectivity", + "data", + "digit", + "edge", + "font", + "four g", + "gprs", + "high speed", + "hspa", + "indicator", + "internet", + "letters", + "lte", + "mobile", + "mobile data", + "mobiledata", + "network", + "network strength", + "numbers", + "phone", + "signal", + "speed", + "status", + "symbol", + "telecommunication", + "text", + "type", + "umts", + "wifi", + "wireless" + ], + "popularity": 2049 + }, + "4G_PLUS_MOBILEDATA": { + "tags": [ + "4g", + "4g plus", + "4g+", + "advanced data", + "alphabet", + "carrier", + "cell phone", + "cellular", + "cellular data", + "character", + "communication", + "connection", + "connectivity", + "data connection", + "data network", + "data usage", + "digit", + "fast speed", + "font", + "internet", + "letters", + "mobile", + "mobile data", + "mobiledata", + "network", + "network speed", + "network status", + "numbers", + "phone", + "plus", + "signal", + "signal strength", + "speed", + "symbol", + "technology", + "telecommunications", + "text", + "type", + "upgraded network", + "wifi", + "wireless", + "wireless data" + ], + "popularity": 1360 + }, + "4K": { + "tags": [ + "4000", + "4k", + "alphabet", + "alphanumeric", + "character", + "cinema", + "content", + "definition", + "digit", + "digital", + "display", + "film", + "font", + "graphic", + "high resolution", + "indicator", + "label", + "letters", + "media", + "movie", + "numbers", + "pixel", + "pixels", + "playback", + "quality", + "quality setting", + "resolution", + "screen", + "streaming", + "symbol", + "technology", + "television", + "text", + "type", + "ultra hd", + "video" + ], + "popularity": 2038 + }, + "4K_PLUS": { + "tags": [ + "+", + "4000", + "4k", + "addition", + "alphabet", + "character", + "digit", + "digital", + "display", + "equation", + "font", + "high definition", + "letters", + "media", + "monitor", + "multimedia", + "numbers", + "pixel", + "pixels", + "plus", + "quality", + "resolution", + "screen", + "streaming", + "symbol", + "technology", + "television", + "text", + "type", + "video" + ], + "popularity": 978 + }, + "4MP": { + "tags": [ + "4", + "4mp", + "aspect ratio", + "camera", + "clarity", + "data", + "detail", + "digit", + "dimension", + "display", + "font", + "four", + "image", + "indicator", + "information", + "label", + "letters", + "measurement", + "mega", + "megapixel", + "megapixels", + "metadata", + "metric", + "mp", + "numbers", + "photo", + "photography", + "picture", + "pixel", + "pixels", + "quality", + "resolution", + "setting", + "size", + "specification", + "symbol", + "text", + "type", + "visual", + "watermark" + ], + "popularity": 573 + }, + "5G": { + "tags": [ + "5g", + "alphabet", + "cellular", + "character", + "communication", + "connection", + "connectivity", + "data", + "data connection", + "digit", + "fifth generation", + "font", + "future", + "high speed", + "icon", + "indicator", + "internet", + "letters", + "mobile", + "mobile data", + "mobile network", + "modern", + "network", + "network status", + "numbers", + "performance", + "phone", + "signal", + "speed", + "status", + "strength", + "symbol", + "technology", + "telecommunications", + "text", + "type", + "wifi", + "wireless", + "wireless network" + ], + "popularity": 2674 + }, + "5K": { + "tags": [ + "5000", + "5k", + "alphabet", + "character", + "clarity", + "crispness", + "definition", + "detail", + "digit", + "display", + "display setting", + "five k", + "five thousand", + "font", + "format", + "high definition", + "high quality", + "letters", + "movie quality", + "numbers", + "pixel", + "pixels", + "playback quality", + "quality indicator", + "resolution", + "screen resolution", + "streaming quality", + "symbol", + "text", + "type", + "uhd", + "ultra high definition", + "video", + "video clarity", + "video quality", + "video resolution", + "video settings", + "visual quality" + ], + "popularity": 746 + }, + "5K_PLUS": { + "tags": [ + "+", + "5000", + "5k", + "addition", + "alphabet", + "amount", + "character", + "count", + "count display.", + "data", + "data point", + "digit", + "display", + "five", + "five thousand", + "font", + "letters", + "limit", + "limit reached", + "metric", + "metric display", + "more than", + "number", + "number symbol", + "numbers", + "numerical", + "numerical value", + "over", + "pixel", + "pixels", + "plus", + "plus sign", + "quantity", + "quantity indicator", + "resolution", + "statistic", + "sum", + "symbol", + "text", + "thousand", + "threshold", + "type", + "value", + "video" + ], + "popularity": 686 + }, + "5MP": { + "tags": [ + "5", + "5mp", + "camera", + "capture", + "clarity", + "detail", + "digit", + "digital", + "five", + "five megapixels", + "font", + "image", + "indicator", + "information", + "letters", + "megapixel", + "megapixels", + "mp", + "number", + "numbers", + "option", + "performance", + "photo", + "photography", + "picture", + "pixel", + "pixels", + "quality", + "resolution", + "sensor", + "setting", + "size", + "specification", + "square", + "symbol", + "technology", + "text", + "type", + "video", + "videography" + ], + "popularity": 616 + }, + "60FPS": { + "tags": [ + "60fps", + "camera", + "capture", + "cinema", + "control", + "definition", + "digit", + "display", + "editing", + "film", + "fps", + "frame rate", + "frames", + "high speed", + "indicator", + "label", + "media", + "number", + "numbers", + "numeric", + "option", + "performance", + "playback", + "production", + "quality", + "recording", + "resolution", + "settings", + "smooth", + "streaming", + "symbol", + "text", + "video", + "video quality" + ], + "popularity": 1145 + }, + "60FPS_SELECT": { + "tags": [ + "60", + "60fps", + "camera", + "choice", + "circle", + "circular", + "configuration", + "control", + "digits", + "film", + "fps", + "frame", + "frame rate", + "frames per second", + "frequency", + "indicator", + "label", + "media", + "media player", + "movie", + "number", + "numbers", + "numeric", + "option", + "per", + "performance", + "playback", + "preference", + "quality", + "rate", + "second", + "seconds", + "select", + "selection", + "settings", + "speed", + "text", + "video", + "video playback", + "video settings" + ], + "popularity": 1065 + }, + "6_FT_APART": { + "tags": [ + "6", + "6 feet", + "apart", + "body", + "caution", + "covid", + "covid-19", + "distance", + "feet", + "figures", + "ft", + "guideline", + "health", + "health and safety", + "horizontal", + "human", + "instruction", + "line", + "measure", + "measurement", + "pandemic", + "people", + "person", + "public health", + "rule", + "safe distance", + "safety", + "separate", + "separation", + "social", + "social distancing", + "spacing", + "standing", + "two people", + "warning" + ], + "popularity": 2494 + }, + "6K": { + "tags": [ + "6000", + "6k", + "alphabet", + "character", + "clarity", + "definition", + "detail", + "digit", + "digital", + "display", + "enhanced", + "font", + "format", + "high definition", + "high resolution", + "indicator", + "letters", + "media", + "movie", + "multimedia", + "numbers", + "option", + "pixel", + "pixels", + "playback", + "premium", + "quality", + "resolution", + "screen", + "setting", + "streaming", + "symbol", + "television", + "text", + "type", + "video", + "video quality", + "visual" + ], + "popularity": 659 + }, + "6K_PLUS": { + "tags": [ + "+", + "6000", + "6k", + "achievement", + "alphabet", + "amount", + "approximation", + "badge", + "character", + "counter", + "data", + "digit", + "display", + "estimate", + "font", + "greater than", + "indicator", + "label", + "letters", + "measurement", + "metric", + "milestone", + "minimum", + "more than", + "number", + "numbers", + "numeral", + "over", + "pixel", + "pixels", + "plus", + "plus sign", + "quantity", + "resolution", + "six thousand", + "statistic", + "symbol", + "text", + "threshold", + "type", + "value", + "video" + ], + "popularity": 655 + }, + "6MP": { + "tags": [ + "6", + "camera", + "camera info", + "camera mode", + "camera settings", + "detail level", + "digit", + "digital photography", + "file information", + "font", + "high resolution", + "image", + "image information", + "image options", + "image quality", + "image size", + "letters", + "megapixel", + "megapixels", + "metadata", + "mp", + "numbers", + "options", + "photo data", + "photo options", + "photo resolution", + "photo size", + "photography", + "picture detail", + "picture info", + "pixel", + "pixels", + "quality", + "quality indicator", + "quality setting", + "resolution", + "resolution info", + "setting", + "symbol", + "text", + "type" + ], + "popularity": 564 + }, + "7K": { + "tags": [ + "7000", + "7k", + "abbreviation", + "alphabet", + "broadcast", + "channel", + "character", + "content", + "content rating", + "definition", + "digit", + "display", + "film rating", + "font", + "high definition", + "high resolution", + "letters", + "media", + "movie rating", + "numbers", + "numbers 7k", + "pixel", + "pixels", + "quality", + "resolution", + "seven thousand", + "source", + "standard definition", + "streaming", + "symbol", + "television rating", + "text", + "text 7k", + "title", + "tv rating", + "type", + "video", + "video resolution" + ], + "popularity": 681 + }, + "7K_PLUS": { + "tags": [ + "+", + "7000", + "7000 plus", + "7000+", + "7k", + "7k+", + "achievement", + "add", + "addition", + "alphabet", + "amount", + "character", + "count", + "counter", + "data", + "digit", + "display", + "font", + "increase", + "indicator", + "label", + "letters", + "marker", + "measurement", + "metric", + "milestone", + "more than", + "number", + "numbers", + "pixel", + "pixels", + "plus", + "quantity", + "rating", + "resolution", + "score", + "statistics", + "symbol", + "text", + "threshold", + "total", + "type", + "value", + "video" + ], + "popularity": 657 + }, + "7MP": { + "tags": [ + "7", + "action", + "active", + "animation", + "buffering", + "busy", + "camera", + "circle", + "circular", + "connection", + "continuous", + "cycle", + "dashed", + "data", + "digit", + "dotted", + "font", + "image", + "indicator", + "internet", + "letters", + "loading", + "loop", + "megapixel", + "megapixels", + "mp", + "network", + "numbers", + "pixel", + "pixels", + "processing", + "progress", + "quality", + "refresh", + "reload", + "resolution", + "ring", + "round", + "spinning", + "symbol", + "sync", + "synchronize", + "text", + "type", + "waiting" + ], + "popularity": 589 + }, + "8K": { + "tags": [ + "8000", + "8k", + "alphabet", + "character", + "cinema quality", + "digit", + "display", + "display settings", + "font", + "high definition", + "letters", + "media quality", + "movie quality", + "multimedia settings", + "numbers", + "numeric", + "pixel", + "pixels", + "playback settings", + "quality", + "resolution", + "screen settings", + "streaming quality", + "symbol", + "text", + "type", + "uhd", + "uhd 8k", + "ultra high definition", + "video", + "video definition", + "video quality", + "video resolution", + "video settings", + "video stream", + "visual quality" + ], + "popularity": 822 + }, + "8K_PLUS": { + "tags": [ + "+", + "7000", + "8k", + "advanced", + "alphabet", + "character", + "cinema", + "clear", + "definition", + "digit", + "digital", + "display", + "enhanced", + "entertainment", + "font", + "high definition", + "image", + "letters", + "media", + "monitor", + "numbers", + "picture", + "pixel", + "pixels", + "playback", + "plus", + "quality", + "resolution", + "screen", + "sharp", + "streaming", + "symbol", + "technology", + "television", + "text", + "type", + "uhd", + "ultra high definition", + "video", + "video quality", + "viewing experience", + "visual" + ], + "popularity": 740 + }, + "8MP": { + "tags": [ + "8", + "8mp", + "camera", + "capture", + "detail", + "device", + "digit", + "digital", + "equipment", + "font", + "image", + "lens", + "letters", + "megapixel", + "megapixels", + "mp", + "number", + "numbers", + "performance", + "photo", + "photography", + "pixel", + "pixels", + "quality", + "resolution", + "sensor", + "specification", + "symbol", + "text", + "type" + ], + "popularity": 572 + }, + "9K": { + "tags": [ + "9000", + "9k", + "alphabet", + "character", + "clarity", + "content", + "definition", + "digit", + "digital", + "display", + "font", + "high definition", + "indicator", + "label", + "letters", + "marking", + "media", + "monitor", + "movie", + "nine k", + "numbers", + "performance", + "pixel", + "pixels", + "playback", + "quality", + "rating", + "resolution", + "screen", + "specification", + "stream", + "symbol", + "tag", + "technical", + "television", + "text", + "type", + "video" + ], + "popularity": 670 + }, + "9K_PLUS": { + "tags": [ + "+", + "9000", + "9k", + "achievement", + "alphabet", + "amount", + "analytic", + "calculation", + "character", + "count", + "data", + "digit", + "display", + "equation", + "font", + "indicator", + "letters", + "level", + "limit", + "math", + "measurement", + "metric", + "milestone", + "more than", + "number", + "numbers", + "over", + "performance", + "pixel", + "pixels", + "plus", + "quantitative", + "ranking", + "rating", + "resolution", + "symbol", + "text", + "threshold", + "type", + "value", + "video" + ], + "popularity": 741 + }, + "9MP": { + "tags": [ + "9", + "9 megapixel", + "9 mp", + "9mp", + "camera", + "camera icon", + "camera resolution", + "camera settings", + "digit", + "digital camera", + "file format", + "file size", + "font", + "format", + "image", + "image format", + "image icon", + "image quality", + "letters", + "megapixel", + "megapixels", + "mp", + "nine", + "nine megapixel", + "numbers", + "photo icon", + "photo resolution", + "photo size", + "photography", + "picture quality", + "pixel", + "pixels", + "quality", + "quality indicator", + "quality setting", + "resolution", + "resolution indicator", + "resolution setting", + "symbol", + "text", + "type", + "video quality", + "video resolution", + "video size", + "videography" + ], + "popularity": 565 + }, + "ABC": { + "tags": [ + "absent", + "alphabet", + "bare", + "blank", + "character", + "clean", + "clear", + "empty", + "featureless", + "font", + "invisible", + "letters", + "minimal", + "neutral", + "no icon", + "no image", + "nothing", + "null", + "placeholder", + "plain", + "pristine", + "space", + "symbol", + "text", + "transparent", + "type", + "undefined", + "undepicted", + "unillustrated", + "unimaged", + "unrepresented", + "unseen", + "unstyled", + "untouched", + "unvisualized", + "void", + "white" + ], + "popularity": 3777 + }, + "AC_UNIT": { + "tags": [ + "ac", + "air", + "air conditioning", + "asterisk", + "climate", + "cold", + "condition", + "conditioner", + "control", + "cool", + "cooling", + "crystal", + "flake", + "frost", + "frozen", + "ice", + "point", + "points", + "polygon", + "six pointed star", + "six points", + "snow", + "snowflake", + "star", + "temperature", + "unit", + "weather", + "winter" + ], + "popularity": 19764 + }, + "ACCESS_ALARM": { + "tags": [ + "access", + "adjust", + "alarm", + "alert", + "appointment", + "bell", + "calendar", + "circle", + "clock", + "control", + "deadline", + "future", + "hands", + "history", + "indicator", + "manage", + "mark", + "notification", + "point", + "reminder", + "ring", + "schedule", + "setting", + "sound", + "time", + "timer", + "wake up", + "watch" + ], + "popularity": 2857 + }, + "ACCESS_ALARMS": { + "tags": [ + "access", + "adjust", + "alarm", + "alert", + "appointment", + "bell", + "calendar", + "circle", + "clock", + "control", + "deadline", + "future", + "hands", + "history", + "indicator", + "manage", + "mark", + "notification", + "point", + "reminder", + "ring", + "schedule", + "setting", + "sound", + "time", + "timer", + "wake up", + "watch" + ], + "popularity": 2739 + }, + "ACCESS_TIME": { + "tags": [ + "alarm", + "appointment", + "calendar", + "chronometer", + "clock", + "countdown", + "date", + "deadline", + "delay", + "duration", + "event", + "future", + "history", + "hour", + "minute", + "organize", + "past", + "pending", + "period", + "plan", + "present", + "reminder", + "schedule", + "second", + "stopwatch", + "time", + "timer", + "upcoming", + "waiting", + "watch" + ], + "popularity": 13941 + }, + "ACCESS_TIME_FILLED": { + "tags": [ + "alarm", + "appointment", + "calendar", + "chronometer", + "clock", + "countdown", + "date", + "deadline", + "delay", + "duration", + "event", + "future", + "history", + "hour", + "minute", + "organize", + "past", + "pending", + "period", + "plan", + "present", + "reminder", + "schedule", + "second", + "stopwatch", + "time", + "timer", + "upcoming", + "waiting", + "watch" + ], + "popularity": 6677 + }, + "ACCESSIBILITY": { + "tags": [ + "access", + "accessibility", + "accessible", + "aid", + "assistance", + "barrier-free", + "body", + "disability", + "disabled", + "easy access", + "feature", + "figure", + "handicap", + "help", + "human", + "inclusion", + "inclusive", + "inclusivity", + "mobility", + "navigation", + "options", + "people", + "person", + "pictogram", + "ramp", + "services", + "setting", + "special needs", + "support", + "symbol", + "universal", + "wheelchair" + ], + "popularity": 28048 + }, + "ACCESSIBILITY_NEW": { + "tags": [ + "access", + "accessibility", + "accessibility icon", + "accessibility statement", + "accessible", + "assistance", + "barrier-free", + "body", + "disability", + "disabled", + "figure", + "handicap", + "help", + "human", + "inclusion", + "inclusive", + "moving", + "needs", + "new", + "outline", + "people", + "person", + "pictogram", + "shape", + "silhouette", + "special needs", + "standing", + "support", + "symbol", + "universal access", + "user" + ], + "popularity": 26181 + }, + "ACCESSIBLE": { + "tags": [ + "accessibility", + "accessible", + "assistance", + "body", + "disability", + "disabled", + "easy access", + "facilities", + "figure", + "handicap", + "handicapped", + "healthcare", + "help", + "human", + "information", + "international symbol", + "medical", + "mobility", + "mobility impaired", + "parking", + "people", + "person", + "public access", + "ramp", + "services", + "sign", + "support", + "symbol", + "toilet", + "transport", + "wheelchair" + ], + "popularity": 14862 + }, + "ACCESSIBLE_FORWARD": { + "tags": [ + "accessibility", + "accessible", + "arrow", + "arrow right", + "body", + "continue", + "direction", + "figure", + "forward", + "geometric", + "graphic", + "handicap", + "help", + "human", + "icon", + "mobility", + "movement", + "navigation", + "next", + "people", + "person", + "pictogram", + "progress", + "right", + "shape", + "silhouette", + "symbol", + "ui element", + "user", + "wheelchair" + ], + "popularity": 7165 + }, + "ACCOUNT_BALANCE": { + "tags": [ + "account", + "accounting", + "balance", + "bank", + "banking", + "bill", + "building", + "business", + "card", + "cash", + "coin", + "columns", + "commerce", + "courthouse", + "credit", + "currency", + "dollars", + "economic", + "federal", + "finance", + "financial", + "financial institution", + "government", + "institution", + "investment", + "loan", + "money", + "mortgage", + "online", + "pay", + "payment", + "pillars", + "prosperity", + "savings", + "structure", + "transaction", + "treasury", + "wealth" + ], + "popularity": 92548 + }, + "ACCOUNT_BALANCE_WALLET": { + "tags": [ + "account", + "assets", + "balance", + "bank", + "banking", + "bill", + "budget", + "card", + "cash", + "coin", + "commerce", + "credit", + "credit card", + "currency", + "dollar", + "dollars", + "economics", + "economy", + "expense", + "finance", + "finances", + "financial", + "funds", + "income", + "investment", + "money", + "online", + "pay", + "payment", + "purse", + "rectangle", + "revenue", + "savings", + "square", + "transaction", + "wallet", + "wealth" + ], + "popularity": 73810 + }, + "ACCOUNT_BOX": { + "tags": [ + "account", + "account icon", + "accounts", + "avatar", + "box", + "bust", + "contact", + "contact icon", + "face", + "figure", + "head", + "human", + "identity", + "individual", + "login", + "man", + "member", + "outline", + "people", + "person", + "person outline", + "person symbol", + "profile", + "register", + "shape", + "shoulders", + "sign in", + "sign up", + "silhouette", + "square", + "thumbnail", + "user", + "user icon", + "user profile" + ], + "popularity": 50499 + }, + "ACCOUNT_CIRCLE": { + "tags": [ + "account", + "account circle", + "account details", + "account icon", + "account management", + "account settings", + "avatar", + "bust", + "circle", + "face", + "filled account", + "full account", + "head", + "human", + "login", + "my account", + "people", + "person", + "person icon", + "personal", + "personal information", + "personal mode", + "profile", + "profile icon", + "shoulders", + "sign in", + "thumbnail", + "user", + "user icon", + "user profile", + "user settings" + ], + "popularity": 644148 + }, + "ACCOUNT_TREE": { + "tags": [ + "account", + "account structure", + "analytics", + "branches", + "chart", + "connect", + "connected", + "connections", + "corporate structure", + "data", + "diagram", + "flow", + "graph", + "grouped", + "hierarchy", + "infographic", + "layers", + "levels", + "linked", + "management", + "mapping", + "measure", + "metrics", + "nested", + "network", + "nodes", + "organization", + "organizational chart", + "outline", + "process", + "project structure", + "relationships", + "square", + "statistics", + "structure", + "system", + "team structure", + "tracking", + "tree", + "tree structure", + "visual hierarchy" + ], + "popularity": 48173 + }, + "AD_UNITS": { + "tags": [ + "ad", + "ad units", + "advertising", + "android", + "article", + "banner", + "block", + "body", + "body text", + "cell", + "cell phone", + "communication", + "content", + "data", + "device", + "display", + "email", + "hardware", + "information", + "ios", + "lines", + "marketing", + "message", + "message content", + "mobile", + "mobile text", + "news", + "notification", + "notifications", + "os", + "paragraph", + "phone", + "rectangles", + "screen", + "smartphone", + "sms", + "tablet", + "text", + "text message", + "top", + "units", + "writing" + ], + "popularity": 3238 + }, + "ADB": { + "tags": [ + "adb", + "android", + "bridge", + "bug", + "code", + "command", + "computing", + "connect", + "connection", + "data", + "debug", + "debugger", + "developer", + "development", + "device", + "line", + "link", + "mobile", + "phone", + "port", + "programming", + "shell", + "software", + "technology", + "terminal", + "test", + "testing", + "tool", + "transfer", + "usb" + ], + "popularity": 5054 + }, + "ADD": { + "tags": [ + "+", + "add", + "addition", + "append", + "arithmetic", + "attach", + "combine", + "create", + "cross", + "expand", + "grow", + "increase", + "insert", + "join", + "mathematical symbol", + "merge", + "more", + "new", + "plus", + "positive", + "sum", + "symbol", + "total", + "two lines" + ], + "popularity": 351934 + }, + "ADD_A_PHOTO": { + "tags": [ + "+", + "a photo", + "add", + "album", + "button", + "camera", + "capture", + "create", + "file", + "gallery", + "graphic", + "icon", + "image", + "input", + "insert", + "interface", + "lens", + "library", + "media", + "new", + "photo", + "photograph", + "photography", + "picture", + "plus", + "shutter", + "symbol", + "ui", + "ui element", + "upload", + "ux", + "visual" + ], + "popularity": 36921 + }, + "ADD_ALARM": { + "tags": [ + "add", + "add alarm", + "alarm", + "alert", + "app", + "appointment", + "audio", + "bell", + "clock", + "create", + "digital", + "event", + "mobile", + "morning", + "new alarm", + "notification", + "phone", + "plus", + "reminder", + "ring", + "schedule", + "set", + "setting", + "sound", + "task", + "time", + "timer", + "wake up", + "watch" + ], + "popularity": 1477 + }, + "ADD_ALERT": { + "tags": [ + "+", + "active", + "add", + "add attention", + "add important", + "add notification", + "add reminder", + "add warning", + "alarm", + "alert", + "attention", + "bell", + "caution", + "chime", + "create", + "create alarm", + "danger", + "exclamation", + "important", + "message", + "new", + "notice", + "notification", + "notifications", + "notify", + "plus", + "remind", + "reminder", + "ring", + "set reminder", + "sound", + "subscribe", + "subscribe to alerts", + "symbol", + "warning" + ], + "popularity": 7264 + }, + "ADD_BOX": { + "tags": [ + "action", + "add", + "addition", + "border", + "box", + "build", + "button", + "construct", + "container", + "content", + "control", + "create", + "element", + "empty", + "feature", + "form", + "frame", + "function", + "geometric", + "geometry", + "insert", + "item", + "new", + "new square", + "object", + "outline", + "plus", + "shape", + "square", + "stroke", + "symbol" + ], + "popularity": 44933 + }, + "ADD_BUSINESS": { + "tags": [ + "+", + "add", + "add building", + "add business", + "add business location", + "add location", + "bill", + "building", + "building and plus", + "building with plus", + "business", + "business location", + "card", + "cash", + "coin", + "commerce", + "company", + "corporate", + "create", + "credit", + "currency", + "dollars", + "enterprise", + "establishment", + "institution", + "location", + "map marker", + "market", + "marketplace", + "money", + "new", + "office", + "online", + "organization", + "pay", + "payment", + "pin", + "plus", + "point of interest", + "retail", + "shop", + "shopping", + "store", + "storefront", + "structure", + "symbol" + ], + "popularity": 11033 + }, + "ADD_CARD": { + "tags": [ + "+", + "account", + "add", + "add card", + "add credit card", + "add debit card", + "add payment", + "banking", + "bill", + "billing", + "border", + "card", + "cash", + "checkout", + "coin", + "commerce", + "cost", + "create", + "credit", + "credit card", + "currency", + "debit card", + "dollars", + "finance", + "financial", + "money", + "new", + "new card", + "online", + "outline", + "pay", + "payment", + "payment method", + "plus", + "plus sign", + "price", + "rectangle", + "shape", + "shopping", + "square", + "symbol", + "transaction", + "wallet" + ], + "popularity": 7162 + }, + "ADD_CHART": { + "tags": [ + "+", + "add", + "analysis", + "analytics", + "bar", + "bar chart", + "bars", + "business", + "chart", + "create", + "dashboard", + "data", + "diagram", + "financial", + "graph", + "growth", + "increase", + "infographic", + "information", + "insert", + "line graph", + "measure", + "metric", + "metrics", + "new", + "performance", + "plus", + "presentation", + "report", + "representation", + "statistics", + "symbol", + "tracking", + "trend", + "visual" + ], + "popularity": 5027 + }, + "ADD_CIRCLE": { + "tags": [ + "+", + "action", + "add", + "append", + "button", + "circle", + "circular", + "content", + "control", + "counter", + "create", + "data", + "document", + "element", + "entry", + "file", + "form", + "generate", + "increase", + "insert", + "item", + "list", + "make", + "new", + "option", + "outline", + "plus", + "point", + "record", + "round", + "row", + "tool" + ], + "popularity": 134380 + }, + "ADD_CIRCLE_OUTLINE": { + "tags": [ + "+", + "action", + "add", + "append", + "button", + "circle", + "circular", + "content", + "control", + "create", + "data", + "document", + "element", + "entry", + "file", + "form", + "generate", + "increase", + "insert", + "item", + "list", + "make", + "new", + "option", + "outline", + "plus", + "point", + "record", + "round", + "row", + "tool" + ], + "popularity": 150073 + }, + "ADD_COMMENT": { + "tags": [ + "+", + "add", + "annotation", + "append", + "bubble", + "chat", + "comment", + "communicate", + "communication", + "conversation", + "create", + "dialog", + "discourse", + "discuss", + "feedback", + "include", + "input", + "insert", + "join", + "message", + "new", + "note", + "notetaking", + "plus", + "reply", + "response", + "social", + "speech", + "speech bubble", + "symbol", + "talk", + "text", + "writing" + ], + "popularity": 10015 + }, + "ADD_HOME": { + "tags": [ + "accommodation", + "add", + "append", + "architecture", + "attach", + "building", + "button", + "construction", + "create", + "cross", + "dwelling", + "enter", + "home", + "house", + "include", + "increase", + "insert", + "location", + "navigation", + "new", + "plus", + "property", + "real estate", + "register", + "residence", + "residential", + "shelter", + "structure", + "suburban", + "urban" + ], + "popularity": 1840 + }, + "ADD_HOME_WORK": { + "tags": [ + "add", + "add building", + "add business", + "add home", + "add house", + "add office", + "add project", + "add task", + "add work", + "address", + "briefcase", + "building", + "business", + "construction", + "create", + "home", + "house", + "job", + "location", + "management", + "new", + "office", + "plus", + "project", + "property", + "real estate", + "residential", + "task", + "work" + ], + "popularity": 1850 + }, + "ADD_IC_CALL": { + "tags": [ + "+", + "action", + "add", + "add call", + "app icon", + "basic", + "button", + "call", + "cell", + "communications", + "contact", + "create", + "device", + "dial", + "graphic", + "hardware", + "icon", + "interface", + "isolated", + "line", + "make call", + "minimalist", + "mobile", + "mobile icon", + "new", + "new call", + "outline", + "phone", + "plus", + "simple", + "symbol", + "telephone", + "ui icon", + "ux icon", + "vector", + "web icon" + ], + "popularity": 5156 + }, + "ADD_LINK": { + "tags": [ + "add", + "add link", + "anchor", + "associate", + "attach", + "build", + "chain", + "clip", + "combine", + "connect", + "connection", + "create", + "cross", + "form", + "hyperlink", + "internet", + "join", + "joint", + "link", + "link symbol", + "merge", + "network", + "new", + "plus", + "plus symbol", + "share", + "social media", + "symbol", + "tie", + "url", + "web", + "website" + ], + "popularity": 10282 + }, + "ADD_LOCATION": { + "tags": [ + "+", + "add", + "address", + "check in", + "coordinate", + "create", + "destination", + "direction", + "event", + "geo", + "geolocate", + "insert", + "location", + "map", + "maps", + "mark", + "marker", + "navigation", + "new", + "pin", + "pinpoint", + "place", + "plus", + "poi", + "point of interest", + "position", + "restaurant", + "route", + "save", + "spot", + "store", + "symbol", + "tag", + "travel" + ], + "popularity": 6837 + }, + "ADD_LOCATION_ALT": { + "tags": [ + "+", + "add", + "address", + "coordinate", + "create", + "destination", + "direction", + "directory", + "discover", + "entry", + "find", + "geographic", + "geotag", + "gps", + "insert", + "location", + "map", + "maps", + "mark", + "marker", + "navigation", + "new", + "pin", + "place", + "plus", + "point", + "position", + "save", + "set", + "specify", + "spot", + "symbol", + "target", + "travel" + ], + "popularity": 8291 + }, + "ADD_MODERATOR": { + "tags": [ + "+", + "add", + "add administrator", + "add member", + "add moderator", + "add person", + "add profile", + "add user", + "administrator", + "certified", + "human icon", + "invite member", + "invite person", + "invite user", + "man icon", + "member icon", + "moderator", + "new", + "new administrator", + "new member", + "new moderator", + "new person", + "new profile", + "new user", + "person icon", + "plus", + "plus administrator", + "plus member", + "plus moderator", + "plus person", + "plus profile", + "plus user", + "privacy", + "private", + "profile icon", + "protect", + "protection", + "security", + "shield", + "symbol", + "user icon", + "verified", + "woman icon" + ], + "popularity": 6143 + }, + "ADD_PHOTO_ALTERNATE": { + "tags": [ + "+", + "add", + "addition", + "album", + "alternate", + "art", + "capture", + "choose", + "collection", + "creation", + "file", + "gallery", + "graphic", + "image", + "import", + "insert", + "landscape", + "media", + "mountain", + "mountains", + "new", + "photo", + "photography", + "picture", + "plus", + "rectangle", + "select", + "square", + "sun", + "symbol", + "upload", + "visual" + ], + "popularity": 25076 + }, + "ADD_REACTION": { + "tags": [ + "+", + "add", + "add emotion", + "add feeling", + "add reaction", + "append", + "button", + "chat", + "circle", + "comment", + "communications", + "emoji", + "emoticon", + "emotions", + "express", + "expressions", + "face", + "feedback", + "feelings", + "glad", + "happiness", + "happy", + "icon", + "icons", + "include", + "insert", + "interaction", + "like", + "mood", + "new", + "outline", + "person", + "pleased", + "plus", + "plus sign", + "positive", + "response", + "smile", + "smiley face", + "smiling", + "social", + "social media", + "survey", + "symbol" + ], + "popularity": 6376 + }, + "ADD_ROAD": { + "tags": [ + "+", + "add", + "add new", + "build", + "create", + "destination", + "direction", + "graphic", + "highway", + "icon", + "infrastructure", + "journey", + "line", + "location", + "map", + "maps", + "marker", + "navigate", + "new", + "path", + "plus", + "road", + "route", + "sign", + "stop", + "street", + "symbol", + "traffic", + "transportation", + "travel", + "ui", + "ux", + "way" + ], + "popularity": 5194 + }, + "ADD_SHOPPING_CART": { + "tags": [ + "acquisition", + "add", + "add to cart", + "basket", + "buy", + "card", + "cart", + "cash", + "checkout", + "coin", + "commerce", + "credit", + "currency", + "dollars", + "e-commerce", + "e-shop", + "item", + "market", + "money", + "online", + "online shopping", + "online store", + "order", + "pay", + "payment", + "plus", + "product", + "purchase", + "retail", + "retail experience", + "retail therapy", + "shop", + "shopping", + "shopping cart", + "store" + ], + "popularity": 59394 + }, + "ADD_TASK": { + "tags": [ + "+", + "accept", + "add", + "addition", + "agenda", + "approve", + "assignment", + "check", + "checkbox", + "checkmark", + "circle", + "complete", + "completed", + "create", + "done", + "goal", + "increase", + "insert", + "list", + "manage", + "mark", + "new", + "ok", + "plus", + "positive", + "project", + "reminder", + "schedule", + "select", + "task", + "tick", + "todo", + "work", + "yes" + ], + "popularity": 27918 + }, + "ADD_TO_DRIVE": { + "tags": [ + "account", + "add", + "app", + "application", + "archive", + "backup", + "cloud", + "cloud computing", + "connection", + "create", + "data", + "document", + "drive", + "external", + "file", + "files", + "folder", + "folders", + "gdrive", + "google", + "google drive", + "insert", + "network", + "online", + "platform", + "plus", + "recovery", + "repository", + "save", + "service", + "shared drive", + "shortcut", + "storage", + "sync", + "transfer", + "triangle", + "upload" + ], + "popularity": 6918 + }, + "ADD_TO_HOME_SCREEN": { + "tags": [ + "add", + "add to", + "add to homescreen", + "android", + "app", + "application", + "arrow", + "bookmark", + "cell", + "device", + "diagonal", + "export", + "hardware", + "home", + "home screen", + "homescreen", + "homescreen add", + "install", + "ios", + "mobile", + "os", + "phone", + "phone screen", + "pin", + "plus", + "right", + "save", + "screen", + "send", + "share", + "shortcut", + "tablet", + "up", + "upload", + "website" + ], + "popularity": 2331 + }, + "ADD_TO_PHOTOS": { + "tags": [ + "add", + "album", + "append", + "camera", + "capture", + "cloud", + "collection", + "create", + "files", + "folder", + "gallery", + "image", + "import", + "include", + "input", + "insert", + "landscape", + "library", + "manage", + "media", + "mountain", + "mountains", + "multimedia", + "new", + "organize", + "photo", + "photography", + "photos", + "picture", + "plus", + "save", + "storage", + "supplement", + "to", + "upload" + ], + "popularity": 4899 + }, + "ADD_TO_QUEUE": { + "tags": [ + "+", + "add", + "add to queue", + "android", + "append", + "arrangement", + "audio", + "chrome", + "desktop", + "device", + "display", + "entertainment", + "hardware", + "include", + "insert", + "ios", + "line", + "list", + "mac", + "management", + "media", + "monitor", + "multimedia", + "music", + "new", + "next", + "order", + "ordering", + "os", + "play next", + "playback", + "playlist", + "plus", + "queue", + "screen", + "sequence", + "stack", + "symbol", + "to", + "upcoming", + "video", + "video player", + "watch next", + "web", + "window" + ], + "popularity": 3932 + }, + "ADDCHART": { + "tags": [ + "+", + "add", + "addchart", + "analysis", + "analytics", + "bar", + "bar chart", + "bars", + "business", + "chart", + "create", + "dashboard", + "data", + "diagram", + "financial", + "graph", + "growth", + "increase", + "infographic", + "information", + "insert", + "line graph", + "measure", + "metric", + "metrics", + "new", + "performance", + "plus", + "presentation", + "report", + "representation", + "statistics", + "symbol", + "tracking", + "trend", + "visual" + ], + "popularity": 11019 + }, + "ADF_SCANNER": { + "tags": [ + "adf", + "adf scanner", + "automatic document feeder", + "business", + "copier", + "copy", + "device", + "digitization", + "document", + "feed", + "feeder", + "hardcopy", + "horizontal lines", + "imaging", + "input", + "machine", + "multiple pages", + "office", + "office equipment", + "output", + "paper", + "parallel lines", + "print", + "printer", + "processing", + "rectangle", + "scan", + "scanner", + "sheet", + "stack", + "technology", + "work" + ], + "popularity": 1354 + }, + "ADJUST": { + "tags": [ + "adjust", + "alter", + "auto click", + "bar", + "bars", + "calibration", + "center", + "change", + "circle", + "circles", + "configuration", + "control panel", + "controls", + "customize", + "dot", + "filter", + "fine tune", + "fix", + "focus", + "hamburger menu", + "horizontal lines", + "image", + "levels", + "lines", + "management", + "menu", + "modify", + "move", + "options", + "preferences", + "refine", + "regulation", + "settings", + "sliders", + "target", + "three lines", + "triple bar", + "tuning" + ], + "popularity": 16421 + }, + "ADMIN_PANEL_SETTINGS": { + "tags": [ + "access", + "account", + "adjust", + "admin", + "administrator", + "avatar", + "certified", + "cog", + "configuration", + "control", + "customize", + "dashboard", + "edit", + "face", + "gear", + "human", + "key", + "lock", + "management", + "options", + "panel", + "people", + "permissions", + "person", + "preferences", + "privacy", + "private", + "profile", + "protect", + "protection", + "security", + "settings", + "setup", + "shield", + "system", + "tool", + "tools", + "user", + "verified" + ], + "popularity": 66394 + }, + "ADS_CLICK": { + "tags": [ + "ads", + "ads click", + "advertisement", + "analytics", + "arrow", + "browser", + "button", + "call to action", + "campaign", + "click", + "clicks", + "conversion", + "cursor", + "destination", + "digital", + "engagement", + "finger", + "interaction", + "internet", + "link", + "marketing", + "measurement", + "network", + "online", + "performance", + "pointer", + "promotion", + "reach", + "select", + "tap", + "target", + "touch", + "tracking", + "traffic", + "web" + ], + "popularity": 25599 + }, + "AGRICULTURE": { + "tags": [ + "agriculture", + "automobile", + "botanical", + "car", + "cars", + "crop", + "cultivate", + "cultivation", + "farm", + "farming", + "farming tools", + "field", + "gardening", + "grain", + "ground", + "grow", + "growth", + "harvest", + "land", + "line", + "maps", + "nature", + "outline", + "plant", + "planting", + "rake", + "rural", + "seeding", + "seeds", + "simplified", + "tool", + "tractor", + "transport", + "travel", + "truck", + "vehicle", + "wheat", + "yield" + ], + "popularity": 10066 + }, + "AIR": { + "tags": [ + "abstract", + "air", + "atmospheric", + "blowing", + "breath", + "breeze", + "climate", + "cooling", + "current", + "element", + "environment", + "environmental", + "flow", + "fragrance", + "fresh", + "heating", + "hvac", + "line", + "lines", + "motion", + "movement", + "quality", + "scent", + "smell", + "stream", + "swirl", + "swoosh", + "ventilation", + "wave", + "waves", + "weather", + "wind" + ], + "popularity": 14719 + }, + "AIRLINE_SEAT_FLAT": { + "tags": [ + "airline", + "airplane", + "aviation", + "bed", + "body", + "business", + "business class", + "chair", + "class", + "comfort", + "first", + "first class", + "flat", + "flight", + "horizontal", + "human", + "journey", + "lay flat", + "lounge", + "luxury", + "lying down", + "passenger", + "people", + "person", + "plane", + "reclining", + "reclining chair", + "relax", + "rest", + "seat", + "sleep", + "transport", + "transportation", + "travel", + "trip" + ], + "popularity": 1534 + }, + "AIRLINE_SEAT_FLAT_ANGLED": { + "tags": [ + "abstract.", + "airline", + "airplane", + "angled", + "bed", + "body", + "booking", + "business", + "business class", + "chair", + "class", + "comfort", + "diagram", + "first", + "first class", + "flat", + "flying", + "graphic", + "human", + "icon", + "illustration", + "legroom", + "passenger", + "people", + "person", + "plane", + "recline", + "reservation", + "rest", + "seat", + "seating", + "sleep", + "symbol", + "transport", + "transportation", + "travel" + ], + "popularity": 1192 + }, + "AIRLINE_SEAT_INDIVIDUAL_SUITE": { + "tags": [ + "aircraft", + "airline", + "airplane", + "aisle", + "aviation", + "body", + "booking", + "business", + "business class", + "cabin", + "class", + "comfort", + "comfortable", + "first", + "first class", + "flight", + "flying", + "human", + "individual", + "individual seat", + "journey", + "luxury", + "middle", + "passenger", + "people", + "person", + "personal", + "plane", + "premium", + "private", + "reclining", + "reservation", + "rest", + "seat", + "sleep", + "sleeping", + "suite", + "transportation", + "travel", + "window" + ], + "popularity": 1689 + }, + "AIRLINE_SEAT_LEGROOM_EXTRA": { + "tags": [ + "airline", + "airplane", + "body", + "booking", + "chair", + "comfort", + "comfortable", + "extended", + "extra", + "feet", + "flying", + "human", + "journey", + "large", + "leg", + "legroom", + "long", + "passenger", + "people", + "person", + "plane", + "premium", + "reservation", + "row", + "seat", + "sitting", + "space", + "stretch", + "transportation", + "travel", + "upgrade", + "vehicle" + ], + "popularity": 1027 + }, + "AIRLINE_SEAT_LEGROOM_NORMAL": { + "tags": [ + "airline", + "airplane", + "area", + "arrangement", + "aviation", + "body", + "cabin", + "chair", + "comfort", + "feet", + "flight", + "human", + "journey", + "layout", + "leg", + "legroom", + "measurement", + "normal", + "passenger", + "people", + "person", + "plane", + "room", + "seat", + "seating", + "sitting", + "space", + "standard", + "transport", + "transportation", + "travel", + "vehicle" + ], + "popularity": 1068 + }, + "AIRLINE_SEAT_LEGROOM_REDUCED": { + "tags": [ + "aircraft", + "airline", + "airplane", + "body", + "cabin", + "comfort", + "cramped", + "diminished", + "economy", + "feet", + "flying", + "human", + "journey", + "leg", + "legroom", + "less", + "limited", + "low", + "minimal", + "passenger", + "people", + "person", + "plane", + "reduced", + "restricted", + "row", + "seat", + "seating", + "shrunk", + "sitting", + "small", + "space", + "tight", + "transport", + "transportation", + "travel", + "trip" + ], + "popularity": 962 + }, + "AIRLINE_SEAT_RECLINE_EXTRA": { + "tags": [ + "airline", + "airplane", + "aviation", + "body", + "booking", + "chair", + "comfort", + "comfortable", + "extra", + "feet", + "flight", + "flying", + "holiday", + "human", + "journey", + "leg", + "legroom", + "leisure", + "lounge", + "passenger", + "people", + "person", + "plane", + "premium", + "recline", + "relax", + "relaxation", + "reservation", + "seat", + "sitting", + "space", + "transport", + "transportation", + "travel", + "trip", + "upgrade", + "vacation" + ], + "popularity": 2758 + }, + "AIRLINE_SEAT_RECLINE_NORMAL": { + "tags": [ + "airline", + "airline diagram", + "airline layout", + "airplane", + "body", + "chair", + "comfort", + "comfortable", + "diagram", + "economy class", + "extra", + "feet", + "flight", + "human", + "journey", + "layout", + "leg", + "legroom", + "normal", + "normal position", + "passenger", + "passenger seat", + "people", + "person", + "recline", + "recline normal", + "relax", + "seat", + "seating", + "seating arrangement", + "sitting", + "space", + "standard seat", + "transport", + "travel", + "travel icon", + "upright position", + "upright seat", + "vehicle" + ], + "popularity": 4074 + }, + "AIRLINE_STOPS": { + "tags": [ + "airline", + "airplane", + "airport", + "arrow", + "aviation", + "circles", + "connection", + "destination", + "destination.", + "direction", + "dots", + "flight", + "itinerary", + "journey", + "journey stops", + "layover", + "line", + "location", + "maps", + "navigation", + "path", + "place", + "plane", + "points", + "points of interest", + "route", + "stops", + "transit", + "transportation", + "travel", + "travel plans", + "travel route", + "trip" + ], + "popularity": 2002 + }, + "AIRLINES": { + "tags": [ + "air", + "air travel", + "aircraft", + "airlines", + "airlines icon", + "airplane", + "airplane mode", + "airplanes", + "airport", + "aviation", + "booking", + "booking app", + "destination", + "flight", + "flight app", + "flights", + "fly", + "flying", + "journey", + "mode", + "on", + "plane", + "plane icon", + "planes", + "signal", + "sky", + "transport", + "transportation", + "travel", + "travel app", + "travel icon", + "trip", + "wings" + ], + "popularity": 1550 + }, + "AIRPLANE_TICKET": { + "tags": [ + "admit", + "air", + "air ticket", + "aircraft", + "airplane", + "airplane ticket", + "airplanes", + "airport", + "boarding", + "boarding pass", + "booking", + "document", + "dotted line", + "entry", + "flight", + "flight ticket", + "flights", + "fly", + "flying", + "identification", + "journey", + "maps", + "paper", + "pass", + "perforations", + "plane", + "plane ticket", + "planes", + "rectangle", + "reservation", + "scan", + "show", + "signal", + "stub", + "tear line", + "ticket", + "transport", + "transportation", + "travel", + "travel document", + "trip", + "vacation" + ], + "popularity": 8091 + }, + "AIRPLANEMODE_ACTIVE": { + "tags": [ + "active", + "air", + "air travel", + "aircraft", + "airplane", + "airplane icon", + "airplane mode", + "airplanes", + "airport", + "communication off", + "disable connectivity", + "disable wireless", + "enabled", + "flight", + "flight mode", + "flights", + "fly", + "flying", + "local airport", + "mode", + "network off", + "on", + "plane", + "planes", + "signal", + "signal off", + "transport", + "transportation", + "travel", + "travel mode", + "trip", + "turn off radio", + "vehicle" + ], + "popularity": 5381 + }, + "AIRPLANEMODE_INACTIVE": { + "tags": [ + "air", + "aircraft", + "airplane", + "airplane mode", + "airplanes", + "airport", + "aviation", + "communications", + "connectivity", + "crossed out", + "deactivated", + "diagonal line", + "disabled", + "enabled", + "flight", + "flight mode", + "flights", + "fly", + "flying", + "inactive", + "line", + "maps", + "mobile settings", + "mode", + "network off", + "not active", + "not enabled", + "off", + "offline", + "on", + "plane", + "planes", + "signal", + "signal off", + "slash", + "transportation", + "travel", + "triangle", + "trip", + "wireless off" + ], + "popularity": 1841 + }, + "AIRPLAY": { + "tags": [ + "airplay", + "arrow", + "audio", + "broadcast", + "cast screen", + "casting", + "connect", + "connection", + "content sharing", + "control", + "desktop", + "device", + "display", + "external display", + "media", + "media sharing", + "monitor", + "multimedia", + "output", + "playback", + "projection", + "screen", + "screen mirroring", + "screen share", + "send to tv", + "sharing", + "signal", + "streaming", + "triangle", + "tv", + "video", + "wireless", + "wireless display" + ], + "popularity": 3613 + }, + "AIRPORT_SHUTTLE": { + "tags": [ + "airport", + "arrival", + "automobile", + "baggage", + "bus", + "car", + "cars", + "commercial", + "commute", + "delivery", + "departure", + "direction", + "driving", + "drop off", + "four wheels", + "ground transport", + "journey", + "luggage", + "maps", + "mini", + "passenger", + "pick up", + "public", + "public transport", + "rectangle", + "road", + "round edges", + "shuttle", + "terminal", + "transit", + "transport", + "transportation", + "travel", + "trip", + "truck", + "van", + "vehicle", + "wheels" + ], + "popularity": 11917 + }, + "ALARM": { + "tags": [ + "access", + "adjust", + "alarm", + "alert", + "appointment", + "bell", + "calendar", + "circle", + "clock", + "control", + "countdown", + "date", + "deadline", + "future", + "hands", + "history", + "indicator", + "manage", + "mark", + "notification", + "point", + "reminder", + "ring", + "schedule", + "setting", + "sound", + "time", + "timer", + "wake up", + "watch" + ], + "popularity": 33092 + }, + "ALARM_ADD": { + "tags": [ + "+", + "add", + "add alarm", + "alarm", + "alert", + "app", + "appointment", + "audio", + "bell", + "clock", + "countdown", + "create", + "date", + "digital", + "event", + "mobile", + "morning", + "new", + "new alarm", + "notification", + "phone", + "plus", + "reminder", + "ring", + "schedule", + "set", + "setting", + "sound", + "symbol", + "task", + "time", + "timer", + "wake up", + "watch" + ], + "popularity": 5997 + }, + "ALARM_OFF": { + "tags": [ + "alarm", + "alarm off", + "alert", + "bell", + "bell disabled", + "bell muted", + "bell off", + "check", + "checkmark", + "clock", + "diagonal line", + "disable alarm", + "disable notification", + "disable sound", + "disabled", + "duration", + "enabled", + "mute alarm", + "mute notification", + "mute sound", + "muted", + "no alarm", + "no bell", + "no notification", + "no sound", + "notification", + "notification off", + "off", + "on", + "quiet", + "silence alarm", + "silent", + "slash", + "sound off", + "stop alarm", + "time", + "timer", + "turn off alarm", + "watch" + ], + "popularity": 4027 + }, + "ALARM_ON": { + "tags": [ + "activated", + "active", + "alarm", + "alert", + "audible", + "awake", + "bell", + "buzzing", + "check", + "checkmark", + "chime", + "clock", + "duration", + "enabled", + "event", + "jingle", + "notification", + "notification bell", + "on", + "reminder", + "ringer", + "ringing", + "ringing bell", + "schedule", + "signal", + "sound", + "sound on", + "time", + "timer", + "wake up", + "warning", + "watch" + ], + "popularity": 12993 + }, + "ALBUM": { + "tags": [ + "album", + "archive", + "artist", + "artwork", + "audio", + "bundle", + "bvb", + "catalog", + "cd", + "collection", + "compilation", + "computer", + "cover", + "data", + "disk", + "documents", + "file", + "folder", + "gallery", + "group", + "index", + "layer", + "library", + "lines", + "media", + "music", + "organization", + "photos", + "pictures", + "playlist", + "record", + "series", + "set", + "sound", + "square", + "stack", + "storage", + "track", + "volume" + ], + "popularity": 8187 + }, + "ALIGN_HORIZONTAL_CENTER": { + "tags": [ + "align", + "alignment", + "arrange", + "bars", + "center", + "content", + "data", + "design", + "distribution", + "document", + "editor", + "format", + "formatting", + "grid", + "horizontal", + "layout", + "lines", + "organize", + "paragraph", + "placement", + "positioning", + "rectangle", + "rule", + "rules", + "shape", + "structure", + "style", + "text", + "word processor" + ], + "popularity": 2284 + }, + "ALIGN_HORIZONTAL_LEFT": { + "tags": [ + "align", + "align horizontal", + "align left", + "alignment", + "arrange", + "arrange elements", + "bars", + "direction", + "document", + "document alignment", + "document layout", + "editor", + "format", + "format text", + "horizontal", + "horizontal align", + "justified", + "layout", + "left", + "left align", + "lines", + "order", + "organize", + "paragraph", + "position", + "position text", + "rule", + "rules", + "spacing", + "style", + "text", + "text align" + ], + "popularity": 3425 + }, + "ALIGN_HORIZONTAL_RIGHT": { + "tags": [ + "adjustment", + "align", + "alignment", + "arrange", + "bars", + "content", + "document", + "document editing", + "editor", + "format", + "formatting options", + "horizontal", + "indent", + "layout", + "lines", + "order", + "paragraph", + "parallel", + "position", + "rectangle", + "right", + "rule", + "rules", + "spacing", + "style", + "text", + "text tools", + "typography", + "word processing", + "writing" + ], + "popularity": 2144 + }, + "ALIGN_VERTICAL_BOTTOM": { + "tags": [ + "align", + "alignment", + "arrange", + "bar", + "bottom", + "creative", + "distribute", + "document", + "document editor", + "editor", + "file", + "format", + "formatting", + "graphic design", + "layout", + "line", + "lines", + "page", + "paragraph", + "position", + "presentation", + "rectangle", + "rule", + "rules", + "style", + "text", + "three bars", + "three lines", + "vertical", + "word processor" + ], + "popularity": 2383 + }, + "ALIGN_VERTICAL_CENTER": { + "tags": [ + "align", + "alignment", + "arrangement", + "blocks", + "center", + "centered", + "columns", + "content", + "distribute", + "document", + "editor", + "evenly", + "format", + "formatting", + "grid", + "layout", + "lines", + "middle", + "paragraph", + "position", + "rows", + "rule", + "rules", + "spacing", + "style", + "text", + "typography", + "vertical", + "writing" + ], + "popularity": 1748 + }, + "ALIGN_VERTICAL_TOP": { + "tags": [ + "adjust", + "align", + "alignment", + "arrange", + "bar", + "bars", + "control", + "design", + "distribute", + "document", + "edit", + "editor", + "format", + "formatting", + "graphic", + "grid", + "layout", + "lines", + "objects", + "order", + "organize", + "paragraph", + "parallel", + "position", + "presentation", + "rectangle", + "rule", + "rules", + "sort", + "style", + "text", + "three lines", + "top", + "ui element", + "vertical" + ], + "popularity": 1792 + }, + "ALL_INBOX": { + "tags": [ + "all", + "all mail", + "archive", + "box", + "bundle", + "collection", + "communication", + "complete", + "comprehensive", + "container", + "correspondence", + "delivered", + "delivery", + "digital mail", + "email", + "entirety", + "envelope", + "full", + "inbox", + "incoming", + "letter", + "mail", + "mail folder", + "mailbox", + "message", + "messaging", + "postal", + "receive", + "received", + "send", + "storage", + "totality" + ], + "popularity": 9071 + }, + "ALL_INCLUSIVE": { + "tags": [ + "abstract", + "all", + "boundless", + "complete", + "comprehensive", + "concept", + "connected", + "continuous", + "cycle", + "encompassing", + "endless", + "eternal", + "everything", + "figure eight", + "forever", + "full", + "global", + "inclusive", + "infinite", + "infinity", + "lemniscate", + "loop", + "math", + "mobius", + "neverending", + "strip", + "sustainability", + "sustainable", + "symbol", + "totality", + "unbroken", + "universal", + "unlimited", + "whole" + ], + "popularity": 12097 + }, + "ALL_OUT": { + "tags": [ + "abstract", + "all", + "arrows", + "aspect ratio", + "bounding box", + "box", + "circle", + "corners", + "enlarge", + "expand", + "expanding", + "extend", + "four directions", + "fullscreen", + "geometric", + "grow", + "indicators", + "lines", + "maximize", + "out", + "outwards", + "pointer", + "rectangle", + "scale", + "shape", + "spreading", + "stretching", + "visual", + "zoom" + ], + "popularity": 2898 + }, + "ALT_ROUTE": { + "tags": [ + "alt", + "alternate", + "alternate routes", + "alternative", + "arrows", + "bifurcate", + "branching", + "change", + "choice", + "choices", + "dash", + "dashed", + "detour", + "different", + "direction", + "directions", + "diversion", + "itinerary", + "journey", + "map", + "mapping", + "maps", + "multiple routes", + "navigation", + "options", + "other", + "path", + "road", + "route", + "route options", + "routes", + "selection", + "split", + "street", + "switch", + "symbol", + "transit", + "transportation", + "travel", + "variety", + "way" + ], + "popularity": 10153 + }, + "ALTERNATE_EMAIL": { + "tags": [ + "@", + "address", + "address book", + "alternate", + "alternate contact", + "alternate email", + "communicate", + "communication", + "contact", + "contact form", + "correspondence", + "email", + "email address", + "email client", + "envelope", + "inbox", + "inbox icon", + "letter", + "mail", + "message", + "messaging", + "outline", + "outline email", + "outline envelope", + "outline mail", + "receive", + "receive message", + "send", + "send message", + "stroke", + "tag" + ], + "popularity": 40002 + }, + "ANALYTICS": { + "tags": [ + "analysis", + "analytics", + "assessment", + "bar", + "bar chart", + "bars", + "business", + "chart", + "dashboard", + "data", + "diagram", + "economic", + "finance", + "graph", + "growth", + "infographic", + "information", + "insights", + "intelligence", + "measure", + "measurement", + "metrics", + "performance", + "progress", + "rectangular bars", + "report", + "results", + "sales", + "statistics", + "survey", + "tracking", + "trends", + "vertical bars", + "visualization" + ], + "popularity": 69855 + }, + "ANCHOR": { + "tags": [ + "anchor", + "attachment", + "base", + "boat", + "chain", + "connection", + "fishing", + "fixed", + "foundation", + "google", + "harbor", + "heavy", + "hold", + "hook", + "link", + "logo", + "maritime", + "metal", + "mooring", + "nautical", + "navigation", + "ocean", + "port", + "reference", + "reliable", + "sailing", + "sea", + "security", + "ship", + "solid", + "stability" + ], + "popularity": 8960 + }, + "ANDROID": { + "tags": [ + "ai", + "android", + "app development", + "artificial intelligence", + "automation", + "bugdroid", + "character", + "code", + "computing", + "developer", + "device", + "digital", + "electronics", + "futuristic", + "google", + "google play", + "logo", + "mascot", + "mobile", + "mobile operating system", + "open source", + "operating system", + "os", + "platform", + "programming", + "robot", + "smartphone", + "software", + "system", + "tablet", + "technology", + "toy" + ], + "popularity": 28559 + }, + "ANIMATION": { + "tags": [ + "active", + "activity", + "activity indicator", + "animation", + "busy", + "circle", + "circles", + "concentric", + "continuous", + "dynamic", + "film", + "flow", + "fluid", + "indicator", + "loading", + "loading spinner", + "looping", + "motion", + "movement", + "processing", + "progress", + "progress indicator", + "refreshing", + "rings", + "sequence", + "spinning", + "status", + "video", + "visualizer", + "wait", + "waiting", + "working" + ], + "popularity": 4685 + }, + "ANNOUNCEMENT": { + "tags": [ + "!", + "alert", + "announcement", + "attention", + "broadcast", + "bubble", + "caution", + "chat", + "comment", + "communicate", + "communication", + "danger", + "delivery failed", + "element", + "error", + "exclamation", + "fail", + "failed", + "feedback", + "icon", + "important", + "mark", + "megaphone", + "message", + "news", + "notification", + "public address", + "send failed", + "sms", + "sound", + "speaker", + "speech", + "symbol", + "text message", + "volume", + "warning" + ], + "popularity": 24258 + }, + "AOD": { + "tags": [ + "abstract", + "alert", + "always", + "always on display", + "ambient display", + "ambient mode", + "android", + "aod", + "clock", + "communication", + "device", + "digital", + "display", + "electronics", + "hardware", + "homescreen", + "information", + "ios", + "line", + "lock screen", + "message", + "minimalist", + "mobile", + "notification", + "on", + "os", + "phone", + "rectangular", + "screen", + "simple", + "smartphone", + "tablet", + "technology", + "text", + "time" + ], + "popularity": 2393 + }, + "APARTMENT": { + "tags": [ + "accommodation", + "address", + "apartment", + "architecture", + "area", + "block", + "building", + "business", + "city", + "commercial", + "company", + "complex", + "downtown", + "estate", + "flat", + "home", + "house", + "housing", + "lines", + "location", + "navigation", + "office", + "outline", + "places", + "property", + "real", + "real estate", + "rectangle", + "region", + "residence", + "residential", + "shelter", + "silhouette", + "skyscraper", + "square", + "structure", + "tower", + "units", + "urban", + "windows", + "workplace" + ], + "popularity": 47255 + }, + "API": { + "tags": [ + "access", + "api", + "application", + "backend", + "bridge", + "cloud", + "code", + "coding", + "communication", + "computer", + "connection", + "data", + "developer", + "development", + "enterprise", + "frontend", + "integration", + "internet", + "link", + "network", + "programming", + "programming interface", + "service", + "software", + "system", + "tech", + "technology", + "transfer", + "web service" + ], + "popularity": 19293 + }, + "APP_BLOCKING": { + "tags": [ + "access denied", + "android", + "app", + "app blocking", + "application", + "ban", + "barrier", + "block", + "blocking", + "cancel", + "cell", + "circle", + "control", + "cross", + "deny", + "device", + "disallow", + "electronic", + "forbidden", + "gadget", + "halt", + "hardware", + "ios", + "limits", + "line", + "mobile", + "mobile block", + "no entry", + "off limits", + "os", + "pause", + "phone", + "prevention", + "prohibited", + "rectangle", + "restrict", + "security", + "shield", + "smartphone", + "stop", + "stopped", + "tablet" + ], + "popularity": 3738 + }, + "APP_REGISTRATION": { + "tags": [ + "app", + "app registration", + "application", + "apps", + "create account", + "data entry", + "details", + "documentation", + "edit", + "enroll", + "entry", + "form", + "information", + "join", + "new account", + "onboarding", + "pencil", + "profile creation", + "record", + "register", + "registration", + "registration form", + "sign up", + "sign up form", + "signup", + "signup form", + "subscription", + "user registration", + "web form" + ], + "popularity": 20228 + }, + "APP_SETTINGS_ALT": { + "tags": [ + "adjust", + "administration", + "android", + "app", + "applications", + "cell", + "cog", + "configuration", + "control", + "customization", + "device", + "gear", + "hardware", + "icon", + "ios", + "manage", + "mobile", + "options", + "os", + "parameters", + "phone", + "preferences", + "setting", + "settings", + "setup", + "smartphone", + "symbol", + "system", + "tablet", + "technology" + ], + "popularity": 6020 + }, + "APP_SHORTCUT": { + "tags": [ + "access", + "android", + "app", + "application", + "broadcast", + "cast", + "casting", + "cell", + "connect", + "connection", + "data", + "device", + "direct link", + "display", + "hardware", + "instant access", + "ios", + "link", + "mirror", + "mirroring", + "mobile", + "monitor", + "network", + "os", + "output", + "phone", + "projection", + "quick launch", + "screen", + "screen share", + "screencast", + "share", + "shortcut", + "stream", + "streaming", + "tablet", + "transmit", + "tv", + "wireless" + ], + "popularity": 3758 + }, + "APPROVAL": { + "tags": [ + "accept", + "accepted", + "acknowledge", + "affirmative", + "agree", + "agreement", + "apply", + "approval", + "approvals", + "approve", + "certificate", + "certification", + "check", + "checkmark", + "complete", + "confirm", + "correct", + "disapproval", + "done", + "drive", + "file", + "finished", + "impression", + "ink", + "mark", + "okay", + "okey dokey", + "permission", + "permitted", + "positive", + "postage", + "right", + "stamp", + "success", + "tick", + "true", + "valid", + "validated", + "verified", + "yes" + ], + "popularity": 10200 + }, + "APPS": { + "tags": [ + "3x3 grid", + "access", + "all", + "all apps", + "application", + "applications", + "apps", + "circles", + "collection", + "components", + "dashboard", + "desktop", + "display", + "dots", + "features", + "functions", + "general", + "grid", + "home", + "icons", + "interface", + "launcher", + "launchpad", + "menu", + "mobile", + "navigation", + "nine squares", + "options", + "programs", + "quick access", + "services", + "settings", + "shortcut", + "software", + "squares", + "system", + "tiles", + "ui", + "ux" + ], + "popularity": 75935 + }, + "APPS_OUTAGE": { + "tags": [ + "alert", + "all", + "application", + "applications", + "apps", + "breakdown", + "circles", + "collection", + "communication", + "components", + "connection", + "connectivity", + "digital", + "disconnected", + "dots", + "error", + "failure", + "grid", + "interface", + "internet", + "issue", + "malfunction", + "network", + "notification", + "offline", + "outage", + "problem", + "program", + "server", + "service", + "software", + "squares", + "system", + "technology", + "ui", + "unavailable", + "ux", + "warning" + ], + "popularity": 3372 + }, + "ARCHITECTURE": { + "tags": [ + "architecture", + "art", + "blueprint", + "building", + "city", + "city building", + "cityscape", + "compass", + "construction", + "design", + "draw", + "drawing", + "dwelling", + "engineering", + "exterior", + "facade", + "geometric", + "home", + "house", + "housing", + "monument", + "plan", + "property", + "real estate", + "residential", + "residential building", + "shelter", + "skyscraper", + "structure", + "tool", + "town", + "urban", + "urban building", + "village" + ], + "popularity": 11659 + }, + "ARCHIVE": { + "tags": [ + "archive", + "archive box", + "backup", + "bin", + "box", + "categorize", + "collection", + "container", + "data", + "document", + "file", + "filing", + "folder", + "history", + "inbox", + "library", + "mail", + "manage", + "memory", + "organization", + "organize", + "past", + "record", + "rectangular", + "repository", + "retrieve", + "save", + "sort", + "storage", + "store", + "symbol", + "system" + ], + "popularity": 25227 + }, + "AREA_CHART": { + "tags": [ + "analysis", + "analytics", + "area", + "area chart", + "area filled", + "area graph", + "business", + "chart", + "chart filled", + "dashboard", + "data", + "diagram", + "filled area", + "financial", + "graph", + "growth", + "infographic", + "information", + "line graph", + "measure", + "measurement", + "metric", + "metrics", + "performance", + "plot", + "presentation", + "progress", + "progress chart", + "report", + "shaded area", + "statistics", + "tracking", + "trend", + "visual data" + ], + "popularity": 6797 + }, + "ARROW_BACK": { + "tags": [ + "app", + "application", + "arrow", + "back", + "back button", + "backward", + "chevron", + "components", + "direction", + "directional", + "disable_ios", + "escape", + "exit", + "go back", + "history", + "indicator", + "interface", + "last", + "lead back", + "left", + "move", + "navigation", + "past", + "pointer", + "previous", + "prior", + "reply", + "retreat", + "return", + "reverse", + "revert", + "screen", + "site", + "step back", + "turn back", + "ui", + "undo", + "ux", + "way back", + "web", + "website" + ], + "popularity": 250130 + }, + "ARROW_BACK_IOS": { + "tags": [ + "app", + "application", + "arrow", + "back", + "back arrow", + "backward", + "breadcrumb", + "caret", + "chevron", + "components", + "control", + "direction", + "directional", + "disable_ios", + "earlier", + "go back", + "history", + "interface", + "ios", + "left", + "mobile", + "navigate", + "navigation", + "page", + "point left", + "pointer", + "precede", + "previous", + "return", + "reverse", + "rewind", + "screen", + "site", + "step back", + "ui", + "undo", + "ux", + "web", + "website" + ], + "popularity": 175960 + }, + "ARROW_BACK_IOS_NEW": { + "tags": [ + "action", + "angle", + "app", + "application", + "arrow", + "back", + "back button", + "backward", + "chevron", + "components", + "control", + "direction", + "disable_ios", + "exit", + "go back", + "history", + "interface", + "ios", + "left", + "less than", + "mobile", + "move", + "navigate", + "navigation", + "point left", + "pointer", + "preceding", + "previous", + "prior", + "return", + "reverse", + "rewind", + "screen", + "site", + "step back", + "ui", + "undo", + "ux", + "web", + "website" + ], + "popularity": 54463 + }, + "ARROW_CIRCLE_DOWN": { + "tags": [ + "arrow", + "button", + "circle", + "collapse", + "contained", + "control", + "cursor", + "direction", + "down", + "download", + "enclosed", + "expand", + "inside", + "mover", + "navigation", + "point", + "pointer", + "round", + "scroll", + "shape", + "within" + ], + "popularity": 16689 + }, + "ARROW_CIRCLE_LEFT": { + "tags": [ + "arrow", + "back", + "button", + "circle", + "circle arrow", + "circular", + "circular arrow", + "contained", + "control", + "direction", + "enclosed", + "enclosed arrow", + "go back", + "history", + "inside circle", + "left", + "navigate", + "navigation", + "pointer", + "pointing", + "previous", + "replay", + "return", + "reverse", + "rounded", + "rounded arrow", + "undo", + "within circle" + ], + "popularity": 14861 + }, + "ARROW_CIRCLE_RIGHT": { + "tags": [ + "app", + "arrow", + "arrow in circle", + "button", + "circle", + "circular arrow", + "continue", + "control", + "direction", + "directional arrow", + "forward", + "geometry", + "go", + "graphic", + "icon", + "illustration", + "interface element", + "link", + "move", + "navigation", + "next", + "pointer", + "proceed", + "right", + "right arrow", + "shape", + "symbol", + "ui", + "user interface", + "ux", + "web" + ], + "popularity": 24622 + }, + "ARROW_CIRCLE_UP": { + "tags": [ + "action", + "arrow", + "button", + "circle", + "circular arrow", + "control", + "data transfer", + "direction", + "direction up", + "file upload", + "forward", + "go to top", + "icon", + "indicator", + "move forward", + "move up", + "navigate up", + "navigation", + "order", + "positive direction", + "progress up", + "return to top", + "scroll up", + "send", + "share", + "sort", + "symbol", + "top", + "ui element", + "up", + "up arrow", + "upload" + ], + "popularity": 19588 + }, + "ARROW_DOWNWARD": { + "tags": [ + "app", + "application", + "arrow", + "collapse", + "components", + "continue", + "descending", + "direction", + "down", + "download", + "downward", + "dropdown", + "expand", + "export", + "flow", + "forward", + "indicate", + "install", + "interface", + "list", + "menu", + "minimize", + "move", + "navigation", + "next", + "next step", + "pointer", + "reveal", + "save", + "screen", + "scroll", + "show more", + "site", + "sort", + "symbol", + "transfer", + "ui", + "ux", + "web", + "website" + ], + "popularity": 51415 + }, + "ARROW_DROP_DOWN": { + "tags": [ + "app", + "application", + "arrow", + "carat", + "caret", + "chevron", + "collapse", + "components", + "control", + "direction", + "down", + "drop", + "dropdown", + "expand", + "expand/collapse", + "expander", + "filter", + "indicator", + "interface", + "list", + "menu", + "more", + "navigation", + "options", + "pointer", + "pointy", + "screen", + "select", + "selector", + "simple", + "site", + "small", + "sort", + "triangle", + "triangle down", + "ui", + "ux", + "web", + "website" + ], + "popularity": 164921 + }, + "ARROW_DROP_DOWN_CIRCLE": { + "tags": [ + "app", + "application", + "arrow", + "button", + "choose", + "circle", + "circled arrow", + "circled down arrow", + "collapse", + "components", + "control", + "direction", + "disclosure", + "down", + "down arrow", + "drop", + "dropdown", + "expand", + "expand down", + "expander", + "interface", + "list", + "menu", + "navigation", + "options", + "pointer", + "screen", + "select", + "selection", + "site", + "ui", + "ui control", + "ux", + "web", + "website" + ], + "popularity": 14768 + }, + "ARROW_DROP_UP": { + "tags": [ + "app", + "application", + "arrow", + "caret", + "caret up", + "collapse", + "collapse button", + "components", + "control", + "direction", + "directional indicator", + "drop", + "drop up", + "dropdown", + "expand", + "expander", + "fold", + "fold up", + "hide", + "indicator", + "interface", + "maximize", + "minimize", + "navigation", + "point up", + "reveal", + "screen", + "show", + "shrink", + "site", + "sort button", + "sort up", + "toggle", + "triangle", + "triangle up", + "ui", + "ui control", + "up", + "up arrow", + "ux", + "web", + "website" + ], + "popularity": 36052 + }, + "ARROW_FORWARD": { + "tags": [ + "advance", + "app", + "application", + "arrow", + "arrows", + "button", + "components", + "continue", + "control", + "direction", + "entry", + "expand", + "forward", + "go", + "graphic", + "indicator", + "interface", + "link", + "media", + "more", + "move", + "navigate", + "navigation", + "next", + "open", + "play", + "pointer", + "proceed", + "progress", + "progression", + "right", + "rightward", + "screen", + "simple", + "site", + "submit", + "ui", + "ux", + "web", + "website" + ], + "popularity": 131296 + }, + "ARROW_FORWARD_IOS": { + "tags": [ + "advance", + "angle", + "app", + "application", + "arrow", + "caret", + "chevron", + "components", + "detail", + "direction", + "expand", + "forward", + "go", + "greater than", + "indicator", + "interface", + "ios", + "link", + "list", + "menu", + "mobile", + "more", + "move", + "navigate", + "navigation", + "next", + "page", + "pointer", + "proceed", + "right", + "right-facing", + "screen", + "scroll", + "site", + "step", + "triangle", + "ui", + "ux", + "web", + "website" + ], + "popularity": 177356 + }, + "ARROW_LEFT": { + "tags": [ + "angle", + "app", + "application", + "arrow", + "back", + "backward", + "basic", + "components", + "curve", + "direction", + "directionality", + "forward", + "go back", + "indicator", + "interface", + "left", + "line", + "minimal", + "move", + "navigation", + "next", + "outline", + "point", + "pointer", + "previous", + "return", + "reverse", + "right", + "screen", + "shape", + "simple", + "site", + "triangle", + "ui", + "undo", + "ux", + "way", + "web", + "website" + ], + "popularity": 21039 + }, + "ARROW_OUTWARD": { + "tags": [ + "access", + "app", + "application", + "arrow", + "arrows", + "components", + "connection", + "diagonal", + "direct", + "direction", + "exit", + "exit button", + "expand", + "external", + "follow link", + "forward", + "go to", + "interface", + "launch", + "launch link", + "leave", + "link", + "movement", + "navigate", + "navigation", + "new tab", + "new window", + "open", + "open link", + "outbound", + "outward", + "pointer", + "redirect", + "right", + "screen", + "share", + "show more", + "site", + "ui", + "ux", + "view more", + "web", + "website" + ], + "popularity": 4416 + }, + "ARROW_RIGHT": { + "tags": [ + "advance", + "angle", + "app", + "application", + "arrow", + "button", + "caret", + "chevron", + "components", + "continuation", + "cue", + "direction", + "enter", + "exit", + "forward", + "go", + "greater than", + "indicator", + "interface", + "line", + "link", + "move", + "navigation", + "next", + "path", + "point", + "pointer", + "proceed", + "progress", + "return", + "right", + "screen", + "shortcut", + "site", + "triangle", + "ui", + "ux", + "way", + "web", + "website" + ], + "popularity": 48430 + }, + "ARROW_RIGHT_ALT": { + "tags": [ + "access", + "alt", + "arrow", + "arrow symbol", + "arrows", + "button", + "carat", + "caret", + "chevron", + "continue", + "details", + "direction", + "east", + "enter", + "expand", + "follow", + "forward", + "geometry", + "go", + "hyperlink", + "indicator", + "learn more", + "line", + "link", + "move", + "navigation", + "next", + "pointer", + "pointing", + "proceed", + "read more", + "right", + "straight", + "symbol" + ], + "popularity": 75688 + }, + "ARROW_UPWARD": { + "tags": [ + "above", + "app", + "application", + "arrow", + "ascend", + "components", + "direction", + "elevate", + "expand", + "export", + "go up", + "grow", + "increase", + "indicator", + "interface", + "move", + "movement", + "navigate", + "navigation", + "pointer", + "reorder", + "return", + "screen", + "scroll", + "scroll up", + "send", + "share", + "site", + "sort", + "sort ascending", + "superior", + "to top", + "top", + "ui", + "up", + "upload", + "upward", + "ux", + "web", + "website" + ], + "popularity": 67077 + }, + "ART_TRACK": { + "tags": [ + "album", + "album art", + "art", + "artist", + "audio", + "collection", + "cover", + "details", + "display", + "gallery", + "image", + "information", + "item", + "library", + "lines", + "list", + "media", + "metadata", + "music", + "photo", + "photography", + "picture", + "playback", + "rectangle", + "screen", + "song", + "sound", + "square", + "track", + "tracks", + "view", + "visualizer" + ], + "popularity": 2459 + }, + "ARTICLE": { + "tags": [ + "archive", + "article", + "cloud", + "content", + "contract", + "create", + "data", + "doc", + "document", + "drive", + "editor", + "file", + "folder", + "form", + "information", + "journal", + "library", + "memo", + "new", + "note", + "outline", + "page", + "paper", + "record", + "report", + "save", + "sheet", + "storage", + "text", + "view", + "writing" + ], + "popularity": 108368 + }, + "ASPECT_RATIO": { + "tags": [ + "adjust", + "aspect", + "aspect ratio", + "crop", + "custom", + "dash", + "dashed", + "dimensions", + "display", + "edit", + "enlarge", + "expand", + "fit", + "format", + "fullscreen", + "height", + "image", + "layout", + "media", + "modify", + "orientation", + "original", + "proportion", + "ratio", + "rectangle", + "resize", + "scale", + "screen", + "settings", + "size", + "square", + "transform", + "video", + "widescreen", + "width" + ], + "popularity": 13759 + }, + "ASSESSMENT": { + "tags": [ + "add", + "analysis", + "analytics", + "assessment", + "bar", + "bar chart", + "bars", + "business", + "chart", + "columns", + "create", + "data", + "diagram", + "finance", + "graph", + "growth", + "infographic", + "insert", + "manage", + "measure", + "metrics", + "options", + "performance", + "poll", + "progress", + "report", + "representation", + "results", + "statistics", + "survey", + "tracking", + "visualize" + ], + "popularity": 43684 + }, + "ASSIGNMENT": { + "tags": [ + "agenda", + "assignment", + "checklist", + "class", + "clipboard", + "course", + "deliverable", + "doc", + "document", + "duty", + "education", + "file", + "form", + "homework", + "learning", + "list", + "manage", + "memo", + "note", + "organize", + "page", + "paper", + "plan", + "project", + "report", + "school", + "sheet", + "submission", + "task", + "text", + "to do", + "work", + "writing" + ], + "popularity": 86901 + }, + "ASSIGNMENT_IND": { + "tags": [ + "account", + "apply", + "assignment", + "badge", + "card", + "clipboard", + "data", + "details", + "doc", + "document", + "enroll", + "face", + "file", + "form", + "graphic", + "icon", + "id", + "identification", + "ind", + "individual", + "information", + "membership", + "paper", + "people", + "person", + "profile", + "record", + "register", + "shape", + "sheet", + "symbol", + "ui element", + "user" + ], + "popularity": 39996 + }, + "ASSIGNMENT_LATE": { + "tags": [ + "!", + "alert", + "assignment", + "assignment late", + "attention", + "calendar", + "caution", + "clipboard", + "clock", + "danger", + "deadline", + "delay", + "doc", + "document", + "due date", + "education", + "error", + "exclamation", + "homework", + "important", + "incomplete", + "late", + "mark", + "notification", + "overdue", + "paper", + "pending", + "reminder", + "schedule", + "school", + "symbol", + "task", + "test", + "time", + "unfinished", + "urgent", + "warning" + ], + "popularity": 9697 + }, + "ASSIGNMENT_RETURN": { + "tags": [ + "approval", + "arrow", + "assignment", + "back", + "checklist", + "checkmark", + "clipboard", + "completed", + "completion", + "data", + "deliver", + "doc", + "document", + "document with check", + "done", + "edit", + "educational", + "file", + "file with tick", + "hand in", + "left", + "list", + "office", + "paper", + "re-submit", + "report", + "resend", + "retun", + "return", + "revise", + "school", + "send back", + "submit", + "success", + "task", + "tick", + "work" + ], + "popularity": 9899 + }, + "ASSIGNMENT_RETURNED": { + "tags": [ + "arrow", + "assignment", + "assignment returned", + "business", + "checking", + "clipboard", + "complete", + "contract", + "doc", + "document", + "down", + "editing", + "education", + "evaluating", + "file", + "form", + "grading", + "marking", + "memo", + "note", + "office", + "page", + "paper", + "pencil", + "report", + "returned", + "reviewing", + "school", + "sheet", + "submission", + "text", + "work", + "writing" + ], + "popularity": 6543 + }, + "ASSIGNMENT_TURNED_IN": { + "tags": [ + "accepted", + "approve", + "approved", + "assignment", + "box", + "check", + "checklist", + "checkmark", + "clipboard", + "complete", + "completed", + "doc", + "document", + "documentation", + "done", + "file", + "finished", + "in", + "line", + "lines", + "mark", + "ok", + "paper", + "progress", + "project", + "rectangle", + "report", + "select", + "square", + "submission", + "task", + "tick", + "to do list", + "turn", + "turned in", + "validate", + "validated", + "verified", + "work", + "yes" + ], + "popularity": 35192 + }, + "ASSIST_WALKER": { + "tags": [ + "accessibility", + "accessible", + "aid", + "assist", + "assistance", + "assisted living", + "assistive device", + "body", + "care", + "disability", + "elderly", + "figure", + "handicap", + "healthcare", + "help", + "human", + "injured", + "injury", + "medical", + "mobility", + "movement", + "nursing home", + "outline", + "person", + "physical therapy", + "rehabilitation", + "retirement", + "senior", + "silhouette", + "stick figure", + "support", + "therapy", + "walk", + "walker", + "walking aid" + ], + "popularity": 1052 + }, + "ASSISTANT": { + "tags": [ + "ai", + "answer", + "artificial", + "artificial intelligence", + "assistant", + "assistant bubble", + "automatic", + "automation", + "bubble", + "chat", + "chatbot", + "circle", + "comment", + "communicate", + "communication", + "conversation", + "custom", + "customer service", + "dialog", + "feedback", + "genai", + "guidance", + "help", + "help bubble", + "information", + "intelligence", + "magic", + "message", + "microphone", + "mouth", + "question", + "recommendation", + "service", + "smart", + "spark", + "sparkle", + "speaking", + "speech", + "speech bubble", + "star", + "suggestion", + "support", + "talk", + "talking", + "twinkle", + "virtual assistant", + "voice" + ], + "popularity": 8480 + }, + "ASSISTANT_DIRECTION": { + "tags": [ + "advising", + "angled arrow", + "arrow", + "assistant", + "destination", + "direction", + "gps", + "guide", + "guide me", + "journey", + "leading", + "left turn", + "location", + "map", + "maps", + "navigate", + "navigation", + "navigation assistant", + "path", + "pin", + "place", + "pointer", + "right", + "road", + "route", + "sign", + "signage", + "stop", + "street", + "street sign", + "suggesting direction", + "travel", + "turn", + "turn by turn", + "wayfinding" + ], + "popularity": 5786 + }, + "ASSISTANT_PHOTO": { + "tags": [ + "achievement", + "assistant", + "banner", + "bookmark", + "border", + "country", + "empty", + "flag", + "goal", + "highlight", + "indicator", + "label", + "location", + "mark", + "marker", + "milestone", + "national", + "notice", + "outline", + "pennant", + "photo", + "pin", + "recommendation", + "save", + "signal", + "smart", + "standard", + "star", + "suggestion", + "territory", + "unfilled" + ], + "popularity": 3324 + }, + "ASSURED_WORKLOAD": { + "tags": [ + "account", + "activity", + "approved", + "assignment", + "assurance", + "assured", + "authenticated", + "authorized", + "balance", + "bank", + "bill", + "building", + "card", + "cash", + "certainty", + "check", + "checked", + "coin", + "commerce", + "compliance", + "confidential", + "confirmed", + "credit", + "currency", + "dollars", + "duty", + "federal", + "finance", + "government", + "guarantee", + "guard", + "integrity", + "job", + "money", + "online", + "operation", + "pay", + "payment", + "protected", + "protection", + "reliability", + "safe", + "safeguard", + "safety", + "secure", + "secured", + "security", + "sensitive regulatory", + "shield", + "task", + "tick", + "trust", + "validated", + "verified", + "work", + "workload" + ], + "popularity": 6900 + }, + "ATM": { + "tags": [ + "alphabet", + "atm", + "automated", + "automated teller machine", + "banking", + "bill", + "building", + "card", + "cart", + "cash", + "cash machine", + "character", + "coin", + "commerce", + "credit", + "currency", + "deposit", + "dollars", + "finance", + "financial", + "finding", + "font", + "keypads", + "letters", + "location", + "machine", + "map", + "money", + "money machine", + "navigation", + "numbers", + "online", + "pay", + "payment", + "point of interest", + "public", + "rectangle", + "screen", + "service", + "shopping", + "slot", + "structure", + "symbol", + "teller", + "text", + "transaction", + "type", + "withdrawal" + ], + "popularity": 3103 + }, + "ATTACH_EMAIL": { + "tags": [ + "add", + "add attachment", + "add file", + "attach", + "attach file", + "attach paper clip", + "attachment", + "clip", + "communication", + "compose", + "compose email", + "compose mail", + "connect", + "correspondence", + "document", + "email", + "envelop", + "file", + "include attachment", + "include file", + "letter", + "letters", + "link", + "link file", + "mail", + "message", + "office", + "paper", + "paper clip", + "paperclip", + "send", + "workspace" + ], + "popularity": 6238 + }, + "ATTACH_FILE": { + "tags": [ + "add", + "append", + "attach", + "attachment", + "binding", + "chain", + "choose", + "clip", + "communication", + "connect", + "correspondence", + "data", + "document", + "email", + "fastener", + "file", + "input", + "insert", + "link", + "mail", + "media", + "message", + "office", + "paper", + "paperclip", + "record", + "report", + "secure", + "select", + "send", + "share", + "upload" + ], + "popularity": 50776 + }, + "ATTACH_MONEY": { + "tags": [ + "add money", + "amount", + "attach", + "banking", + "bill", + "business", + "buy", + "card", + "cash", + "circle", + "coin", + "commerce", + "connect", + "cost", + "credit", + "currency", + "dollar sign", + "dollars", + "economy", + "exchange", + "finance", + "financial", + "funds", + "income", + "investment", + "link", + "monetization", + "money", + "on", + "online", + "pay", + "payment", + "price", + "profit", + "purchase", + "revenue", + "sell", + "shopping", + "symbol", + "transaction", + "value", + "wealth" + ], + "popularity": 91004 + }, + "ATTACHMENT": { + "tags": [ + "add file", + "attach", + "attachment", + "clip", + "communication", + "compose", + "connect", + "connect file", + "document", + "document icon", + "document management", + "email", + "file", + "image", + "insert document", + "insert file", + "link", + "office", + "office supplies", + "paperclip", + "paperclip icon", + "productivity", + "send", + "share", + "share document", + "upload document", + "upload file" + ], + "popularity": 23732 + }, + "ATTRACTIONS": { + "tags": [ + "activity", + "amusement", + "amusement park", + "attractions", + "circle", + "destination", + "entertainment", + "event", + "excitement", + "ferris", + "ferris wheel", + "fun", + "geometry", + "holiday", + "landmark", + "leisure", + "lines", + "maps", + "park", + "place", + "places", + "pleasure", + "recreation", + "ride", + "spot", + "theme park", + "thrill", + "tourism", + "travel", + "trip", + "vacation", + "view", + "wheel" + ], + "popularity": 4477 + }, + "ATTRIBUTION": { + "tags": [ + "account", + "attribute", + "attribution", + "author", + "body", + "cc", + "circle", + "community", + "content", + "copyright", + "copywriter", + "creative commons", + "credit", + "human", + "icon", + "intellectual property", + "label", + "legal", + "letters", + "license", + "licensing", + "marker", + "media", + "open source", + "people", + "permission", + "person", + "profile", + "rights", + "sharing", + "source", + "stamp", + "symbol", + "text", + "usage", + "user", + "video", + "youtube" + ], + "popularity": 5757 + }, + "AUDIO_FILE": { + "tags": [ + "add", + "audio", + "bars", + "chart", + "control", + "create", + "data", + "digital", + "doc", + "document", + "download", + "equalizer", + "file", + "format", + "graph", + "key", + "lines", + "media", + "music", + "note", + "player", + "representation", + "sound", + "technology", + "three lines", + "track", + "type", + "upload", + "vertical lines", + "volume", + "wave", + "waveform" + ], + "popularity": 3000 + }, + "AUDIOTRACK": { + "tags": [ + "audio", + "audio file", + "audio icon", + "audiotrack", + "clef", + "composition", + "eighth note", + "key", + "listen", + "media", + "media controls", + "melody", + "music", + "music icon", + "musical", + "note", + "play", + "player", + "playlist", + "quaver", + "rhythm", + "score", + "song", + "sound", + "sound icon", + "track", + "tune", + "waveform" + ], + "popularity": 13022 + }, + "AUTO_AWESOME": { + "tags": [ + "adjust", + "ai", + "artificial", + "artificial intelligence", + "auto", + "automatic", + "automation", + "awesome", + "beautiful", + "custom", + "edit", + "editing", + "effect", + "enhance", + "filter", + "filters", + "function", + "genai", + "improve", + "intelligence", + "magic", + "magic wand", + "recommend", + "recommendations", + "refine", + "smart", + "spark", + "sparkle", + "special effects", + "star", + "stars", + "suggest", + "suggestion", + "tool", + "twinklestar", + "wand" + ], + "popularity": 47301 + }, + "AUTO_AWESOME_MOSAIC": { + "tags": [ + "adjust", + "album", + "arrange", + "art", + "auto", + "automatic", + "awesome", + "blocks", + "collage", + "collection", + "create", + "design", + "display", + "edit", + "editing", + "enhance", + "enhanced", + "format", + "gallery", + "grid", + "group", + "image", + "layout", + "mosaic", + "multiple", + "organize", + "pattern", + "photo", + "pieces", + "presentation", + "rectangles", + "sections", + "squares", + "structure", + "tile", + "view" + ], + "popularity": 5847 + }, + "AUTO_AWESOME_MOTION": { + "tags": [ + "adjust", + "ai", + "animate", + "animation", + "auto", + "automatic", + "automation", + "awesome", + "collage", + "create", + "dynamic", + "edit", + "editing", + "effect", + "enhance", + "enhancement", + "film", + "filmstrip", + "frames", + "generate", + "generate video", + "image", + "improve", + "magic", + "magical", + "motion", + "movement", + "photo", + "process", + "quality", + "sequence", + "smart", + "sparkle", + "stars", + "timeline", + "video" + ], + "popularity": 7483 + }, + "AUTO_DELETE": { + "tags": [ + "archive", + "auto", + "auto delete", + "automatic", + "bin", + "can", + "clean up", + "clear", + "clock", + "configuration", + "content", + "control", + "data", + "date", + "delete", + "disposal", + "document", + "erase", + "file", + "garbage", + "management", + "message", + "recurring", + "remove", + "schedule", + "settings", + "time", + "timer", + "tool", + "trash", + "utility" + ], + "popularity": 6982 + }, + "AUTO_FIX_HIGH": { + "tags": [ + "adjust", + "ai", + "artificial", + "auto", + "automated", + "automatic", + "automatically", + "automation", + "beautify", + "custom", + "edit", + "editing", + "effect", + "emphasize", + "enhance", + "erase", + "filter", + "fix", + "genai", + "glitter", + "glow", + "glowing", + "high", + "highlight", + "improve", + "improve quality", + "intelligence", + "magic", + "magic wand", + "modify", + "pen", + "perfect", + "polish", + "refine", + "retouch", + "shine", + "smart", + "spark", + "sparkle", + "spell", + "star", + "tool", + "touch up", + "twinkle", + "wand", + "wizard" + ], + "popularity": 19847 + }, + "AUTO_FIX_NORMAL": { + "tags": [ + "adjust", + "ai", + "apply", + "artificial", + "auto", + "auto fix", + "automated", + "automatic", + "automation", + "custom", + "default", + "edit", + "effect", + "enhance", + "erase", + "filter", + "fix", + "genai", + "improve", + "intelligence", + "intelligent", + "magic", + "magic wand", + "modify", + "normal", + "optimize", + "perfect", + "process", + "quick fix", + "refine", + "retouch", + "smart", + "spark", + "sparkle", + "star", + "suggestions", + "tool", + "transform", + "wand", + "wizard" + ], + "popularity": 6717 + }, + "AUTO_FIX_OFF": { + "tags": [ + "adjustments off", + "ai", + "artificial", + "auto", + "auto enhance off", + "auto fix off", + "automatic", + "automation", + "block", + "cancel", + "clear", + "corrections off", + "custom", + "delete", + "denied", + "deselect", + "disable", + "disabled", + "edit", + "enabled", + "erase", + "exclude", + "filter off", + "fix", + "genai", + "intelligence", + "magic", + "magic wand", + "minus", + "modify", + "no", + "none", + "not available", + "off", + "on", + "remove", + "slash", + "smart", + "spark", + "sparkle", + "sparkles", + "star", + "stars", + "turn off", + "uncheck", + "wand" + ], + "popularity": 1568 + }, + "AUTO_GRAPH": { + "tags": [ + "analysis", + "analytics", + "auto", + "auto graph", + "automated", + "automatic", + "business", + "chart", + "dashboard", + "data", + "data representation", + "decline", + "diagram", + "economics", + "finance", + "graph", + "growth", + "infographic", + "information", + "line", + "line graph", + "measure", + "metrics", + "performance", + "plot", + "presentation", + "progress", + "report", + "stars", + "statistics", + "tracking", + "trend", + "visualization" + ], + "popularity": 14918 + }, + "AUTO_MODE": { + "tags": [ + "a", + "ai", + "alphabet", + "around", + "arrow", + "arrows", + "artificial", + "auto", + "auto mode", + "automatic", + "automation", + "character", + "configuration", + "control", + "custom", + "direction", + "feature", + "function", + "genai", + "inprogress", + "intelligence", + "letter a", + "letters", + "load", + "loading refresh", + "magic", + "mode", + "navigation", + "nest", + "option", + "preference", + "renew", + "rotate", + "selection", + "setting", + "smart", + "spark", + "sparkle", + "star", + "switch", + "text", + "toggle", + "turn" + ], + "popularity": 4253 + }, + "AUTO_STORIES": { + "tags": [ + "archive", + "articles", + "auto", + "bibliography", + "book", + "books", + "chapter", + "collection", + "content", + "education", + "feed", + "flipping", + "information", + "journal", + "learning", + "library", + "literature", + "magazine", + "narration", + "narrative", + "news", + "open book", + "pages", + "publication", + "read", + "reading", + "series", + "stories", + "story", + "stream", + "tales", + "textbook" + ], + "popularity": 41711 + }, + "AUTOFPS_SELECT": { + "tags": [ + "a", + "adjust", + "alphabet", + "animation", + "auto", + "automatic", + "character", + "chart", + "computer", + "control", + "curve", + "data", + "digital", + "display", + "font", + "fps", + "frame", + "frame rate", + "frames per second", + "frequency", + "graph", + "indicator", + "information", + "letters", + "line", + "measure", + "metric", + "motion", + "optimize", + "per", + "performance", + "quality", + "rate", + "second", + "seconds", + "select", + "settings", + "smooth", + "speed", + "statistics", + "symbol", + "technology", + "text", + "type", + "video" + ], + "popularity": 980 + }, + "AUTORENEW": { + "tags": [ + "action", + "around", + "arrow", + "arrows", + "autorenew", + "cache", + "cached", + "circle", + "circular", + "circular arrow", + "content", + "continuous", + "curved arrow", + "cycle", + "data", + "direction", + "endless", + "inprogress", + "load", + "loading refresh", + "loop", + "media", + "navigation", + "playback", + "process", + "redo", + "refresh", + "refresh data", + "refresh page", + "reload", + "renew", + "repeat", + "repeat playlist", + "repeat song", + "restart", + "rotate", + "synchronize", + "turn", + "update" + ], + "popularity": 73921 + }, + "AV_TIMER": { + "tags": [ + "alert", + "av", + "chronograph", + "circular", + "clock", + "competition", + "countdown", + "deadline", + "duration", + "event", + "hour", + "interval", + "lap time", + "measurement", + "minute", + "minutes", + "notification", + "outline", + "performance", + "race", + "reminder", + "schedule", + "second", + "seconds", + "speed", + "stop watch", + "stopwatch", + "time", + "timekeeping", + "timer", + "timing", + "track", + "watch" + ], + "popularity": 8154 + }, + "BABY_CHANGING_STATION": { + "tags": [ + "accessibility", + "amenities", + "babies", + "baby", + "bathroom", + "body", + "care", + "changing", + "changing station", + "child", + "children", + "diaper", + "facilities", + "family", + "father", + "health", + "human", + "hygiene", + "infant", + "kids", + "lavatory", + "location", + "medical", + "mother", + "nappy", + "newborn", + "nursery", + "parent", + "parent and child room", + "parents room", + "people", + "person", + "pictogram", + "place", + "public restrooms", + "rest area", + "restroom", + "services", + "sign", + "station", + "symbol", + "toddler", + "toilets", + "w.c.", + "wc", + "young" + ], + "popularity": 3204 + }, + "BACK_HAND": { + "tags": [ + "anatomy", + "appendage", + "back", + "back of hand", + "backhand", + "body part", + "fingers", + "five", + "five fingers", + "gesture", + "hand", + "high five", + "human", + "index finger", + "knuckles", + "limb", + "middle finger", + "open", + "open hand", + "palm", + "palm facing away", + "person", + "pinky", + "raised", + "ring finger", + "stop", + "talk to the hand", + "thumb", + "wave" + ], + "popularity": 11975 + }, + "BACKPACK": { + "tags": [ + "adventure", + "back", + "backpack", + "bag", + "book", + "bookbag", + "camping", + "camping bag", + "carry", + "college", + "daypack", + "education", + "gear", + "hiking", + "hiking bag", + "journey", + "knapsack", + "luggage", + "outdoor", + "pack", + "rucksack", + "satchel", + "school", + "storage", + "supplies", + "travel", + "travel bag", + "trip", + "vacation" + ], + "popularity": 4332 + }, + "BACKSPACE": { + "tags": [ + "arrow", + "back", + "backspace", + "box", + "button", + "cancel", + "character", + "clear", + "computer", + "control", + "correct", + "delete", + "edit", + "editing", + "entry", + "erase", + "form", + "input", + "input field", + "keyboard", + "left", + "navigation", + "pointed", + "rectangular", + "remove", + "symbol", + "text", + "triangle", + "typing", + "ui", + "undo", + "ux" + ], + "popularity": 28273 + }, + "BACKUP": { + "tags": [ + "archive", + "arrow", + "backup", + "cloud", + "computing", + "copy", + "data", + "database", + "digital", + "document", + "download", + "drive", + "duplicate", + "file", + "files folders", + "folder", + "history", + "internet", + "management", + "network", + "protection", + "recovery", + "restore", + "save", + "security", + "server", + "storage", + "synchronize", + "system", + "technology", + "transfer", + "up", + "upload" + ], + "popularity": 17549 + }, + "BACKUP_TABLE": { + "tags": [ + "archive", + "backup", + "cloud", + "columns", + "copy", + "data", + "database", + "document", + "drive", + "duplicate", + "file", + "files folders", + "format", + "grid", + "history", + "layout", + "list", + "migration", + "protection", + "restore", + "rows", + "save", + "security", + "spreadsheet", + "stack", + "storage", + "sync", + "synchronize", + "table", + "version" + ], + "popularity": 6166 + }, + "BADGE": { + "tags": [ + "accolade", + "account", + "achievement", + "approval", + "avatar", + "award", + "badge", + "card", + "certificate", + "certified", + "champion", + "crest", + "distinction", + "emblem", + "employee", + "endorsed", + "excellence", + "face", + "guarantee", + "honor", + "human", + "id", + "id card", + "identification", + "mark", + "merit", + "name", + "official", + "people", + "person", + "premium", + "prize", + "profile", + "quality", + "recognition", + "reward", + "seal", + "security", + "stamp", + "star", + "symbol", + "token", + "user", + "verified", + "warranty", + "winner", + "work" + ], + "popularity": 61282 + }, + "BAKERY_DINING": { + "tags": [ + "baked goods", + "bakery", + "baking", + "bread", + "breakfast", + "brunch", + "cafe", + "catering", + "croissant", + "cuisine", + "dessert", + "dining", + "eat", + "food", + "food service", + "ingredient", + "meal", + "menu", + "oven", + "pastry", + "patisserie", + "restaurant", + "savory", + "serving", + "snack", + "sweet", + "table", + "treat" + ], + "popularity": 6601 + }, + "BALANCE": { + "tags": [ + "balance", + "compare", + "compare and contrast", + "court", + "courthouse", + "decision", + "equal", + "equality", + "equilibrium", + "equity", + "fair", + "horizontal line", + "impartiality", + "judgment", + "justice", + "law", + "legal", + "measure", + "measurement", + "object", + "parity", + "proportion", + "scale", + "scales", + "stability. equilibrium", + "steadiness", + "symbol", + "symmetry", + "two pans", + "two sides", + "vertical line", + "weighing", + "weight" + ], + "popularity": 10571 + }, + "BALCONY": { + "tags": [ + "accommodation", + "apartment", + "architecture", + "balcony", + "building", + "doors", + "estate", + "exterior", + "flat", + "home", + "hotel", + "house", + "housing", + "living space", + "loggia", + "maps", + "open air", + "out", + "outdoor", + "outdoor space", + "outside", + "place", + "property", + "railing", + "real", + "real estate", + "residence", + "residential", + "residential building", + "stay", + "structure", + "terrace", + "tourism", + "travel", + "vacation", + "veranda", + "view", + "window" + ], + "popularity": 2493 + }, + "BALLOT": { + "tags": [ + "agreement", + "ballot", + "box", + "bullet", + "checklist", + "choice", + "choices", + "consent", + "democracy", + "document", + "election", + "form", + "governance", + "items", + "law", + "legal", + "list", + "paper", + "point", + "political", + "poll", + "questionnaire", + "register", + "registration", + "selection", + "selections", + "square", + "survey", + "task", + "tasks", + "vote", + "voting" + ], + "popularity": 14983 + }, + "BAR_CHART": { + "tags": [ + "analysis", + "analytics", + "bar", + "bar chart", + "bars", + "business", + "chart", + "columns", + "dashboard", + "data", + "data analysis", + "diagram", + "finance", + "financial data", + "graph", + "growth", + "growth icon", + "infographic", + "information", + "measure", + "metrics", + "performance", + "progress", + "quantitative", + "report", + "report icon", + "statistics", + "statistics icon", + "tracking", + "trends", + "visual representation", + "visualization" + ], + "popularity": 40441 + }, + "BATCH_PREDICTION": { + "tags": [ + "ai", + "algorithms", + "analysis", + "artificial intelligence", + "automated", + "batch", + "bulb", + "bulk", + "collection", + "computations", + "data", + "documents", + "files", + "flow", + "group", + "idea", + "large scale", + "layers", + "light", + "machine learning", + "multiple", + "output", + "prediction", + "predictions", + "process", + "processing", + "queue", + "results", + "set", + "stacked", + "system", + "volume" + ], + "popularity": 4902 + }, + "BATHROOM": { + "tags": [ + "accessibility", + "accessible", + "amenities", + "bar", + "bath", + "bathroom", + "building", + "closet", + "convenience", + "directions", + "disabled access", + "facilities", + "gender neutral", + "home", + "hotel", + "house", + "hygiene", + "lavatory", + "location", + "mens", + "navigation", + "place", + "plumbing", + "public bathroom", + "public facilities", + "public restroom", + "public toilet", + "public wc", + "restaurant", + "restroom", + "room", + "sanitary", + "shower", + "sprinkler", + "toilet", + "toilet facilities", + "toilet room", + "unisex", + "venue", + "wash", + "wash room", + "washroom", + "water", + "water closet", + "wc", + "womens" + ], + "popularity": 3734 + }, + "BATHTUB": { + "tags": [ + "amenity", + "appliance", + "bath", + "bathing", + "bathroom", + "bathtub", + "bubbles", + "clean", + "comfort", + "domestic", + "element", + "fixture", + "graphic", + "home", + "hotel", + "house", + "human", + "hygiene", + "icon", + "leisure", + "outline", + "person", + "plumbing", + "relaxation", + "sanitation", + "shape", + "shower", + "soak", + "spa", + "symbol", + "therapy", + "travel", + "tub", + "wash", + "water", + "wellness" + ], + "popularity": 6738 + }, + "BATTERY_0_BAR": { + "tags": [ + "alert", + "bar", + "battery", + "cell", + "charge", + "critical", + "device", + "electric", + "empty", + "energy", + "icon", + "indicator", + "laptop", + "level", + "low", + "meter", + "mobile", + "phone", + "power", + "rectangle", + "status", + "tablet", + "warning", + "zero" + ], + "popularity": 3180 + }, + "BATTERY_1_BAR": { + "tags": [ + "1 bar", + "20 percent", + "20%", + "bar", + "battery", + "cell", + "charge", + "charging", + "computer", + "device", + "electrical", + "empty", + "energy", + "full", + "gauge", + "horizontal", + "indicator", + "laptop", + "level", + "low", + "meter", + "mobile", + "one bar", + "phone", + "power", + "rectangle", + "status", + "twenty percent" + ], + "popularity": 2418 + }, + "BATTERY_2_BAR": { + "tags": [ + "2 bars", + "30 percent", + "bar", + "battery", + "battery indicator", + "battery level", + "cell", + "charge", + "charge level", + "device", + "electrical", + "energy", + "fill", + "gadget", + "half", + "indicator", + "level", + "low", + "medium", + "meter", + "mobile", + "percentage", + "portable", + "power", + "power status", + "rectangular", + "segmented", + "status", + "thirty percent", + "two bars" + ], + "popularity": 2031 + }, + "BATTERY_3_BAR": { + "tags": [ + "50%", + "bar", + "battery", + "battery gauge", + "battery icon", + "battery indicator", + "battery meter", + "battery status", + "cell", + "charge", + "charge status", + "energy", + "energy level", + "fill", + "gauge", + "half", + "indicator", + "intermediate", + "level", + "medium", + "meter", + "middle", + "mobile", + "percentage", + "power", + "power icon", + "power level", + "power status", + "remaining energy", + "remaining power", + "status", + "three bars" + ], + "popularity": 2670 + }, + "BATTERY_4_BAR": { + "tags": [ + "60", + "almost full", + "bar", + "bars", + "battery", + "capacity", + "cell", + "charge", + "circle", + "device", + "energy", + "five bars", + "four bars", + "full", + "indicator", + "laptop", + "level", + "mobile", + "percentage", + "phone", + "power", + "rectangle", + "remaining", + "rounded rectangle", + "six bars", + "status", + "tablet", + "three bars" + ], + "popularity": 3209 + }, + "BATTERY_5_BAR": { + "tags": [ + "80%", + "bars", + "battery", + "cell", + "charge", + "charging", + "device", + "electric", + "electronic", + "energy", + "five bars", + "five segments", + "four fifths", + "full", + "gauge", + "high level", + "indicator", + "level", + "lines", + "meter", + "mobile", + "notification icon", + "percentage", + "power", + "rechargeable", + "rectangle", + "status", + "status bar", + "system icon", + "vertical" + ], + "popularity": 3947 + }, + "BATTERY_6_BAR": { + "tags": [ + "90", + "almost full", + "bar", + "bars", + "battery", + "battery status", + "cell", + "charge", + "charge level", + "charged", + "device", + "electric", + "energy", + "energy level", + "full", + "full battery", + "high", + "high battery", + "indicator", + "level", + "meter", + "mobile", + "nearly full", + "nine", + "ninety", + "percentage", + "power", + "power level", + "status", + "zero" + ], + "popularity": 2835 + }, + "BATTERY_ALERT": { + "tags": [ + "!", + "alert", + "attention", + "battery", + "caution", + "cell", + "charge", + "critical", + "danger", + "device status", + "energy", + "error", + "exclamation", + "exclamation point", + "important", + "low battery", + "mark", + "mobile", + "notification", + "phone", + "power", + "status", + "symbol", + "system status", + "triangle", + "warning" + ], + "popularity": 4850 + }, + "BATTERY_CHARGING_FULL": { + "tags": [ + "battery", + "bolt", + "capacity", + "cell", + "charge", + "charged", + "charging", + "charging up", + "complete", + "connection", + "device", + "electric", + "electricity", + "electronic", + "energy", + "full", + "gadget", + "indicator", + "instant", + "level", + "lightning", + "low", + "mobile", + "plugged in", + "power", + "power supply", + "power up", + "rectangle", + "status", + "symbol", + "technology", + "thunder", + "thunderbolt" + ], + "popularity": 16616 + }, + "BATTERY_FULL": { + "tags": [ + "bar", + "battery", + "battery icon", + "battery level", + "battery meter", + "cell", + "charge", + "device", + "device status", + "electronic", + "energy", + "energy level", + "full", + "full battery", + "full charge", + "gadget", + "indicator", + "level", + "max charge", + "mobile", + "percentage", + "power", + "power indicator", + "power status", + "rectangular", + "signal", + "standard battery", + "status", + "technology" + ], + "popularity": 21179 + }, + "BATTERY_SAVER": { + "tags": [ + "+", + "add", + "addition", + "bar", + "battery", + "charge", + "charging", + "configuration", + "conserve", + "control", + "device", + "efficiency", + "energy", + "energy saving", + "fill", + "indicator", + "level", + "low power", + "management", + "mobile", + "new", + "options", + "phone", + "plus", + "power", + "power saving", + "rectangle", + "save", + "saver", + "settings", + "smartphone", + "status", + "symbol", + "technology" + ], + "popularity": 3479 + }, + "BATTERY_STD": { + "tags": [ + "bar", + "battery", + "battery icon", + "battery level", + "battery meter", + "cell", + "charge", + "device", + "device status", + "electronic", + "energy", + "energy level", + "full", + "full battery", + "full charge", + "gadget", + "indicator", + "level", + "max charge", + "mobile", + "percentage", + "power", + "power indicator", + "power status", + "rectangular", + "signal", + "standard battery", + "status", + "technology" + ], + "popularity": 6485 + }, + "BATTERY_UNKNOWN": { + "tags": [ + "?", + "assistance", + "battery", + "cell", + "charge", + "device", + "electricity", + "element", + "energy", + "graphic", + "help", + "icon", + "indicator", + "info", + "information", + "level", + "mobile", + "outline", + "power", + "punctuation", + "query", + "question mark", + "rectangle", + "status", + "status bar", + "support", + "symbol", + "system", + "troubleshoot", + "ui", + "unavailable", + "unknown", + "unsure" + ], + "popularity": 2883 + }, + "BEACH_ACCESS": { + "tags": [ + "access", + "activity", + "beach", + "coastal", + "coastline", + "destination", + "getaway", + "holiday", + "leisure", + "ocean", + "outdoors", + "parasol", + "places", + "recreation", + "relax", + "relaxation", + "resort", + "sand", + "sea", + "shade", + "summer", + "sun", + "sunny", + "sunshade", + "tourism", + "travel", + "trip", + "tropical", + "umbrella", + "vacation" + ], + "popularity": 10420 + }, + "BED": { + "tags": [ + "apartment", + "bed", + "bedroom", + "bedtime", + "blanket", + "comfort", + "double", + "dreaming", + "dwelling", + "full", + "furniture", + "home", + "hospital", + "hostel", + "hotel", + "house", + "inn", + "king", + "lodging", + "mattress", + "motel", + "nap", + "night", + "pillow", + "pillows", + "queen", + "relax", + "residence", + "rest", + "room", + "siesta", + "size", + "sleep", + "sleeping" + ], + "popularity": 14875 + }, + "BEDROOM_BABY": { + "tags": [ + "babies", + "baby", + "bed", + "bedroom", + "care", + "child", + "childhood", + "children", + "comfort", + "cradle", + "crib", + "domestic", + "family", + "furniture", + "guardian", + "home", + "horse", + "house", + "infant", + "interior", + "kid", + "monitor", + "nap", + "newborn", + "nursery", + "parent", + "rest", + "rocking", + "room", + "room type", + "safety", + "security", + "sleep", + "sleeping", + "toddler", + "young" + ], + "popularity": 3847 + }, + "BEDROOM_CHILD": { + "tags": [ + "accommodation", + "baby", + "bed", + "bedroom", + "building", + "child", + "children", + "cot", + "crib", + "domestic", + "furniture", + "home", + "hotel", + "house", + "infant", + "interior", + "kid", + "kids", + "lodging", + "night", + "nursery", + "pillows", + "rest", + "room", + "size", + "sleep", + "sleeping", + "small", + "toddler", + "twin", + "young" + ], + "popularity": 3107 + }, + "BEDROOM_PARENT": { + "tags": [ + "adult", + "bed", + "bedroom", + "building", + "child", + "children", + "domestic", + "double", + "dwelling", + "family", + "full", + "furniture", + "guardian", + "home", + "hotel", + "house", + "kids", + "king", + "night", + "parent", + "parents", + "pillows", + "queen", + "relaxation", + "residential", + "rest", + "room", + "sizem master", + "sleep", + "sleeping", + "structure" + ], + "popularity": 3885 + }, + "BEDTIME": { + "tags": [ + "astronomy", + "bedtime", + "calm", + "celestial", + "celestial bodies", + "clear", + "clear night", + "clear sky", + "climate", + "cosmos", + "crescent moon", + "dark", + "evening", + "evening sky", + "galaxy", + "home", + "lunar", + "midnight", + "moon", + "nest", + "night", + "nightime", + "nocturnal", + "peaceful", + "quiet", + "quiet time", + "relaxation", + "rest", + "security", + "silent", + "sleep", + "slumber", + "space", + "stars", + "thermostat", + "time", + "weather" + ], + "popularity": 5566 + }, + "BEDTIME_OFF": { + "tags": [ + "active", + "bedtime", + "button", + "clear", + "climate", + "crescent", + "disabled", + "dream", + "home", + "icon", + "inactive", + "indicator", + "lunar", + "mode", + "moon", + "nest", + "night", + "nightime", + "off", + "offline", + "private", + "quiet", + "rest", + "security", + "silence", + "slash", + "sleep", + "slumber", + "stars", + "status", + "symbol", + "thermostat", + "time", + "toggle", + "weather", + "zzz" + ], + "popularity": 739 + }, + "BEENHERE": { + "tags": [ + "acknowledgement", + "approve", + "archive", + "arrival", + "been", + "beenhere", + "bookmark", + "check", + "check-in", + "checked", + "complete", + "confirmed", + "destination", + "done", + "favorite", + "geo", + "geographic", + "here", + "label", + "landmark", + "library", + "location", + "map", + "mark", + "marker", + "navigation", + "ok", + "pin", + "place", + "point", + "position", + "previously", + "read", + "reading", + "remember", + "ribbon", + "save", + "seen", + "select", + "spot", + "tag", + "tick", + "tourism", + "travel", + "trip", + "validate", + "verified", + "visited", + "visited place", + "yes" + ], + "popularity": 10067 + }, + "BENTO": { + "tags": [ + "applications", + "arrangement", + "bento", + "blocks", + "box", + "collection", + "compartments", + "control", + "dashboard", + "dinner", + "display", + "food", + "grid", + "grouped", + "launcher", + "layout", + "lunch", + "matrix", + "meal", + "menu", + "modules", + "navigation", + "nine squares", + "options", + "organized", + "pattern", + "restaurant", + "sections", + "shortcuts", + "squares", + "structure", + "takeout", + "tiles", + "view", + "window" + ], + "popularity": 2374 + }, + "BIKE_SCOOTER": { + "tags": [ + "agile", + "automobile", + "bicycle", + "bike", + "car", + "cars", + "city", + "commute", + "exercise", + "fast", + "graphic", + "maps", + "mobility", + "outdoor", + "outline", + "personal", + "pictogram", + "quick", + "recreation", + "rental", + "ride", + "scooter", + "sharing", + "sign", + "simple", + "sports", + "symbol", + "transport", + "transportation", + "travel", + "two-wheeled", + "urban", + "vehicle", + "vespa", + "wheeled" + ], + "popularity": 1476 + }, + "BIOTECH": { + "tags": [ + "analysis", + "beaker", + "biology", + "biotech", + "chemical", + "chemistry", + "data", + "development", + "discovery", + "dna", + "experiment", + "flask", + "futuristic", + "genetics", + "healthcare", + "innovation", + "laboratory", + "liquid", + "medicine", + "microscope", + "molecular", + "progress", + "research", + "science", + "solution", + "technology", + "test", + "tube" + ], + "popularity": 14878 + }, + "BLENDER": { + "tags": [ + "appliance", + "base", + "beverage preparation", + "blades", + "blend", + "blender", + "container", + "cook", + "cooking", + "drink", + "electric", + "electric mixer", + "food", + "food preparation", + "food processing", + "home", + "home appliance", + "jug", + "juicer", + "kitchen", + "kitchen gadget", + "liquid", + "machine", + "mixing", + "mixing machine", + "object", + "preparing drinks", + "preparing food", + "shake", + "smoothie", + "vitamix" + ], + "popularity": 4333 + }, + "BLIND": { + "tags": [ + "abstract", + "accessibility", + "accessible", + "assist", + "blind", + "blinds", + "blinds down", + "block", + "body", + "cane", + "closed blinds", + "cover", + "curtain", + "darkness", + "decoration", + "disability", + "geometry", + "handicap", + "help", + "home", + "horizontal lines", + "human", + "interior", + "light", + "mobility", + "obscure", + "parallel", + "parallel lines", + "person", + "privacy", + "shades", + "stripes", + "sunblock", + "vertical lines", + "walk", + "walker", + "window", + "window blinds", + "window covering", + "window shades" + ], + "popularity": 931 + }, + "BLINDS": { + "tags": [ + "adjust", + "automation", + "blinds", + "close", + "control", + "cover", + "covering", + "curtains", + "decoration", + "home", + "home decor", + "horizontal lines", + "house", + "interior", + "light control", + "lines", + "nest", + "open", + "panel", + "privacy", + "rectangle", + "rectangular", + "shade", + "shades", + "shutter", + "smart home", + "solid", + "stripe", + "sunshade", + "venetian blinds", + "vertical lines", + "window", + "window covering" + ], + "popularity": 873 + }, + "BLINDS_CLOSED": { + "tags": [ + "architecture", + "blinds", + "block light", + "building", + "closed", + "cover", + "covering", + "curtains", + "darkness", + "home automation", + "horizontal lines", + "interior", + "light control", + "nest", + "opaque", + "parallel lines", + "privacy", + "rectangular", + "residential", + "room darkener", + "secure", + "shade", + "shutter", + "shutters", + "smart home", + "sunblock", + "sunshade", + "window blinds", + "window covering" + ], + "popularity": 762 + }, + "BLOCK": { + "tags": [ + "alert", + "avoid", + "ban", + "block", + "cancel", + "circle", + "close", + "control", + "diagonal", + "disable", + "disturb", + "do not disturb", + "entry", + "exclude", + "exit", + "forbidden", + "interrupt", + "limit", + "line", + "mute", + "no", + "notification", + "off", + "preference", + "prohibited", + "quiet", + "quit", + "remove", + "restricted", + "setting", + "silent", + "slash", + "state", + "status", + "stop", + "unavailable" + ], + "popularity": 43496 + }, + "BLOODTYPE": { + "tags": [ + "abstract", + "analysis", + "blood", + "blood type", + "bloodtype", + "donate", + "donation", + "droplet", + "emergency", + "health", + "healthcare", + "hospital", + "icon", + "information", + "lab", + "laboratory", + "medical", + "medical record", + "medicine", + "minimal", + "negative", + "patient", + "positive", + "profile", + "report", + "result", + "shape", + "symbol", + "test", + "type", + "water" + ], + "popularity": 6552 + }, + "BLUETOOTH": { + "tags": [ + "audio", + "bluetooth", + "cast", + "communication", + "connect", + "connection", + "connectivity", + "data", + "device", + "electronic", + "icon", + "line", + "mobile", + "network", + "pairing", + "paring", + "share", + "signal", + "streaming", + "symbol", + "technology", + "transfer", + "wireless", + "zig-zag" + ], + "popularity": 13333 + }, + "BLUETOOTH_AUDIO": { + "tags": [ + "audio", + "bluetooth", + "communication", + "connect", + "connecting", + "connection", + "connectivity", + "data", + "device", + "discover", + "find", + "geometric", + "lines", + "link", + "media", + "music", + "network", + "pairing", + "scan", + "searching", + "shape", + "signal", + "sound", + "symbol", + "technology", + "transfer", + "waves", + "wireless" + ], + "popularity": 1911 + }, + "BLUETOOTH_CONNECTED": { + "tags": [ + "audio", + "bluetooth", + "bluetooth icon", + "cast", + "communication", + "communication technology", + "connect", + "connected", + "connected devices", + "connection", + "connection status", + "data", + "device", + "discover", + "discoverable", + "electronic", + "electronic device", + "link", + "link devices", + "mobile", + "network", + "network connection", + "paired", + "pairing", + "paring", + "signal", + "signal strength", + "streaming", + "symbol", + "technology", + "technology symbol", + "wireless", + "wireless connection" + ], + "popularity": 3971 + }, + "BLUETOOTH_DISABLED": { + "tags": [ + "audio", + "bluetooth", + "cast", + "communication", + "connect", + "connection", + "connectivity", + "cross", + "data", + "device", + "diagonal line", + "disabled", + "disconnected", + "electronics", + "enabled", + "icon", + "line", + "mobile", + "network", + "off", + "offline", + "on", + "pairing", + "paring", + "peripheral", + "signal", + "slash", + "streaming", + "symbol", + "technology", + "unavailable", + "wireless" + ], + "popularity": 3178 + }, + "BLUETOOTH_DRIVE": { + "tags": [ + "automobile", + "bluetooth", + "car", + "cars", + "cast", + "communication", + "computer", + "connect", + "connection", + "connectivity", + "data", + "device", + "digital", + "drive", + "electronic", + "hard drive", + "link", + "logo", + "maps", + "media", + "memory", + "network", + "pairing", + "paring", + "pc", + "storage", + "streaming", + "symbol", + "sync", + "synchronize", + "technology", + "transfer", + "transfer data", + "transportation", + "travel", + "vehicle", + "wireless" + ], + "popularity": 1352 + }, + "BLUETOOTH_SEARCHING": { + "tags": [ + "audio", + "bluetooth", + "communication", + "connecting", + "connection", + "connectivity", + "data", + "device", + "discover", + "find", + "geometric", + "lines", + "link", + "media", + "network", + "pairing", + "paring", + "scan", + "search", + "searching", + "shape", + "signal", + "sound", + "symbol", + "technology", + "transfer", + "waves", + "wireless" + ], + "popularity": 3256 + }, + "BLUR_CIRCULAR": { + "tags": [ + "aesthetic", + "art", + "blur", + "circle", + "circular", + "design", + "diffused", + "dots", + "dreamy", + "edit", + "editing", + "effect", + "enhance", + "filter", + "focus", + "fuzzy", + "gaussian", + "graphic", + "halo", + "image", + "out of focus", + "photo", + "photography", + "radial", + "radial blur", + "smooth", + "soft", + "soft focus", + "unfocus", + "visual" + ], + "popularity": 2664 + }, + "BLUR_LINEAR": { + "tags": [ + "adjust", + "art", + "blend", + "blur", + "dots", + "edit", + "editing", + "editor", + "effect", + "enhance", + "fade", + "filter", + "gradient", + "graphic", + "graphic design", + "image", + "line", + "linear", + "option", + "photo", + "picture", + "setting", + "smooth", + "softening", + "tool", + "transition", + "visual" + ], + "popularity": 1909 + }, + "BLUR_OFF": { + "tags": [ + "adjust", + "blur", + "blur off", + "clarity", + "clear", + "crisp", + "deactivate", + "definition", + "detail", + "disable", + "disabled", + "display", + "dots", + "edit", + "editing", + "effect", + "enabled", + "enhance", + "filter", + "focus", + "image", + "lens", + "off", + "on", + "optics", + "photo", + "photography", + "picture", + "pixel", + "remove blur", + "remove effect", + "sharp", + "slash", + "toggle off", + "unblur", + "view", + "visual" + ], + "popularity": 1240 + }, + "BLUR_ON": { + "tags": [ + "activate", + "active", + "blur", + "blur on", + "circle", + "diffuse", + "disabled", + "dots", + "edit", + "editing", + "effect", + "enable", + "enabled", + "enhance", + "filter", + "focus", + "gaussian blur", + "graphic design", + "image effect", + "image processing", + "off", + "on", + "option", + "out of focus", + "pattern", + "photo effect", + "photography", + "round", + "setting", + "slash", + "soft", + "spherical", + "switch", + "toggle", + "tool", + "unfocused", + "visual effect" + ], + "popularity": 7509 + }, + "BOLT": { + "tags": [ + "alert", + "bolt", + "charge", + "current", + "danger", + "electric", + "electricity", + "energy", + "fast", + "flash", + "graphic", + "icon", + "instant", + "lightning", + "power", + "quick", + "shape", + "speed", + "storm", + "surge", + "symbol", + "thunderbolt", + "urgent", + "warning", + "weather", + "zap" + ], + "popularity": 52630 + }, + "BOOK": { + "tags": [ + "academic", + "academy", + "book", + "book icon", + "bookmark", + "class", + "class icon", + "course", + "education", + "education icon", + "favorite", + "knowledge", + "knowledge icon", + "label", + "learning", + "learning icon", + "library", + "literature", + "literature icon", + "novel", + "open book", + "open book icon", + "read", + "reading", + "reading icon", + "reading material", + "remember", + "ribbon", + "save", + "school", + "school icon", + "study", + "tag", + "textbook", + "university", + "university icon" + ], + "popularity": 31593 + }, + "BOOK_ONLINE": { + "tags": [ + "access", + "admission", + "android", + "app", + "appointment", + "barcode", + "book", + "booking", + "cell", + "device", + "digital", + "download", + "entry", + "event", + "hardware", + "ios", + "mobile", + "movie", + "online", + "order", + "os", + "pass", + "payment", + "phone", + "purchase", + "qr code", + "receipt", + "reservation", + "scan", + "scan code", + "show", + "smartphone", + "tablet", + "ticket", + "transport", + "travel", + "validation", + "verification" + ], + "popularity": 16337 + }, + "BOOKMARK": { + "tags": [ + "app", + "archive", + "article", + "book", + "bookmark", + "browser", + "collection", + "content", + "corner", + "document", + "favorite", + "file", + "fold", + "guide", + "keep", + "label", + "library", + "mark", + "mobile", + "organize", + "page", + "pin", + "read", + "reading", + "remember", + "ribbon", + "save", + "site", + "tag", + "tutorial", + "web page" + ], + "popularity": 50597 + }, + "BOOKMARK_ADD": { + "tags": [ + "+", + "add", + "archive", + "bookmark", + "button", + "collection", + "document", + "favorite", + "file", + "folder", + "icon", + "interface", + "internet", + "mark", + "memo", + "note", + "organize", + "page", + "plus", + "reading list", + "remember", + "ribbon", + "save", + "sign", + "star", + "symbol", + "ui", + "ux", + "website" + ], + "popularity": 12399 + }, + "BOOKMARK_ADDED": { + "tags": [ + "add", + "added", + "approve", + "bookmark", + "check", + "complete", + "document", + "done", + "favorite", + "file", + "location", + "mark", + "marker", + "marker_add", + "marker_plus", + "navigation", + "ok", + "placeholder", + "placeholder_add", + "placeholder_plus", + "plus", + "reading", + "reading_list", + "remember", + "reminder", + "save", + "saved_item", + "saved_location", + "saved_page", + "select", + "shape", + "tab", + "tagging", + "tagging_add", + "tagging_plus", + "tick", + "triangle", + "validate", + "verified", + "web", + "yes" + ], + "popularity": 10003 + }, + "BOOKMARK_BORDER": { + "tags": [ + "app", + "archive", + "article", + "book", + "bookmark", + "border", + "browser", + "collection", + "content", + "corner", + "document", + "favorite", + "file", + "fold", + "guide", + "keep", + "label", + "library", + "mark", + "mobile", + "organize", + "page", + "pin", + "read", + "reading", + "remember", + "ribbon", + "save", + "site", + "tag", + "tutorial", + "web page" + ], + "popularity": 47698 + }, + "BOOKMARK_REMOVE": { + "tags": [ + "action", + "bookmark", + "button", + "clear", + "control", + "delete", + "document", + "erase", + "favorite", + "interface", + "internet", + "label", + "mark", + "minus", + "navigation", + "outline", + "page", + "remember", + "remove", + "ribbon", + "save", + "subtract", + "symbol", + "tag", + "ui", + "unfavorite", + "unmark", + "unsave", + "ux", + "web" + ], + "popularity": 4702 + }, + "BOOKMARKS": { + "tags": [ + "bookmark", + "bookmarks", + "browser", + "collection", + "document", + "favorite", + "favorites", + "file", + "flag", + "highlighted", + "important", + "label", + "layers", + "library", + "list", + "management", + "marker", + "multiple", + "navigation", + "organize", + "paper", + "read", + "reading", + "remember", + "ribbon", + "save", + "saved", + "shape", + "stack", + "tag", + "triangular", + "web" + ], + "popularity": 19492 + }, + "BORDER_ALL": { + "tags": [ + "all", + "area", + "arrange", + "border", + "boundary", + "box", + "cells", + "complete", + "container", + "content", + "data", + "display", + "divide", + "doc", + "edit", + "editing", + "editor", + "element", + "entire", + "full", + "grid", + "layout", + "lines", + "matrix", + "multiple", + "organize", + "outline", + "rectangles", + "section", + "separate", + "sheet", + "spreadsheet", + "squares", + "stroke", + "structure", + "table", + "text", + "type", + "view", + "writing" + ], + "popularity": 2935 + }, + "BORDER_BOTTOM": { + "tags": [ + "add border", + "apply border", + "border", + "border bottom", + "border style", + "bottom", + "bottom edge", + "bottom line", + "cell border", + "dash", + "dashed", + "delete border", + "divider", + "doc", + "edit", + "editing", + "editor", + "element border", + "formatting", + "horizontal line", + "layout", + "line below", + "page border", + "remove border", + "row border", + "separator", + "sheet", + "spreadsheet", + "stroke", + "style", + "table border", + "table formatting", + "text", + "text border", + "text decoration", + "text formatting", + "type", + "underline", + "writing" + ], + "popularity": 946 + }, + "BORDER_CLEAR": { + "tags": [ + "border", + "border clear", + "border none", + "borderless", + "box", + "cancel", + "clear", + "clear border", + "dash", + "dashed", + "delete", + "design", + "doc", + "edit", + "editing", + "editor", + "element", + "erase", + "formatting", + "frame", + "geometry", + "layout", + "line", + "no border", + "object", + "outline", + "rectangle", + "remove", + "remove border", + "remove frame", + "remove line", + "remove outline", + "shape", + "sheet", + "spreadsheet", + "square", + "stroke", + "style", + "text", + "type", + "writing" + ], + "popularity": 1761 + }, + "BORDER_COLOR": { + "tags": [ + "adjust", + "all", + "art", + "border", + "border color", + "change", + "color", + "colour", + "customize", + "design", + "diagonal", + "doc", + "draw", + "edit", + "editing", + "editor", + "format", + "graphic", + "line", + "modify", + "outline", + "pen", + "pencil", + "pointed", + "rectangle", + "shape", + "sheet", + "sketch", + "spreadsheet", + "square", + "stroke", + "style", + "text", + "tool", + "type", + "write", + "writing" + ], + "popularity": 21789 + }, + "BORDER_HORIZONTAL": { + "tags": [ + "border", + "boundary", + "content break", + "dash", + "dashed", + "delineation", + "design element", + "divide", + "divider", + "division", + "doc", + "document break", + "edit", + "editing", + "editor", + "element", + "formatting", + "graphic element", + "horizontal", + "horizontal border", + "horizontal line", + "hr", + "layout", + "layout control", + "line", + "line break", + "outline", + "rule", + "rule line", + "section break", + "segment", + "separator", + "sheet", + "spreadsheet", + "stroke", + "text", + "text formatting", + "type", + "ui element", + "visual separation", + "writing" + ], + "popularity": 886 + }, + "BORDER_INNER": { + "tags": [ + "alignment", + "area", + "border", + "border inner", + "boundary", + "box", + "cells", + "columns", + "content", + "dash", + "dashed", + "define", + "divisions", + "doc", + "edit", + "editing", + "editor", + "frame", + "grid", + "inner", + "inside", + "layout", + "lines", + "organize", + "rectangular", + "rows", + "section", + "separate", + "sheet", + "spreadsheet", + "square", + "stroke", + "structure", + "table", + "text", + "type", + "writing" + ], + "popularity": 1021 + }, + "BORDER_LEFT": { + "tags": [ + "align left", + "alignment", + "border", + "border left", + "boundary", + "column", + "dash", + "dashed", + "doc", + "document", + "edge", + "edit", + "editing", + "editor", + "formatting", + "grid", + "guide", + "indentation", + "layout", + "left", + "line", + "margin", + "paragraph", + "publishing", + "rule", + "sheet", + "side", + "sidebar", + "spreadsheet", + "stroke", + "structure", + "text", + "text align", + "type", + "web design", + "writing" + ], + "popularity": 960 + }, + "BORDER_OUTER": { + "tags": [ + "area", + "border", + "border outer", + "boundaries", + "box", + "cell", + "container", + "content", + "dash", + "dashed", + "design", + "doc", + "document", + "edge", + "edit", + "editing", + "editor", + "element", + "focus", + "format", + "frame", + "graphic", + "grid", + "layout", + "lines", + "outer", + "outline", + "page", + "perimeter", + "rectangle", + "selection", + "shape", + "sheet", + "spreadsheet", + "square", + "stroke", + "structure", + "style", + "table", + "text", + "type", + "writing" + ], + "popularity": 1491 + }, + "BORDER_RIGHT": { + "tags": [ + "alignment", + "border", + "border right", + "boundary", + "box", + "dash", + "dashed", + "design", + "doc", + "document", + "edge", + "edit", + "editing", + "editor", + "element", + "format", + "frame", + "geometry", + "grid", + "layout", + "line", + "margin", + "outline", + "paragraph", + "right", + "right border", + "right edge", + "shape", + "sheet", + "spreadsheet", + "square", + "stroke", + "styling", + "table", + "text", + "thin line", + "type", + "visual", + "writing" + ], + "popularity": 835 + }, + "BORDER_STYLE": { + "tags": [ + "appearance", + "border", + "boundary", + "box", + "cell", + "color", + "container", + "dash", + "dashed", + "design", + "doc", + "document", + "dotted", + "edge", + "edit", + "editing", + "editor", + "element", + "formatting", + "frame", + "graphic", + "graphic design", + "layout", + "line", + "outline", + "paragraph", + "shape", + "sheet", + "solid", + "spreadsheet", + "stroke", + "style", + "table", + "text", + "thickness", + "type", + "ui element", + "web design", + "weight", + "writing" + ], + "popularity": 1612 + }, + "BORDER_TOP": { + "tags": [ + "above", + "border", + "border top", + "boundary", + "cell", + "component", + "dash", + "dashed", + "divider", + "division", + "doc", + "edge", + "edit", + "editing", + "editor", + "element", + "formatting", + "frame", + "grid", + "horizontal line", + "layout", + "line", + "line segment", + "outline", + "paragraph", + "rule", + "rule line", + "section", + "segment", + "separator", + "sheet", + "spreadsheet", + "stroke", + "table", + "text", + "text editor", + "thick line", + "top", + "top line", + "type", + "visual aid", + "writing" + ], + "popularity": 859 + }, + "BORDER_VERTICAL": { + "tags": [ + "alignment", + "border", + "boundaries", + "column", + "column break", + "columns", + "dash", + "dashed", + "divide", + "divide vertically", + "doc", + "edges", + "edit", + "editing", + "editor", + "formatting", + "frame", + "grid", + "layout", + "lines", + "organize", + "outline", + "pane", + "panel", + "parallel lines", + "rule", + "section", + "separation", + "separator", + "sheet", + "split", + "split vertically", + "spreadsheet", + "stroke", + "structure", + "text", + "two lines", + "type", + "vertical", + "vertical border", + "vertical lines", + "writing" + ], + "popularity": 906 + }, + "BOY": { + "tags": [ + "account", + "avatar", + "body", + "boy", + "bust", + "character", + "child", + "gender", + "head", + "human", + "male", + "man", + "minimal", + "outline", + "people", + "person", + "profile", + "profile picture", + "shoulders", + "silhouette", + "simple", + "social", + "symbol", + "user", + "young person" + ], + "popularity": 3701 + }, + "BRANDING_WATERMARK": { + "tags": [ + "abstract", + "asset", + "branding", + "branding watermark", + "company", + "components", + "copyright", + "corner", + "design", + "diagonal", + "element", + "emblem", + "format", + "graphic", + "identity", + "image", + "imprint", + "interface", + "layout", + "line", + "logo", + "mark", + "outline", + "overlay", + "picture", + "rectangle", + "screen", + "shape", + "sign", + "simple", + "site", + "square", + "stamp", + "symbol", + "trademark", + "transparency", + "ui", + "ux", + "vector", + "watermark", + "web", + "website", + "window" + ], + "popularity": 7091 + }, + "BREAKFAST_DINING": { + "tags": [ + "bakery", + "bread", + "breakfast", + "brunch", + "butter", + "catering", + "circle", + "cooking", + "cuisine", + "culinary", + "delicious", + "diner", + "dining", + "dish", + "eat", + "edible", + "egg", + "food", + "fried egg", + "kitchen", + "meal", + "menu", + "morning", + "nutrition", + "order", + "plate", + "protein", + "restaurant", + "round", + "serving", + "sunny side up", + "tasty", + "toast", + "yolk" + ], + "popularity": 3289 + }, + "BRIGHTNESS_1": { + "tags": [ + "1", + "active", + "badge", + "basic", + "brightness", + "centralized", + "circle", + "complete", + "control", + "crescent", + "disc", + "dot", + "element", + "filled", + "focused", + "full", + "indicator", + "isolated", + "level", + "lone", + "marker", + "minimal", + "moon", + "orb", + "perfect", + "point", + "round", + "screen", + "selected", + "shape", + "simple", + "single", + "solid", + "sphere", + "status", + "unified", + "whole" + ], + "popularity": 5876 + }, + "BRIGHTNESS_2": { + "tags": [ + "2", + "adjust", + "adjustment", + "brightness", + "circle", + "contrast", + "control", + "crescent", + "dark", + "dim", + "display", + "icon", + "interface", + "level", + "light", + "mode", + "moon", + "night", + "screen", + "setting", + "switch", + "symbol", + "theme", + "toggle", + "ui element", + "view", + "visibility", + "visual" + ], + "popularity": 2463 + }, + "BRIGHTNESS_3": { + "tags": [ + "3", + "adjust", + "astronomy", + "atmosphere", + "brightness", + "celestial", + "celestial body", + "circle", + "control", + "cosmos", + "crescent", + "cycle", + "darkness", + "dim", + "display", + "environment", + "indicator", + "level", + "low light", + "mode", + "moon", + "night", + "phases", + "satellite", + "screen", + "setting", + "sleep", + "space", + "symbol", + "third", + "three" + ], + "popularity": 2745 + }, + "BRIGHTNESS_4": { + "tags": [ + "4", + "adjustment", + "bar", + "brightness", + "circle", + "contrast", + "control", + "crescent", + "dark mode", + "display", + "exposure", + "glare", + "illumination", + "image", + "intensity", + "level", + "light", + "luminance", + "moon", + "nature", + "night", + "option", + "photo", + "screen", + "setting", + "slider", + "sun", + "visibility", + "weather" + ], + "popularity": 6370 + }, + "BRIGHTNESS_5": { + "tags": [ + "5", + "adjust", + "brightness", + "button", + "circle", + "control", + "crescent", + "display", + "glow", + "hot", + "icon", + "illumination", + "intensity", + "level", + "light", + "moon", + "option", + "radial", + "radiation", + "rays", + "screen", + "setting", + "solar", + "star", + "summer", + "sun", + "ui", + "weather" + ], + "popularity": 5656 + }, + "BRIGHTNESS_6": { + "tags": [ + "6", + "adjust", + "brightness", + "circle", + "contrast", + "control", + "crescent", + "dark", + "day", + "decrease", + "dim", + "display", + "environment", + "exposure", + "glow", + "increase", + "level", + "light", + "luminance", + "monitor", + "moon", + "points", + "radial", + "ray", + "scale", + "screen", + "setting", + "slider", + "spokes", + "star", + "sun", + "sunny", + "weather" + ], + "popularity": 5705 + }, + "BRIGHTNESS_7": { + "tags": [ + "7", + "adjust", + "appearance", + "bright", + "bright light", + "brightness", + "circle", + "clear", + "clear day", + "control", + "crescent", + "day", + "daytime", + "display", + "full", + "full sun", + "glow", + "high", + "illumination", + "increase", + "intensity", + "level", + "light", + "maximum", + "monitor", + "moon", + "screen", + "setting", + "shiny", + "star", + "sun", + "sunny", + "up", + "visual" + ], + "popularity": 4171 + }, + "BRIGHTNESS_AUTO": { + "tags": [ + "a", + "adjust", + "adjustment", + "ambient light", + "auto", + "auto adjust", + "automatic", + "automatic brightness", + "brightness", + "brightness auto", + "control", + "display", + "display settings", + "environment", + "icon", + "interface", + "level", + "light", + "light control", + "media", + "mobile", + "monitor", + "phone", + "screen", + "screen brightness", + "sensing", + "sensor", + "setting", + "settings", + "sparkle", + "star", + "sun", + "symbol", + "ui control" + ], + "popularity": 2029 + }, + "BRIGHTNESS_HIGH": { + "tags": [ + "adjust", + "adjustment", + "auto", + "beam", + "brightness", + "circle", + "control", + "display", + "glow", + "high", + "illumination", + "image", + "intensity", + "level", + "light", + "lines", + "luminous", + "maximum", + "media", + "mobile", + "monitor", + "multimedia", + "phone", + "picture", + "radiant", + "rays", + "screen", + "setting", + "settings", + "solar", + "sun", + "vibrant", + "video", + "visibility" + ], + "popularity": 3611 + }, + "BRIGHTNESS_LOW": { + "tags": [ + "adjust", + "auto", + "battery", + "brightness", + "brightness low", + "circle", + "control", + "dark", + "decrease", + "dim", + "display", + "energy", + "gear", + "indicator", + "less", + "level", + "light", + "lines", + "low", + "minus", + "mobile", + "monitor", + "phone", + "power", + "rays", + "saver", + "screen", + "setting", + "slider", + "spokes", + "star", + "sun", + "value" + ], + "popularity": 3240 + }, + "BRIGHTNESS_MEDIUM": { + "tags": [ + "adjustment", + "auto", + "brightness", + "circle", + "configuration", + "control", + "dial", + "display", + "glow", + "illumination", + "interface", + "level", + "light", + "medium", + "mobile", + "monitor", + "options", + "phone", + "radial", + "rays", + "screen", + "setting", + "sun", + "visibility", + "visual" + ], + "popularity": 3256 + }, + "BROADCAST_ON_HOME": { + "tags": [ + "airplay", + "audio", + "broadcast", + "cast", + "communication", + "connect", + "connectivity", + "content", + "device", + "home", + "house", + "media", + "network", + "remote", + "send", + "share", + "signal", + "smart device", + "smart home", + "sound", + "speaker", + "streaming", + "technology", + "transmission", + "transmit", + "wave", + "wireless", + "wireless communication" + ], + "popularity": 768 + }, + "BROADCAST_ON_PERSONAL": { + "tags": [ + "account", + "antenna", + "avatar", + "broadcast", + "communication", + "connection", + "digital", + "feed", + "internet", + "live", + "me", + "network", + "online", + "person", + "personal", + "profile", + "publish", + "radiating", + "sharing", + "signal", + "social", + "stream", + "transmit", + "update", + "user", + "wave" + ], + "popularity": 931 + }, + "BROKEN_IMAGE": { + "tags": [ + "alert", + "broken", + "content", + "corrupt", + "damaged", + "data", + "default", + "display error", + "error", + "failed", + "file", + "graphic", + "image", + "issue", + "landscape", + "loading error", + "media", + "missing", + "mountain", + "mountains", + "network issue", + "no image", + "not found", + "photo", + "photography", + "picture", + "placeholder", + "problem", + "resource", + "server error", + "thumbnail", + "torn", + "unavailable", + "visual", + "warning" + ], + "popularity": 7088 + }, + "BROWSE_GALLERY": { + "tags": [ + "album", + "artwork", + "assets", + "browse", + "browse gallery", + "catalog", + "clock", + "collection", + "explore", + "files", + "gallery", + "graphics", + "grid", + "illustrations", + "image library", + "images", + "library", + "media", + "multimedia", + "photo album", + "photo library", + "photography", + "pictures", + "stack", + "storage", + "thumbnails", + "view", + "visual assets", + "visual content", + "watch" + ], + "popularity": 1807 + }, + "BROWSER_NOT_SUPPORTED": { + "tags": [ + "alert", + "asset", + "blocked", + "browser", + "computer", + "connection", + "desktop", + "diagonal", + "disabled", + "enabled", + "error", + "failure", + "forbidden", + "icon", + "internet", + "line", + "network", + "no", + "not", + "not supported", + "off", + "on", + "page", + "problem", + "screen", + "site", + "slash", + "status", + "supported", + "symbol", + "technology", + "unavailable", + "warning", + "web", + "website", + "window", + "www", + "x" + ], + "popularity": 1495 + }, + "BROWSER_UPDATED": { + "tags": [ + "android", + "application", + "arrow", + "browser", + "checkmark", + "chrome", + "complete", + "computer", + "confirmation", + "desktop", + "device", + "display", + "done", + "download", + "finished", + "green tick", + "hardware", + "install", + "installed", + "internet", + "ios", + "mac", + "monitor", + "navigation", + "new version", + "os", + "page", + "program", + "progress", + "refresh", + "screen", + "software", + "status", + "success", + "tab", + "tick", + "update", + "updated", + "verification", + "web", + "web browser", + "website", + "window" + ], + "popularity": 3383 + }, + "BRUNCH_DINING": { + "tags": [ + "bistro", + "breakfast", + "brunch", + "cafe", + "champagne", + "cuisine", + "cutlery", + "dining", + "dining room", + "diningware", + "drink", + "eat", + "eatery", + "eating", + "food", + "fork", + "knife", + "lunch", + "meal", + "mealtime", + "nourish", + "repast", + "reservation", + "restaurant", + "setting", + "silverware", + "spoon", + "table", + "utensils" + ], + "popularity": 2941 + }, + "BRUSH": { + "tags": [ + "art", + "artist", + "artistic", + "bristle", + "brush", + "color", + "creative", + "design", + "designer", + "draw", + "drawing", + "drawing tool", + "edit", + "editing", + "editor", + "fill", + "graphics", + "handle", + "illustration", + "instrument", + "line", + "object", + "paint", + "painter", + "painting", + "painting tool", + "shape", + "stroke", + "style", + "tip", + "tool", + "tools" + ], + "popularity": 21333 + }, + "BUBBLE_CHART": { + "tags": [ + "analysis", + "analytics", + "bar", + "bars", + "bubble", + "bubble chart", + "business intelligence", + "chart", + "circles", + "comparison", + "dashboard", + "data", + "diagram", + "dots", + "education", + "finance", + "graph", + "infographic", + "information", + "measure", + "measurements", + "metrics", + "points", + "presentation", + "progress", + "reporting", + "research", + "results", + "scale", + "scatter plot", + "science", + "statistics", + "summary", + "tracking", + "trends", + "visualization" + ], + "popularity": 8169 + }, + "BUG_REPORT": { + "tags": [ + "alert", + "animal", + "application", + "bug", + "case", + "circle", + "communicate", + "complaint", + "creature", + "debugging", + "document", + "error", + "feedback", + "file", + "fix", + "help", + "insect", + "issue", + "message", + "note", + "notify", + "paper", + "problem", + "report", + "software", + "submit", + "support", + "system", + "testing", + "ticket", + "troubleshooting", + "virus", + "warning" + ], + "popularity": 31610 + }, + "BUILD": { + "tags": [ + "adjust", + "adjustment", + "build", + "building", + "configuration", + "construction", + "control", + "engineering", + "equipment", + "fix", + "fixing", + "gear", + "general", + "hardware", + "home", + "industrial", + "instrument", + "machinery", + "maintenance", + "mechanical", + "nest", + "options", + "repair", + "service", + "settings", + "spanner", + "tool", + "toolkit", + "tools", + "utility", + "work", + "wrench" + ], + "popularity": 73576 + }, + "BUILD_CIRCLE": { + "tags": [ + "adjust", + "build", + "circle", + "cog", + "configuration", + "construct", + "contained", + "create", + "development", + "engineer", + "fix", + "gear", + "machinery", + "maintenance", + "mechanical", + "options", + "outlined", + "preferences", + "repair", + "round", + "settings", + "setup", + "spanner", + "technical", + "tool", + "wrench" + ], + "popularity": 18733 + }, + "BUNGALOW": { + "tags": [ + "accommodation", + "architecture", + "building", + "bungalow", + "buy", + "chimney", + "construction", + "cottage", + "dwelling", + "estate", + "home", + "home icon", + "house", + "house icon", + "housing", + "lodging", + "maps", + "place", + "property", + "property listing", + "real", + "real estate", + "rent", + "residence", + "residential", + "roof", + "shelter", + "simple house", + "small house", + "stay", + "structure", + "traveling", + "windows" + ], + "popularity": 2192 + }, + "BURST_MODE": { + "tags": [ + "action", + "burst", + "burst mode", + "camera", + "capture", + "continuous", + "fast", + "frames", + "image", + "landscape", + "many", + "mode", + "mountain", + "mountains", + "multiple", + "photo", + "photography", + "picture", + "quick", + "rapid", + "repeat", + "repeating", + "sequence", + "series", + "shoot", + "shooting", + "shutter", + "snapping", + "speed", + "stream", + "taking" + ], + "popularity": 2097 + }, + "BUS_ALERT": { + "tags": [ + "!", + "alarm", + "alert", + "attention", + "automobile", + "breakdown", + "bus", + "car", + "cars", + "caution", + "commuter", + "danger", + "error", + "exclamation", + "exclamation mark", + "important", + "information", + "issue", + "journey", + "maps", + "mark", + "message", + "mobility", + "notification", + "passenger", + "problem", + "public transport", + "road", + "route", + "signal", + "stop", + "symbol", + "transit", + "transportation", + "travel", + "triangle", + "update", + "vehicle", + "warning" + ], + "popularity": 2620 + }, + "BUSINESS": { + "tags": [ + "address", + "apartment", + "architecture", + "building", + "business", + "circle", + "communication", + "company", + "concept", + "connection", + "domain", + "estate", + "global", + "globe", + "home", + "icon", + "internet", + "link", + "navigation", + "network", + "online", + "place", + "real", + "representation", + "residence", + "residential", + "round", + "shelter", + "sphere", + "symbol", + "technology", + "ui", + "url", + "web address", + "website", + "world" + ], + "popularity": 78248 + }, + "BUSINESS_CENTER": { + "tags": [ + "accessory", + "assets", + "bag", + "baggage", + "belongings", + "box", + "briefcase", + "business", + "career", + "carrying", + "case", + "center", + "commerce", + "container", + "corporate", + "goods", + "handle", + "holding", + "item", + "job", + "luggage", + "object", + "office", + "personal", + "places", + "portfolio", + "professional", + "purse", + "rectangle", + "storage", + "strap", + "suitcase", + "travel", + "work" + ], + "popularity": 25365 + }, + "CABIN": { + "tags": [ + "accommodation", + "architecture", + "basic", + "building", + "cabin", + "camping", + "cottage", + "country", + "door", + "dwelling", + "escape", + "estate", + "getaway", + "home", + "house", + "lodging", + "log", + "log cabin", + "maps", + "nature", + "outdoors", + "place", + "property", + "real", + "real estate", + "rectangle", + "residence", + "residential", + "roof", + "rural", + "shelter", + "simple", + "square", + "stay", + "structure", + "travel", + "traveling", + "triangle", + "vacation", + "walls", + "windows", + "wood" + ], + "popularity": 3568 + }, + "CABLE": { + "tags": [ + "analog", + "cable", + "communication", + "component", + "connect", + "connection", + "connector", + "cord", + "data", + "device", + "digital", + "electrical", + "electricity", + "electronic", + "electronics", + "hardware", + "input", + "line", + "link", + "network", + "network cable", + "optic", + "output", + "plug", + "port", + "power", + "signal", + "socket", + "technology", + "transfer", + "transmit", + "usb", + "wire" + ], + "popularity": 8808 + }, + "CACHED": { + "tags": [ + "access", + "around", + "arrows", + "cache", + "cached", + "circle", + "cloud", + "connection", + "data", + "database", + "directory", + "download", + "files", + "folder", + "information", + "inprogress", + "load", + "loading refresh", + "loop", + "memory", + "network", + "offline", + "processing", + "refresh", + "reload", + "renew", + "retrieve", + "rotate", + "save", + "server", + "storage", + "store", + "sync", + "synchronize", + "system", + "two arrows", + "update" + ], + "popularity": 32188 + }, + "CAKE": { + "tags": [ + "add", + "anniversary", + "baked", + "baked goods", + "bakery", + "birthday", + "cake", + "candle", + "candles", + "celebration", + "confection", + "delicious", + "dessert", + "edible", + "event", + "festive", + "food", + "frosting", + "happy birthday", + "holiday", + "new", + "occasion", + "party", + "pastries", + "pastry", + "patisserie", + "plus", + "slice", + "snack", + "social", + "special occasion", + "sugar", + "sweet", + "symbol", + "treat" + ], + "popularity": 24507 + }, + "CALCULATE": { + "tags": [ + "+", + "-", + "=", + "addition", + "arithmetic", + "calculate", + "calculator", + "count", + "counting", + "digits", + "division", + "equals", + "equation", + "filled", + "finance calculator", + "geometry", + "keypad", + "line", + "math", + "math operations", + "multiplication", + "number pad", + "numbers", + "numpad", + "object", + "result", + "shape", + "solid", + "subtraction", + "sum", + "symbol", + "technology", + "tool", + "total" + ], + "popularity": 41318 + }, + "CALENDAR_MONTH": { + "tags": [ + "agenda", + "appointment", + "button", + "calendar", + "clock", + "date", + "day", + "duration", + "element", + "event", + "icon", + "interface", + "lines", + "month", + "navigation", + "organise", + "period", + "plan", + "record", + "rectangle", + "schedule", + "square", + "symbol", + "time", + "today", + "widget" + ], + "popularity": 79928 + }, + "CALENDAR_TODAY": { + "tags": [ + "agenda", + "appointment", + "booking", + "calendar", + "calendaricon", + "calendartoday", + "daily", + "date", + "dating", + "day", + "diary", + "event", + "grid", + "lines", + "month", + "monthly", + "organizer", + "plan", + "planning", + "punctual", + "rectangle", + "reminder", + "schedule", + "square", + "time", + "today", + "todaycalendar", + "week", + "year", + "yearly" + ], + "popularity": 128640 + }, + "CALENDAR_VIEW_DAY": { + "tags": [ + "activity", + "agenda", + "appointment", + "appointments", + "calendar", + "column", + "date", + "day", + "day view", + "detailed", + "event", + "events", + "format", + "grid", + "layout", + "linear", + "list", + "list view", + "long", + "month", + "organize", + "plan", + "rectangle", + "schedule", + "scheduler", + "shape", + "single", + "time", + "timeline", + "today", + "vertical", + "view", + "week" + ], + "popularity": 6364 + }, + "CALENDAR_VIEW_MONTH": { + "tags": [ + "agenda", + "appointments", + "arrangement", + "block", + "booking", + "box", + "calendar", + "date", + "day", + "event", + "events", + "format", + "grid", + "horizontal", + "layout", + "lines", + "matrix", + "month", + "organizer", + "outline", + "planning", + "rectangle", + "reminder", + "schedule", + "structure", + "time", + "today", + "vertical", + "view", + "weekly", + "yearly" + ], + "popularity": 12761 + }, + "CALENDAR_VIEW_WEEK": { + "tags": [ + "appointments", + "arrangement", + "calendar", + "columns", + "date", + "dates", + "day", + "days", + "display", + "event", + "events", + "format", + "grid", + "layout", + "management", + "month", + "organizer", + "overview", + "planner", + "planning", + "rectangle", + "schedule", + "seven days", + "structure", + "time", + "timeline", + "today", + "vertical", + "view", + "week", + "weekly" + ], + "popularity": 7471 + }, + "CALL": { + "tags": [ + "audio", + "business", + "call", + "cell", + "communication", + "connect", + "connection", + "contact", + "contact us", + "customer service", + "device", + "dial", + "directory", + "emergency", + "handset", + "hardware", + "help", + "incoming", + "local phone", + "mobile", + "office", + "outgoing", + "phone", + "phone alt", + "receiver", + "ring", + "speak", + "support", + "talk", + "telecommunication", + "telephone", + "voice" + ], + "popularity": 192034 + }, + "CALL_END": { + "tags": [ + "audio", + "button", + "call", + "cancel", + "cell", + "close", + "communication", + "contact", + "control", + "decline", + "device", + "disconnect", + "end", + "hang up", + "hardware", + "incoming", + "interaction", + "mobile", + "outgoing", + "phone", + "pictogram", + "reject", + "ringing", + "shape", + "stop", + "symbol", + "telephone", + "terminate", + "voice" + ], + "popularity": 11883 + }, + "CALL_MADE": { + "tags": [ + "action", + "activity", + "angular", + "arrow", + "call", + "call made", + "communication", + "connectivity", + "control", + "device", + "diagonal arrow", + "direction", + "external link", + "icon", + "indicator", + "interface", + "line", + "line arrow", + "link", + "made", + "mobile", + "navigate", + "outbound", + "outgoing", + "phone", + "pointer", + "right arrow", + "share", + "symbol", + "telephone", + "top right arrow" + ], + "popularity": 7947 + }, + "CALL_MERGE": { + "tags": [ + "arrow", + "arrows", + "branches", + "call", + "collapse", + "combine", + "connect", + "connect points", + "connecting points", + "consolidate", + "consolidate lines", + "converge", + "converging lines", + "data", + "device", + "diagram", + "direction", + "dots", + "flowchart", + "graph", + "integrate", + "join", + "lines", + "link", + "merge", + "mobile", + "network", + "node", + "points", + "structure", + "union", + "unity" + ], + "popularity": 3036 + }, + "CALL_MISSED": { + "tags": [ + "alert", + "angle", + "angle down", + "arrow", + "call", + "call status", + "communication", + "contact", + "declined call", + "device", + "diagonal down", + "diagonal line", + "dialing", + "direction", + "down", + "dropped call", + "hang up", + "history", + "line", + "log", + "missed", + "missed call", + "mobile", + "notification", + "phone", + "phone symbol", + "recent calls", + "smartphone", + "technology", + "telephone", + "telephony" + ], + "popularity": 2206 + }, + "CALL_MISSED_OUTGOING": { + "tags": [ + "arrow", + "attempted", + "call", + "cellular", + "communication", + "connection", + "contact", + "device", + "diagonal", + "dial", + "direction", + "failed", + "history", + "icon", + "incomplete", + "indicator", + "line", + "log", + "missed", + "mobile", + "network", + "number", + "outgoing", + "phone", + "point", + "right", + "signal", + "symbol", + "telephone", + "unfinished", + "up" + ], + "popularity": 2499 + }, + "CALL_RECEIVED": { + "tags": [ + "accept", + "alert", + "answering", + "arrival", + "arrow", + "audio", + "bottom", + "call", + "call received", + "communication", + "connectivity", + "curve", + "device", + "direction", + "download", + "history", + "inbound call", + "incoming", + "incoming call", + "left", + "line", + "log", + "message", + "mobile", + "notification", + "phone", + "point", + "received", + "recent calls", + "signal", + "telephone", + "voice" + ], + "popularity": 4939 + }, + "CALL_SPLIT": { + "tags": [ + "action", + "arrow", + "arrows", + "branch", + "call", + "call split", + "communication", + "connect", + "connection", + "control", + "device", + "direction", + "disconnect", + "distribute", + "diverge", + "divide", + "fork", + "lines", + "menu", + "mobile", + "more", + "multiply", + "navigation", + "network", + "options", + "path", + "phone", + "redirect", + "routing", + "separate", + "share", + "split", + "spread", + "telephone", + "transfer" + ], + "popularity": 7237 + }, + "CALL_TO_ACTION": { + "tags": [ + "action", + "active", + "alert", + "arrow", + "bar", + "button", + "call", + "call to action", + "choose", + "clicking", + "components", + "cta", + "cursor", + "cursor hand", + "design", + "desktop", + "fingertip", + "gesture", + "hand", + "highlight", + "icon", + "info", + "information", + "interacting", + "interaction", + "interface", + "layout", + "link", + "message", + "mobile", + "navigation", + "notification", + "pointer", + "pointing", + "press", + "screen", + "select", + "site", + "to", + "touch", + "touch screen", + "ui", + "ui element", + "ux", + "web", + "website", + "window" + ], + "popularity": 3530 + }, + "CAMERA": { + "tags": [ + "aperture", + "button", + "camera", + "capture", + "capture device", + "device", + "digital", + "electronic", + "film", + "glyph", + "graphic", + "icon", + "image", + "instant", + "lens", + "media", + "optic", + "photo", + "photography", + "picture", + "record", + "recording", + "shoot", + "shutter", + "snapshot", + "symbol", + "tool", + "ui element", + "video", + "viewfinder", + "visual" + ], + "popularity": 14012 + }, + "CAMERA_ALT": { + "tags": [ + "alt", + "analog", + "button", + "camera", + "capture", + "circle", + "device", + "digital", + "film", + "icon", + "image", + "input", + "lens", + "media", + "movie", + "multimedia", + "multimedia input", + "photo", + "photograph", + "photography", + "picture", + "record", + "shoot", + "shutter", + "square", + "symbol", + "technology", + "video", + "videography", + "visual" + ], + "popularity": 14118 + }, + "CAMERA_ENHANCE": { + "tags": [ + "adjustment", + "ai", + "aperture", + "artificial", + "automatic", + "automation", + "bright", + "button", + "camera", + "capture", + "control", + "custom", + "edit", + "effect", + "enhance", + "filter", + "flash", + "genai", + "glow", + "icon", + "image", + "important", + "intelligence", + "lens", + "magic", + "option", + "photo", + "photography", + "picture", + "quality", + "setting", + "shine", + "shot", + "smart", + "spark", + "sparkle", + "special", + "star", + "symbol", + "tool" + ], + "popularity": 7680 + }, + "CAMERA_FRONT": { + "tags": [ + "body", + "camera", + "capture", + "circle", + "device", + "flip camera", + "front", + "front facing camera", + "human", + "image capture", + "lens", + "live video", + "mobile", + "mobile camera", + "multimedia", + "person", + "phone", + "photo", + "photography", + "picture", + "portrait", + "portrait mode", + "record", + "recording", + "rectangle", + "selfie", + "shot", + "square", + "streaming", + "switch camera", + "technology", + "video", + "video call", + "webcam" + ], + "popularity": 2215 + }, + "CAMERA_INDOOR": { + "tags": [ + "architecture", + "automation", + "building", + "camera", + "cctv", + "device", + "dome camera", + "electronic", + "estate", + "film", + "filming", + "home", + "home security", + "house", + "image", + "indoor", + "indoor camera", + "inside", + "interior camera", + "ip camera", + "live feed", + "monitoring", + "motion", + "nest", + "network camera", + "picture", + "place", + "protection", + "real", + "recording", + "residence", + "residential", + "safety", + "security", + "security camera", + "shelter", + "smart home", + "stream", + "surveillance", + "surveillance camera", + "technology", + "video", + "video feed", + "videography" + ], + "popularity": 3818 + }, + "CAMERA_OUTDOOR": { + "tags": [ + "architecture", + "building", + "business", + "camera", + "cctv", + "commercial", + "dome camera", + "estate", + "exterior", + "film", + "filming", + "footage", + "home", + "home security", + "house", + "image", + "monitor", + "monitoring", + "motion", + "nest", + "outdoor", + "outdoor camera", + "outside", + "perimeter", + "picture", + "place", + "property", + "protection", + "real", + "record", + "recording", + "residence", + "residential", + "safety", + "security", + "security camera", + "shelter", + "surveillance", + "surveillance camera", + "video", + "videography", + "view", + "watching" + ], + "popularity": 3546 + }, + "CAMERA_REAR": { + "tags": [ + "aperture", + "back camera", + "camera", + "camera mode", + "camera toggle", + "capture", + "capture image", + "circle", + "device", + "focus", + "front", + "image capture", + "lens", + "lense", + "mobile", + "optical", + "phone", + "photo", + "photography", + "picture", + "portrait", + "rear", + "rear camera", + "record", + "recording", + "selfie", + "shutter", + "square", + "switch camera", + "switch view", + "take picture", + "video", + "videography", + "vision" + ], + "popularity": 1123 + }, + "CAMERA_ROLL": { + "tags": [ + "album", + "browse photos", + "camera", + "camera roll", + "collection", + "digital photos", + "film", + "gallery", + "image", + "image collection", + "image gallery", + "images", + "library", + "media", + "memories", + "mobile", + "photo", + "photo album", + "photo collection", + "photo storage", + "photography", + "photography collection", + "photos", + "pictures", + "roll", + "saved photos", + "smartphone", + "view photos", + "visual media" + ], + "popularity": 1982 + }, + "CAMERASWITCH": { + "tags": [ + "arrow", + "arrows", + "back camera", + "camera", + "camera switch", + "camera toggle", + "cameraswitch", + "change camera", + "circle", + "circular arrows", + "communication", + "flip", + "flip camera", + "front camera", + "mobile camera", + "photo camera", + "photography", + "record", + "rotate", + "rotate camera", + "selfie camera", + "shoot", + "swap", + "switch", + "switch camera", + "two arrows", + "video call", + "video camera", + "video chat", + "videography", + "view" + ], + "popularity": 8327 + }, + "CAMPAIGN": { + "tags": [ + "achievement", + "action", + "advertisement", + "alert", + "announcement", + "banner", + "campaign", + "celebration", + "concept", + "curve", + "direction", + "emblem", + "event", + "flag", + "goal", + "line", + "loud", + "marketing", + "megaphone", + "microphone", + "milestone", + "navigation", + "notification", + "object", + "pennant", + "point", + "progress", + "promotion", + "shape", + "speaker", + "success", + "symbol", + "triangle", + "victory", + "wave", + "wind" + ], + "popularity": 57615 + }, + "CANCEL": { + "tags": [ + "abort", + "action", + "block", + "button", + "cancel", + "circle", + "clear", + "close", + "cross", + "delete", + "deny", + "deselect", + "discard", + "dismiss", + "error", + "exit", + "failure", + "forbidden", + "highlight off", + "invalid", + "negative", + "quit", + "reject", + "remove", + "revoke", + "round", + "stop", + "turn off", + "unselect", + "x" + ], + "popularity": 177565 + }, + "CANCEL_PRESENTATION": { + "tags": [ + "abort", + "cancel", + "clear", + "close", + "conference", + "cross", + "denial", + "device", + "diagonal lines", + "dismiss", + "display", + "end", + "exclude", + "exit", + "halt", + "meeting", + "monitor", + "no", + "present", + "presentation", + "projection", + "projector", + "quit", + "rectangle", + "rejection", + "remove", + "revoke", + "screen", + "slide", + "slideshow", + "stop", + "terminate", + "website", + "window", + "x", + "x mark" + ], + "popularity": 8350 + }, + "CANCEL_SCHEDULE_SEND": { + "tags": [ + "abort", + "action", + "button", + "cancel", + "clear", + "command", + "communication", + "delete", + "draft", + "email", + "envelope", + "icon", + "interface", + "letter", + "linear", + "mail", + "message", + "no", + "outline", + "pending", + "quit", + "remove", + "revoke", + "schedule", + "scheduled email", + "scheduled message", + "send", + "share", + "stop", + "symbol", + "timed message", + "unschedule", + "x" + ], + "popularity": 5468 + }, + "CANDLESTICK_CHART": { + "tags": [ + "analysis", + "analytics", + "bar graph", + "bars", + "business", + "candlestick", + "chart", + "chart bars", + "data", + "data visualization", + "diagram", + "economic analysis", + "economics", + "economy", + "finance", + "financial", + "graph", + "growth", + "infographic", + "investment", + "investment chart", + "line chart", + "market", + "measure", + "metrics", + "report", + "statistics", + "stock analysis", + "stock data", + "stock market", + "tracking", + "trading", + "trading chart", + "trend" + ], + "popularity": 2575 + }, + "CAR_CRASH": { + "tags": [ + "accident", + "alert", + "auto", + "automobile", + "broken", + "car", + "cars", + "collision", + "crash", + "damage", + "damaged", + "danger", + "dangerous", + "direction", + "driving", + "emergency", + "hazard", + "impact", + "incident", + "insurance", + "maps", + "motor vehicle", + "public", + "risk", + "road", + "safety", + "traffic", + "transport", + "transportation", + "vehicle", + "warning", + "wreck" + ], + "popularity": 2531 + }, + "CAR_RENTAL": { + "tags": [ + "access", + "automobile", + "booking", + "booking service", + "car", + "car key", + "cars", + "drive", + "driving", + "drop off", + "entry", + "hire", + "journey", + "key", + "lock", + "maps", + "mobility", + "passenger", + "password", + "pick up", + "rent", + "rental", + "reservation", + "reservation details", + "road transport", + "road trip", + "service", + "transport", + "transport service", + "transportation", + "travel", + "travel booking", + "travel service", + "trip", + "unlock", + "vacation", + "vehicle" + ], + "popularity": 4599 + }, + "CAR_REPAIR": { + "tags": [ + "adjustments", + "assistance", + "auto", + "automobile", + "automotive", + "breakdown", + "car", + "car service", + "cars", + "configuration", + "emergency", + "fix", + "garage", + "garage tools", + "gears", + "machinery", + "maintenance", + "maps", + "mechanic", + "repair", + "repair shop", + "service", + "settings", + "spanner", + "support", + "tool", + "transportation", + "travel", + "tune-up", + "vehicle", + "vehicle maintenance", + "workshop", + "wrench" + ], + "popularity": 3848 + }, + "CARD_GIFTCARD": { + "tags": [ + "account", + "balance", + "bill", + "bonus", + "bonus points", + "bow", + "buy", + "card", + "cart", + "cash", + "celebration", + "certificate", + "coin", + "commerce", + "coupon", + "credit", + "currency", + "discount", + "dollars", + "event", + "gift", + "gift card", + "giftcard", + "giving", + "holiday", + "loyalty", + "loyalty program", + "money", + "online", + "pay", + "payment", + "present", + "prize", + "purchase", + "rectangle", + "redeem", + "reward", + "reward system", + "ribbon", + "shopping", + "special offer", + "transaction", + "voucher" + ], + "popularity": 38340 + }, + "CARD_MEMBERSHIP": { + "tags": [ + "access", + "account", + "bill", + "bookmark", + "card", + "cash", + "certificate", + "club", + "club card", + "coin", + "commerce", + "cost", + "credit", + "currency", + "document", + "dollars", + "enrollment", + "entry pass", + "finance", + "id", + "identification", + "identity", + "login", + "loyalty", + "loyalty card", + "membership", + "money", + "online", + "pass", + "pay", + "payment", + "permit", + "premium", + "profile", + "rectangle", + "registration", + "shape", + "shopping", + "sign up", + "square", + "subscription", + "user", + "vip" + ], + "popularity": 16657 + }, + "CARD_TRAVEL": { + "tags": [ + "accessory", + "bag", + "baggage", + "bill", + "briefcase", + "business", + "card", + "carry", + "case", + "cash", + "coin", + "commerce", + "cost", + "credit", + "currency", + "dollars", + "finance", + "handle", + "item", + "journey", + "luggage", + "membership", + "miles", + "money", + "online", + "packing", + "pay", + "payment", + "personal", + "rectangle", + "square", + "suitcase", + "transportation", + "travel", + "trip", + "voyage" + ], + "popularity": 6756 + }, + "CARPENTER": { + "tags": [ + "build", + "building", + "career", + "carpenter", + "construct", + "construction", + "craft", + "create", + "cutting", + "employee", + "figure", + "fix", + "handyman", + "individual", + "job", + "labor", + "manual labor", + "occupation", + "outline", + "person", + "profession", + "repair", + "saw", + "silhouette", + "skill", + "tool", + "tools", + "trade", + "woodworking", + "work", + "worker" + ], + "popularity": 3233 + }, + "CASES": { + "tags": [ + "administration", + "archive", + "bag", + "baggage", + "briefcase", + "briefcases", + "bureaucracy", + "business", + "case", + "cases", + "categorized", + "collection", + "data", + "documentation", + "documents", + "file cabinet", + "files", + "filing", + "folders", + "information", + "law", + "legal", + "management", + "office", + "organization", + "organized", + "purse", + "records", + "repository", + "storage", + "structured", + "suitcase", + "system", + "work" + ], + "popularity": 6958 + }, + "CASINO": { + "tags": [ + "bet", + "betting", + "cards", + "casino", + "casino chip", + "chance", + "chip", + "chips", + "dice", + "dots", + "entertainment", + "fortune", + "fun", + "gamble", + "gambling", + "game", + "games", + "gaming", + "jackpot", + "leisure", + "luck", + "machine", + "money", + "places", + "play", + "poker", + "prize", + "recreation", + "reward", + "risk", + "roulette", + "slot", + "success", + "tokens", + "vegas", + "wager", + "win" + ], + "popularity": 9359 + }, + "CAST": { + "tags": [ + "airplay", + "android", + "audio", + "broadcast", + "cast", + "chrome", + "chromecast", + "connect", + "connection", + "content", + "desktop", + "device", + "display", + "hardware", + "ios", + "mac", + "media", + "mirror", + "monitor", + "network", + "os", + "output", + "playback", + "projector", + "push", + "receiver", + "screen", + "screencast", + "send", + "share", + "signal", + "stream", + "streaming", + "technology", + "television", + "transmit", + "tv", + "video", + "web", + "window", + "wireless" + ], + "popularity": 7595 + }, + "CAST_CONNECTED": { + "tags": [ + "airplay", + "android", + "audio", + "beaming", + "broadcast", + "cast", + "cast connected", + "chrome", + "connect", + "connected", + "connected device", + "connection", + "content", + "control", + "desktop", + "device", + "display", + "entertainment", + "hardware", + "ios", + "link", + "link established", + "mac", + "media", + "media player", + "mirroring", + "monitor", + "multimedia", + "network", + "os", + "projecting", + "remote", + "screen", + "screencast", + "share", + "signal", + "smart tv", + "streaming", + "television", + "transmit", + "tv", + "video", + "web", + "window", + "wireless" + ], + "popularity": 3549 + }, + "CAST_FOR_EDUCATION": { + "tags": [ + "airplay", + "android", + "audio", + "broadcast", + "cast", + "chrome", + "classroom", + "college", + "connect", + "connection", + "desktop", + "device", + "display", + "education", + "for", + "hardware", + "ios", + "knowledge", + "learn", + "learning", + "lecture", + "lessons teaching", + "mac", + "media", + "monitor", + "os", + "presentation", + "projection", + "school", + "screen", + "screencast", + "share", + "sharing", + "stream", + "streaming", + "student", + "teach", + "teacher", + "technology", + "television", + "tv", + "university", + "video", + "web", + "window", + "wireless" + ], + "popularity": 8446 + }, + "CASTLE": { + "tags": [ + "abode", + "ancient", + "architecture", + "battlement", + "building", + "castle", + "domain", + "dwelling", + "establishment", + "estate", + "fairytale", + "fort", + "fortress", + "historical", + "home", + "housing", + "kingdom", + "landmark", + "lodging", + "mansion", + "medieval", + "monument", + "palace", + "protected", + "residence", + "royal", + "security", + "stronghold", + "structure", + "tower", + "turrets" + ], + "popularity": 2575 + }, + "CATCHING_POKEMON": { + "tags": [ + "catching", + "go", + "pokemon", + "pokestop", + "travel" + ], + "popularity": 8428 + }, + "CATEGORY": { + "tags": [ + "categories", + "category", + "chain", + "chains", + "chart", + "charts", + "circle", + "circles", + "collection", + "concept", + "concepts", + "connection", + "connections", + "diagram", + "diagrams", + "flow", + "hierarchical", + "hierarchy", + "idea", + "ideas", + "items", + "link", + "links", + "network", + "networks", + "orb", + "orbs", + "organization", + "organize", + "product", + "relate", + "related", + "relationship", + "relationships", + "shapes", + "sort", + "square", + "structure", + "structures", + "three circles", + "tree", + "trees", + "triangle" + ], + "popularity": 58592 + }, + "CELEBRATION": { + "tags": [ + "achievement", + "activity", + "award", + "birthday", + "burst", + "celebration", + "confetti", + "congratulations", + "emblem", + "event", + "excitement", + "explode", + "festive", + "fireworks", + "fun", + "glitter", + "glyph", + "graphic", + "happy", + "joy", + "light", + "magic", + "party", + "reward", + "shape", + "sparkle", + "special", + "star", + "success", + "surprise", + "symbol", + "victory" + ], + "popularity": 21038 + }, + "CELL_TOWER": { + "tags": [ + "5g", + "antenna", + "broadcast", + "building", + "casting", + "cell", + "cell tower", + "cellular", + "communication", + "connection", + "connectivity", + "data", + "gsm", + "infrastructure", + "internet", + "lte", + "mast", + "mobile", + "network", + "radio", + "radio tower", + "signal", + "station", + "structure", + "technology", + "telecommunications", + "tower", + "transmission", + "transmission tower", + "transmitting", + "wireless" + ], + "popularity": 4572 + }, + "CELL_WIFI": { + "tags": [ + "access", + "bars", + "cell", + "cellular", + "communication", + "connection", + "connectivity", + "curves", + "data", + "device", + "indicator", + "internet", + "lines", + "mobile", + "network", + "phone", + "reception", + "service", + "signal", + "status", + "technology", + "waves", + "wifi", + "wireless" + ], + "popularity": 2419 + }, + "CENTER_FOCUS_STRONG": { + "tags": [ + "accuracy", + "adjust", + "aiming", + "alignment", + "area", + "boundaries", + "box", + "camera", + "capture", + "center", + "control", + "corners", + "crosshairs", + "define", + "editor", + "focus", + "frame", + "highlight", + "image", + "lens", + "measurement", + "photo", + "photography", + "pinpoint", + "selection", + "settings", + "square", + "strong", + "target", + "tool", + "view", + "zone", + "zoom" + ], + "popularity": 7750 + }, + "CENTER_FOCUS_WEAK": { + "tags": [ + "aim", + "alignment", + "area", + "boundaries", + "camera", + "capture", + "center", + "center focus weak", + "crosshairs", + "focus", + "frame", + "guide", + "image", + "indicator", + "lens", + "limit", + "outline", + "photo", + "photography", + "rectangle", + "region", + "selection", + "shot", + "space", + "square", + "symbol", + "target", + "video", + "viewfinder", + "weak", + "zone", + "zoom" + ], + "popularity": 4667 + }, + "CHAIR": { + "tags": [ + "balcony", + "bedroom", + "chair", + "comfort", + "couch", + "decoration", + "dining", + "furniture", + "garden", + "graphic", + "home", + "house", + "illustration", + "indoors", + "item", + "living", + "living room", + "lounge", + "lounging", + "loveseat", + "object", + "office", + "outline", + "patio", + "pictogram", + "relax", + "rest", + "room", + "seat", + "seating", + "simple", + "sofa", + "symbol" + ], + "popularity": 15789 + }, + "CHAIR_ALT": { + "tags": [ + "basic", + "cahir", + "chair", + "comfortable", + "furniture", + "graphic", + "home", + "house", + "household", + "illustration", + "indoor", + "kitchen", + "line", + "lounging", + "object", + "office", + "outline", + "pictogram", + "rectangle", + "seat", + "seating", + "simple", + "sitting", + "solid", + "symbol", + "table", + "waiting" + ], + "popularity": 3625 + }, + "CHALET": { + "tags": [ + "a-frame", + "alpine", + "architecture", + "building", + "cabin", + "chalet", + "chimney", + "cottage", + "countryside", + "door", + "dwelling", + "dwelling place", + "estate", + "holiday", + "home", + "house", + "lodge", + "lodging", + "maps", + "mountain", + "place", + "real", + "residence", + "residential", + "retreat", + "roof", + "rural", + "shelter", + "skiing", + "stay", + "structure", + "travel", + "traveling", + "triangular", + "trip", + "vacation", + "window" + ], + "popularity": 1980 + }, + "CHANGE_CIRCLE": { + "tags": [ + "alter", + "around", + "arrow", + "arrows", + "change", + "circle", + "circular", + "cycle", + "direction", + "exchange", + "flow", + "loop", + "modification", + "movement", + "navigation", + "ongoing", + "process", + "progress", + "refresh", + "reload", + "renew", + "repeat", + "replace", + "rotate", + "round", + "status", + "switch", + "transition", + "update" + ], + "popularity": 21339 + }, + "CHANGE_HISTORY": { + "tags": [ + "audit trail", + "change", + "change history", + "chronology", + "development", + "edits", + "events", + "evolution", + "flow", + "history", + "journal", + "journey", + "log", + "modifications", + "past", + "path", + "process", + "progression", + "record", + "revisions", + "sequence", + "shape", + "time", + "timeline", + "track changes", + "triangle", + "updates", + "version history" + ], + "popularity": 15536 + }, + "CHARGING_STATION": { + "tags": [ + "android", + "battery", + "bolt", + "car", + "cell", + "charge", + "charging", + "charging station", + "connector", + "device", + "electric", + "electric vehicle", + "electricity", + "energy", + "ev", + "filling", + "fueling", + "hardware", + "icon", + "instant", + "ios", + "lightning", + "location", + "map", + "mobile", + "mobile charge", + "navigation", + "os", + "phone", + "pin", + "plug", + "point of interest", + "pointer", + "power", + "road", + "station", + "symbol", + "tablet", + "thunderbolt", + "transport", + "vehicle" + ], + "popularity": 3221 + }, + "CHAT": { + "tags": [ + "alert", + "bubble", + "chat", + "comment", + "communicate", + "communication", + "connect", + "contact", + "conversation", + "dialogue", + "discussion", + "feedback", + "help", + "im", + "inbox", + "instant message", + "message", + "messaging", + "messenger", + "new", + "notification", + "receive", + "send", + "sms", + "social", + "speak", + "speech", + "support", + "talk", + "text" + ], + "popularity": 75662 + }, + "CHAT_BUBBLE": { + "tags": [ + "bubble", + "chat", + "chat outline", + "chatbox", + "comment", + "communicate", + "communication", + "communication bubble", + "contact", + "conversation", + "dialog", + "dialogue", + "discuss", + "feedback", + "forum", + "help", + "interaction", + "message", + "message outline", + "messaging", + "new message", + "notification", + "social", + "speak", + "speech", + "speech outline", + "support", + "talk", + "text", + "texting", + "thoughts" + ], + "popularity": 33786 + }, + "CHAT_BUBBLE_OUTLINE": { + "tags": [ + "bubble", + "chat", + "chat outline", + "chatbox", + "comment", + "communicate", + "communication", + "communication bubble", + "contact", + "conversation", + "dialog", + "dialogue", + "discuss", + "feedback", + "forum", + "help", + "interaction", + "message", + "message outline", + "messaging", + "new message", + "notification", + "social", + "speak", + "speech", + "speech outline", + "support", + "talk", + "text", + "texting", + "thoughts" + ], + "popularity": 42244 + }, + "CHECK": { + "tags": [ + "!", + "acceptance", + "achievement", + "alert", + "apply", + "approve", + "attention", + "caution", + "check", + "checkmark", + "complete", + "completion", + "confirm", + "confirmation", + "correct", + "danger", + "disable_ios", + "done", + "enter", + "error", + "exclamation", + "final", + "finished", + "good", + "input", + "mark", + "notification", + "ok", + "okay", + "option", + "right", + "select", + "selection", + "submit", + "success", + "task", + "tick", + "validated", + "verified", + "verify", + "yes" + ], + "popularity": 111291 + }, + "CHECK_BOX": { + "tags": [ + "activate", + "agree", + "approved", + "binary", + "box", + "button", + "check", + "check box", + "checkbox", + "checked", + "choice", + "complete", + "component", + "confirm", + "consent", + "control", + "done", + "enable", + "false", + "field", + "form", + "input", + "list", + "mark", + "marked", + "ok", + "option", + "select", + "selected", + "selection", + "square", + "task", + "tick", + "toggle", + "true", + "ui", + "yes" + ], + "popularity": 129237 + }, + "CHECK_BOX_OUTLINE_BLANK": { + "tags": [ + "blank", + "boundary", + "box", + "button", + "check", + "checkbox", + "choice", + "component", + "control", + "dash", + "dashed", + "data entry", + "deselect", + "deselected", + "empty", + "field", + "form", + "frame", + "inactive", + "input", + "list", + "mark", + "option", + "outline", + "pending", + "preference", + "rectangle", + "select", + "selection", + "setting", + "square", + "task", + "tick", + "todo", + "toggle", + "ui", + "unchecked", + "unselected", + "widget" + ], + "popularity": 104318 + }, + "CHECK_CIRCLE": { + "tags": [ + "accept", + "approval", + "approve", + "check", + "checkmark", + "circle", + "complete", + "completion", + "confirm", + "confirmation", + "correct", + "done", + "filled", + "finished", + "indicator", + "mark", + "ok", + "option", + "outline", + "passed", + "select", + "selection", + "status", + "success", + "task", + "tick", + "true", + "valid", + "validate", + "validation", + "verified", + "yes" + ], + "popularity": 421412 + }, + "CHECK_CIRCLE_OUTLINE": { + "tags": [ + "accept", + "approval", + "approve", + "check", + "checkmark", + "circle", + "complete", + "completion", + "confirm", + "confirmation", + "correct", + "done", + "filled", + "finished", + "indicator", + "mark", + "ok", + "option", + "outline", + "passed", + "select", + "selection", + "status", + "success", + "task", + "tick", + "true", + "valid", + "validate", + "validation", + "verified", + "yes" + ], + "popularity": 136778 + }, + "CHECKLIST": { + "tags": [ + "align", + "alignment", + "approve", + "check", + "check marks", + "checked", + "checklist", + "checkmark", + "complete", + "completed", + "doc", + "done", + "edit", + "editing", + "editor", + "entries", + "finished", + "format", + "item", + "items", + "line", + "lines", + "list", + "list items", + "mark", + "notes", + "ok", + "organization", + "planning", + "productivity", + "project management", + "select", + "sheet", + "spreadsheet", + "square", + "squares", + "task", + "task list", + "text", + "tick", + "tick mark", + "tick marks", + "ticks", + "to do list", + "type", + "validate", + "verified", + "writing", + "yes" + ], + "popularity": 39364 + }, + "CHECKLIST_RTL": { + "tags": [ + "align", + "alignment", + "approve", + "bullet points", + "check", + "checklist", + "complete", + "content list", + "data", + "doc", + "document", + "done", + "edit", + "editing", + "editor", + "entries", + "form", + "format", + "horizontal lines", + "information", + "items", + "lined list", + "list", + "management", + "mark", + "notes", + "numbered list", + "ok", + "order", + "organization", + "plan", + "planning", + "progress", + "report", + "right-to-left", + "rtl", + "select", + "sequence", + "sheet", + "spreadsheet", + "survey", + "tasks", + "text", + "tick", + "to-do", + "type", + "validate", + "verified", + "writing", + "yes" + ], + "popularity": 15592 + }, + "CHECKROOM": { + "tags": [ + "apparel", + "bag", + "boutique", + "changing room", + "checkroom", + "cloakroom", + "closet", + "clothes", + "clothing", + "coat check", + "dressing room", + "facility", + "fashion", + "fitting room", + "garment", + "hanger", + "hanging", + "hotel", + "location", + "luggage", + "place", + "reception", + "retail", + "service", + "shop", + "storage", + "store", + "travel", + "visitor", + "wardrobe" + ], + "popularity": 13674 + }, + "CHEVRON_LEFT": { + "tags": [ + "angle", + "arrow", + "arrows", + "back", + "backward", + "before", + "caret", + "carousel", + "chevron", + "direction", + "directional", + "disable_ios", + "go back", + "history", + "indicator", + "left", + "less than", + "media control", + "move left", + "navigate", + "navigation", + "page", + "pagination", + "pointer", + "previous", + "prior", + "retreat", + "return", + "rewind", + "scroll", + "slider", + "step back" + ], + "popularity": 129260 + }, + "CHEVRON_RIGHT": { + "tags": [ + "advance", + "angle", + "arrow", + "arrows", + "bracket", + "caret", + "carousel", + "chevron", + "continue", + "direction", + "drilldown", + "entry", + "expand", + "forward", + "go", + "greater than", + "indicator", + "item", + "link", + "list", + "menu", + "more", + "move", + "navigate", + "next", + "pagination", + "pointer", + "proceed", + "right", + "show", + "slider" + ], + "popularity": 224550 + }, + "CHILD_CARE": { + "tags": [ + "babies", + "baby", + "care", + "carriage", + "child", + "childcare", + "children", + "cradle", + "crib", + "crèche", + "daycare", + "face", + "family", + "guardian", + "high chair", + "infant", + "kids", + "monitor", + "newborn", + "nursery", + "parenting", + "protection", + "responsibility", + "safety", + "security", + "stroller", + "supervised", + "supervision", + "toddler", + "watch", + "young", + "youth" + ], + "popularity": 11121 + }, + "CHILD_FRIENDLY": { + "tags": [ + "access", + "age", + "age rating", + "baby", + "body", + "care", + "carriage", + "child", + "children", + "content", + "control", + "demographic", + "family", + "figure", + "filter", + "friendly", + "head", + "infant", + "kid", + "kids", + "newborn", + "parent", + "parent filter", + "person", + "profile", + "protection", + "restriction", + "safe", + "secure", + "silhouette", + "stroller", + "toddler", + "user", + "young", + "youth" + ], + "popularity": 6628 + }, + "CHROME_READER_MODE": { + "tags": [ + "article", + "book", + "bookmark", + "browser", + "chrome", + "content", + "document", + "layout", + "magazine", + "mode", + "page", + "paper", + "print", + "publication", + "read", + "reader", + "reading", + "rectangle", + "square", + "text", + "three lines", + "web", + "website" + ], + "popularity": 6436 + }, + "CHURCH": { + "tags": [ + "architecture", + "building", + "cathedral", + "ceremony", + "chapel", + "christian", + "christianity", + "church", + "community", + "cross", + "event", + "faith", + "funeral", + "gathering", + "holy place", + "ideology", + "landmark", + "location", + "place of worship", + "pointer", + "prayer", + "religion", + "religious building", + "sacred", + "sacred place", + "sanctuary", + "service", + "spiritual", + "steeple", + "temple", + "wedding", + "worship" + ], + "popularity": 4224 + }, + "CIRCLE": { + "tags": [ + "active", + "angle", + "bullet", + "button", + "circle", + "circular", + "complete", + "disc", + "dot", + "empty", + "eye", + "fish", + "focus", + "full", + "geometry", + "graphic", + "image", + "indicator", + "lens", + "mark", + "moon", + "orb", + "outline", + "panorama", + "photo", + "photography", + "picture", + "point", + "progress", + "radio", + "record", + "round", + "select", + "shape", + "solid", + "sphere", + "status", + "stop", + "target", + "whole", + "wide" + ], + "popularity": 62027 + }, + "CIRCLE_NOTIFICATIONS": { + "tags": [ + "active", + "activity", + "alarm", + "alert", + "alert bell", + "alert sound", + "announcements", + "attention", + "bell", + "bulletin", + "chime", + "circle", + "circular", + "contained", + "current", + "encircled", + "incoming", + "indication", + "information", + "message", + "new", + "news", + "notification", + "notifications", + "notify", + "ping", + "prompt", + "reminder", + "reminders", + "ring", + "ringtone", + "signal", + "sound", + "updates" + ], + "popularity": 17492 + }, + "CLASS": { + "tags": [ + "academic", + "academy", + "archive", + "book", + "book icon", + "bookmark", + "class", + "class icon", + "course", + "education", + "education icon", + "favorite", + "knowledge", + "knowledge icon", + "label", + "learning", + "learning icon", + "library", + "literature", + "literature icon", + "novel", + "open book", + "open book icon", + "read", + "reading", + "reading icon", + "reading material", + "remember", + "ribbon", + "save", + "school", + "school icon", + "study", + "tag", + "textbook", + "university", + "university icon" + ], + "popularity": 14698 + }, + "CLEAN_HANDS": { + "tags": [ + "bacteria", + "body", + "bubbles", + "care", + "clean", + "cleanse", + "disinfect", + "germ", + "germs", + "gesture", + "hand", + "hand washing", + "hands", + "health", + "health education", + "healthcare", + "hygiene", + "hygiene awareness", + "medical", + "personal", + "prevention", + "protection", + "public health", + "safety", + "sanitary", + "sanitize", + "sanitizer", + "sickness", + "soap", + "virus", + "wash hands", + "washing", + "water", + "wellness" + ], + "popularity": 5226 + }, + "CLEANING_SERVICES": { + "tags": [ + "broom", + "care", + "chore", + "clean", + "cleaning", + "commercial", + "domestic", + "dust", + "floor", + "home", + "house", + "housekeeping", + "hygiene", + "janitorial", + "maintenance", + "mop", + "organized", + "polish", + "professional", + "refresh", + "residential", + "sanitation", + "scrub", + "service", + "services", + "sparkle", + "squeaky clean", + "sweep", + "tidy", + "wash" + ], + "popularity": 15273 + }, + "CLEAR": { + "tags": [ + "abort", + "action", + "alert", + "back", + "cancel", + "cancel button", + "clear", + "close", + "confirmation", + "correct", + "cross", + "delete", + "delete button", + "dialog close", + "dismiss", + "erase", + "error", + "exit", + "exit button", + "interface control", + "modal close", + "multiply", + "notification", + "remove", + "remove item", + "stop", + "times", + "warning", + "window close", + "x", + "x mark" + ], + "popularity": 109887 + }, + "CLEAR_ALL": { + "tags": [ + "action", + "all", + "app", + "broom", + "button", + "clean", + "clear", + "clear all", + "control", + "data", + "delete all", + "desktop", + "doc", + "document", + "entries", + "erase all", + "format", + "graphic", + "icon", + "information", + "items", + "lines", + "list", + "management", + "mobile", + "organized", + "pictogram", + "remove all", + "reset", + "sweep", + "sweeping", + "symbol", + "tidy", + "web" + ], + "popularity": 11537 + }, + "CLOSE": { + "tags": [ + "abort", + "action", + "alert", + "cancel", + "cancel button", + "clear", + "close", + "confirmation", + "cross", + "delete", + "delete button", + "dialog close", + "dismiss", + "error", + "exit", + "exit button", + "interface control", + "modal close", + "multiply", + "notification", + "remove", + "remove item", + "stop", + "times", + "warning", + "window close", + "x", + "x mark" + ], + "popularity": 431377 + }, + "CLOSE_FULLSCREEN": { + "tags": [ + "action", + "arrow", + "arrows", + "arrows inward", + "box", + "button", + "close", + "collapse", + "contract", + "control", + "corners", + "diagonal arrows", + "direction", + "display", + "exit fullscreen", + "full", + "fullscreen", + "interaction", + "interface", + "media", + "minimize", + "mode", + "presentation", + "rectangle", + "reduce", + "restore", + "screen", + "shrink", + "square", + "system", + "toggle", + "video", + "view", + "window" + ], + "popularity": 23737 + }, + "CLOSED_CAPTION": { + "tags": [ + "accessibility", + "accessible", + "alphabet", + "audio", + "box", + "button", + "caption", + "captions", + "cc", + "character", + "closed", + "closed captions", + "controls", + "decoder", + "disabled", + "font", + "language", + "letters", + "line", + "listen", + "media", + "movies", + "off", + "player", + "read", + "rectangle", + "settings", + "slash", + "speech", + "spoken", + "subtitle", + "subtitles", + "switch", + "symbol", + "text", + "toggle", + "translation", + "tv", + "type", + "video" + ], + "popularity": 5565 + }, + "CLOSED_CAPTION_DISABLED": { + "tags": [ + "accessibility", + "accessible", + "alphabet", + "audio", + "barrier", + "caption", + "captions", + "cc", + "character", + "closed", + "closed captioning", + "decoder", + "disabled", + "enabled", + "exclusion", + "film", + "font", + "hearing", + "language", + "letters", + "lines", + "listening", + "media", + "movie", + "movies", + "muted", + "off", + "on", + "rectangle", + "screen", + "show", + "silent", + "slash", + "slashed", + "speech", + "square", + "struck through", + "subtitle", + "subtitles", + "symbol", + "television", + "text", + "tv", + "type", + "video" + ], + "popularity": 1634 + }, + "CLOSED_CAPTION_OFF": { + "tags": [ + "accessibility", + "accessible", + "alphabet", + "audio", + "box", + "button", + "caption", + "captions", + "cc", + "character", + "closed", + "closed captions", + "controls", + "decoder", + "disabled", + "font", + "language", + "letters", + "line", + "listen", + "media", + "movies", + "off", + "outline", + "player", + "read", + "rectangle", + "settings", + "slash", + "speech", + "spoken", + "subtitle", + "subtitles", + "switch", + "symbol", + "text", + "toggle", + "translation", + "tv", + "type", + "video" + ], + "popularity": 3173 + }, + "CLOUD": { + "tags": [ + "air", + "atmosphere", + "climate", + "cloud", + "cloudy", + "connection", + "environment", + "filled", + "forecast", + "graphic", + "icon", + "internet", + "meteorology", + "minimal", + "nature", + "network", + "outline", + "overcast", + "queue", + "rain", + "round", + "rounded", + "shape", + "simple", + "sky", + "snow", + "solid", + "symbol", + "temperature", + "ui", + "ui element", + "upload", + "weather", + "white" + ], + "popularity": 33655 + }, + "CLOUD_CIRCLE": { + "tags": [ + "app", + "application", + "backup", + "circle", + "circular", + "cloud", + "computing", + "connection", + "data", + "download", + "drive", + "files", + "filled", + "folders", + "forecast", + "internet", + "network", + "online", + "outline", + "round", + "server", + "shape", + "sky", + "storage", + "synchronization", + "technology", + "upload", + "weather" + ], + "popularity": 4607 + }, + "CLOUD_DONE": { + "tags": [ + "app", + "application", + "approve", + "available", + "backup", + "check", + "checkmark", + "cloud", + "complete", + "completed", + "computing", + "confirmed", + "connection", + "data", + "digital", + "document", + "done", + "download", + "drive", + "file", + "files", + "finished", + "folders", + "infrastructure", + "internet", + "mark", + "network", + "ok", + "online", + "ready", + "saved", + "select", + "server", + "sky", + "storage", + "success", + "symbol", + "sync", + "synchronization", + "technology", + "tick", + "upload", + "validate", + "verified", + "weather", + "yes" + ], + "popularity": 12581 + }, + "CLOUD_DOWNLOAD": { + "tags": [ + "access", + "app", + "application", + "arrow", + "backup", + "cloud", + "cloud computing", + "cloud storage", + "computer", + "connection", + "data", + "document", + "down", + "download", + "download file", + "drive", + "file", + "files", + "folders", + "get", + "internet", + "move", + "network", + "receive", + "retrieve", + "save", + "server", + "sky", + "storage", + "sync", + "synchronization", + "transfer", + "transfer file", + "upload" + ], + "popularity": 31149 + }, + "CLOUD_OFF": { + "tags": [ + "access", + "app", + "application", + "backup", + "broken", + "cloud", + "connection", + "data", + "disabled", + "disconnected", + "drive", + "enabled", + "error", + "failed", + "failed connection", + "files", + "folders", + "internet", + "network", + "no access", + "not available", + "not connected", + "not synced", + "off", + "offline", + "on", + "outage", + "service disabled", + "service offline", + "sky", + "slash", + "storage", + "storage offline", + "storage unavailable", + "sync", + "unavailable", + "unavailable service", + "upload", + "warning", + "weather" + ], + "popularity": 9711 + }, + "CLOUD_QUEUE": { + "tags": [ + "air", + "atmosphere", + "climate", + "cloud", + "cloudy", + "connection", + "environment", + "filled", + "forecast", + "graphic", + "icon", + "internet", + "meteorology", + "minimal", + "nature", + "network", + "outline", + "overcast", + "queue", + "rain", + "round", + "rounded", + "shape", + "simple", + "sky", + "snow", + "solid", + "symbol", + "temperature", + "ui", + "ui element", + "upload", + "weather", + "white" + ], + "popularity": 11900 + }, + "CLOUD_SYNC": { + "tags": [ + "app", + "application", + "around", + "arrow", + "backup", + "circular arrow", + "cloud", + "computing", + "connection", + "cycle", + "data", + "data transfer", + "database", + "direction", + "download", + "drive", + "files", + "folders", + "icon", + "inprogress", + "internet", + "load", + "loading refresh", + "loop", + "network", + "online", + "progress", + "refresh", + "renew", + "rotate", + "save", + "sky", + "storage", + "sync", + "synchronize", + "system", + "transfer", + "turn", + "two arrows", + "two-way", + "update", + "upload", + "web" + ], + "popularity": 7754 + }, + "CLOUD_UPLOAD": { + "tags": [ + "app", + "application", + "arrow", + "backup", + "cloud", + "computing", + "connection", + "data", + "digital", + "document upload", + "download", + "drive", + "file upload", + "files", + "folders", + "image upload", + "internet", + "move", + "network", + "online", + "remote storage", + "save", + "send", + "send data", + "server", + "share", + "sky", + "software", + "storage", + "sync", + "system", + "transfer", + "up", + "up arrow", + "upload", + "video upload", + "weather" + ], + "popularity": 40778 + }, + "CO2": { + "tags": [ + "air", + "atom", + "carbon", + "carbon dioxide", + "chemical", + "chemical compound", + "chemical formula", + "chemistry", + "climate change", + "co2", + "dioxide", + "education", + "element", + "emissions", + "environmental", + "experiment", + "gas", + "greenhouse gas", + "icon", + "laboratory", + "learning", + "molecule", + "outline", + "pictogram", + "pollution", + "science", + "scientific", + "stroke", + "study", + "symbol" + ], + "popularity": 3793 + }, + "CO_PRESENT": { + "tags": [ + "arrow", + "broadcast", + "broadcasting", + "cast", + "co-present", + "collaboration", + "conference", + "digital", + "display", + "meeting", + "online", + "person", + "present", + "presentation", + "profile", + "projection", + "rectangle", + "remote", + "screen", + "screen sharing", + "share", + "sharing", + "site", + "slides", + "streaming", + "togather", + "user", + "video", + "video call", + "view", + "web", + "webcam", + "website", + "window" + ], + "popularity": 6075 + }, + "CODE": { + "tags": [ + "algorithm", + "application", + "backend", + "brackets", + "build", + "code", + "coding", + "commands", + "compile", + "computer", + "console", + "css", + "develop", + "developer", + "development", + "editor", + "engineer", + "engineering", + "frontend", + "function", + "html", + "language", + "logic", + "markup", + "platform", + "programmer", + "programming", + "script", + "software", + "source", + "syntax", + "technology", + "terminal", + "variable", + "web" + ], + "popularity": 60261 + }, + "CODE_OFF": { + "tags": [ + "angle brackets", + "block", + "brackets", + "cancel", + "code", + "coding", + "css", + "deactivate", + "develop", + "developer", + "developer tools", + "disable", + "disabled", + "disallow", + "editing", + "enabled", + "engineer", + "engineering", + "error", + "exclude", + "forbidden", + "function", + "html", + "invalid", + "less than greater than", + "markup", + "no", + "off", + "on", + "platform", + "programming", + "remove", + "restrict", + "script", + "slash", + "source", + "stop", + "syntax", + "toggle off", + "unavailable" + ], + "popularity": 4726 + }, + "COFFEE": { + "tags": [ + "barista", + "beverage", + "break", + "breakfast", + "cafe", + "cafe culture", + "cafe menu", + "caffeine", + "chocolate", + "coffee", + "coffee cup", + "cup", + "diner", + "drink", + "energy", + "food", + "hot", + "hot beverage", + "hot drink", + "kitchen", + "liquid", + "menu item", + "morning", + "mug", + "plate", + "refreshments", + "restaurant", + "set", + "steam", + "steaming", + "tea", + "warm" + ], + "popularity": 11253 + }, + "COFFEE_MAKER": { + "tags": [ + "appliance", + "appliances", + "automation", + "beverage", + "breakfast", + "brew", + "cafe", + "caffeine", + "coffee", + "coffee maker", + "cooking", + "cup", + "domestic", + "drink", + "drip coffee", + "electric", + "equipment", + "food and drink", + "home", + "hot drink", + "household", + "kitchen", + "machine", + "maker", + "morning", + "mug", + "object", + "pour over", + "preparation", + "restaurant", + "service" + ], + "popularity": 4597 + }, + "COLLECTIONS": { + "tags": [ + "adjustments", + "album", + "categorization", + "categorize", + "choices", + "collection", + "collections", + "control", + "criteria", + "data", + "filter", + "funnel", + "gallery", + "image", + "landscape", + "library", + "list", + "manage", + "management", + "mountain", + "mountains", + "narrow", + "narrowing", + "options", + "organization", + "organize", + "photo", + "photography", + "picture", + "preferences", + "refine", + "refinement", + "rules", + "select", + "selection", + "settings", + "sort", + "sorting", + "stack", + "view" + ], + "popularity": 38824 + }, + "COLLECTIONS_BOOKMARK": { + "tags": [ + "album", + "archive", + "bookmark", + "books", + "categorized", + "collection", + "collections", + "documents", + "favorite", + "gallery", + "grouped", + "journal", + "knowledge", + "label", + "library", + "list", + "literature", + "multiple", + "notebook", + "notes", + "organize", + "paper", + "piled", + "read", + "reading", + "reading list", + "readings", + "record", + "records", + "reference", + "register", + "remember", + "ribbon", + "save", + "stack", + "tab", + "tag" + ], + "popularity": 9770 + }, + "COLOR_LENS": { + "tags": [ + "appearance", + "art", + "artist", + "artistic", + "brush", + "color", + "colors", + "creative", + "customization", + "customize", + "design", + "designer", + "draw", + "drawing", + "editor", + "graphic", + "hues", + "lens", + "paint", + "painting", + "palette", + "pallet", + "shades", + "spectrum", + "style", + "swatch", + "theme", + "tint", + "tints", + "tone", + "tones", + "visual" + ], + "popularity": 11612 + }, + "COLORIZE": { + "tags": [ + "adjustments", + "appearance", + "art", + "brush", + "color", + "color fill", + "color options", + "color palette", + "color picker", + "color settings", + "color swatches", + "color wheel", + "colorize", + "colors", + "customization", + "design", + "drawing", + "dropper", + "extract", + "eye", + "filters", + "hues", + "image editing", + "paint", + "painting", + "palette", + "photo editing", + "picker", + "rainbow", + "shades", + "spectrum", + "style", + "swatches", + "tints", + "tool", + "visual effects" + ], + "popularity": 6722 + }, + "COMMENT": { + "tags": [ + "add", + "add comment", + "balloon", + "bubble", + "chat", + "comment", + "communicate", + "communication", + "conversation", + "create", + "create comment", + "dialogue", + "discussion", + "feedback", + "insert", + "message", + "new", + "new comment", + "outline", + "plus", + "rectangle", + "reply", + "respond", + "speech", + "square", + "square bubble", + "talk", + "text", + "text bubble", + "write comment" + ], + "popularity": 25576 + }, + "COMMENT_BANK": { + "tags": [ + "archive", + "bank", + "bookmark", + "bubble", + "cchat", + "chat", + "collection", + "comment", + "communicate", + "communication", + "conversation", + "dialogue", + "discussion", + "favorite", + "feedback", + "group", + "history", + "label", + "layered", + "library", + "message", + "multiple", + "notes", + "organized", + "record", + "remember", + "repository", + "ribbon", + "save", + "sorted", + "speech", + "speech bubble", + "square", + "stacking", + "storage", + "store", + "tag", + "talk", + "text" + ], + "popularity": 5195 + }, + "COMMENTS_DISABLED": { + "tags": [ + "balloon", + "bar", + "blocked", + "bubble", + "censorship", + "chat", + "chat bubble with line", + "chat disabled", + "circle", + "comment", + "comment off", + "comments", + "comments blocked", + "comments disabled", + "communicate", + "communication restricted", + "conversation disabled", + "cross", + "dialogue restricted", + "disabled", + "enabled", + "feedback", + "line", + "message", + "message balloon with bar", + "messaging disabled", + "moderation", + "muted", + "muted comments", + "no comments", + "off", + "offline", + "on", + "restricted comments", + "slash", + "speech", + "speech bubble", + "speech bubble with slash" + ], + "popularity": 2067 + }, + "COMMIT": { + "tags": [ + "accomplish", + "bind", + "branch", + "changes", + "circle", + "code", + "commit", + "confirm", + "connection", + "dedicate", + "development", + "diagram", + "execute", + "finalize", + "flow", + "git", + "graph", + "history", + "journey", + "line", + "link", + "log", + "merge", + "network", + "node", + "path", + "perform", + "pledge", + "point", + "progress", + "repository", + "save", + "source control", + "submit", + "update", + "version control" + ], + "popularity": 2794 + }, + "COMMUTE": { + "tags": [ + "automobile", + "car", + "commute", + "destination", + "direction", + "directions", + "driving", + "guidance", + "journey", + "location", + "location pin", + "map", + "maps", + "marker", + "mobility", + "navigation", + "path", + "pin", + "place", + "pointer", + "position", + "public", + "public transport", + "road", + "route", + "spot", + "street", + "train", + "transit", + "transportation", + "travel", + "trip", + "vehicle", + "way" + ], + "popularity": 11277 + }, + "COMPARE": { + "tags": [ + "adjust", + "adjustment", + "analysis", + "analyze", + "chart", + "compare", + "comparison", + "comparison tool", + "competing", + "contrast", + "data", + "data comparison", + "difference", + "edit", + "editing", + "edits", + "enhance", + "evaluation", + "feature comparison", + "fix", + "graph", + "image", + "images", + "items", + "measurement", + "metrics", + "opposing", + "opposite", + "parallel", + "photo", + "photography", + "photos", + "product comparison", + "report", + "review", + "scan", + "settings", + "side by side", + "statistics", + "two", + "versus", + "vs" + ], + "popularity": 8398 + }, + "COMPARE_ARROWS": { + "tags": [ + "alternative", + "arrow", + "arrows", + "balance", + "bidirectional", + "change", + "choices", + "collide", + "compare", + "cross", + "data transfer", + "direction", + "exchange", + "flow", + "horizontal", + "left", + "left and right", + "move", + "opposing arrows", + "opposite", + "options", + "parallel arrows", + "pressure", + "push", + "reciprocal", + "right", + "swap", + "switch", + "symmetry", + "sync", + "synchronize", + "together", + "toggle", + "transfer", + "two", + "x-axis" + ], + "popularity": 21485 + }, + "COMPASS_CALIBRATION": { + "tags": [ + "accuracy", + "adjust", + "alignment", + "bearing", + "calibrate", + "calibration", + "circle", + "compass", + "configuration", + "connection", + "direction", + "east", + "fine tune", + "internet", + "location", + "magnetic north", + "map", + "mapping", + "maps", + "measurement", + "navigation", + "needle", + "network", + "north", + "orientation", + "pointer", + "position", + "refresh", + "sensor", + "service", + "setting", + "settings", + "signal", + "south", + "tool", + "true north", + "west", + "wifi", + "wireless" + ], + "popularity": 2039 + }, + "COMPOST": { + "tags": [ + "bin", + "bio", + "biomass", + "compost", + "compostable", + "composting", + "container", + "decomposable", + "decompose", + "decomposition", + "earth", + "eco", + "ecology", + "environment", + "environmental", + "food scraps", + "garbage", + "garden", + "gardening", + "green", + "leaf", + "leafs", + "natural", + "nature", + "organic", + "organic waste", + "plant", + "recycle", + "recycling", + "reduce", + "reuse", + "rot", + "sustainability", + "sustainable", + "trash", + "waste" + ], + "popularity": 9895 + }, + "COMPRESS": { + "tags": [ + "adjust size", + "arrow", + "arrows", + "collide", + "compact", + "compress", + "compress file", + "corners", + "data", + "diagonal arrows", + "dimensions", + "expand", + "file size", + "fit", + "image", + "maximize", + "minimize", + "multimedia", + "opposite arrows", + "optimize", + "outward arrows", + "pressure", + "push", + "reduce", + "resize", + "scale", + "scale down", + "scale up", + "screen", + "shrink", + "together", + "transform", + "video", + "window", + "zoom" + ], + "popularity": 6747 + }, + "COMPUTER": { + "tags": [ + "accessory", + "android", + "chrome", + "communication", + "computer", + "computing", + "data", + "desk", + "desktop", + "device", + "digital", + "display", + "electronic", + "electronic device", + "gadget", + "hardware", + "internet", + "ios", + "laptop", + "mac", + "monitor", + "network", + "notebook", + "office", + "os", + "pc", + "peripheral", + "personal computer", + "screen", + "server", + "system", + "technology", + "technology device", + "web", + "window", + "work", + "workstation" + ], + "popularity": 35803 + }, + "CONFIRMATION_NUMBER": { + "tags": [ + "access", + "account", + "admission", + "authorization", + "booking", + "code", + "confirmation", + "credential", + "digits", + "entertainment", + "entry", + "event", + "identifier", + "key", + "lock", + "login", + "number", + "numbers", + "order", + "pass", + "password", + "pin", + "receipt", + "reference", + "reservation", + "secret", + "secure", + "sequence", + "symbol", + "ticket", + "token", + "unique", + "validation", + "verification" + ], + "popularity": 25725 + }, + "CONNECT_WITHOUT_CONTACT": { + "tags": [ + "broadcast", + "communicating", + "communication", + "connect", + "connection", + "connectivity", + "contact", + "contactless", + "data", + "distance", + "link", + "network", + "pairing", + "people", + "proximity", + "radio", + "rf", + "ripples", + "sharing", + "signal", + "social", + "socialize", + "sync", + "synchronization", + "technology", + "transfer", + "transmission", + "waves", + "wireless", + "without" + ], + "popularity": 12022 + }, + "CONNECTED_TV": { + "tags": [ + "airplay", + "android", + "cast", + "chrome", + "connect", + "connected", + "connection", + "desktop", + "device", + "display", + "electronic", + "hardware", + "home entertainment", + "ios", + "lines", + "mac", + "media", + "mirror", + "monitor", + "network", + "os", + "rectangle", + "screen", + "screencast", + "smart tv", + "streaming", + "technology", + "television", + "tv", + "video", + "web", + "wifi", + "window", + "wireless" + ], + "popularity": 3878 + }, + "CONNECTING_AIRPORTS": { + "tags": [ + "air", + "aircraft", + "airplane", + "airplanes", + "airport", + "arrival", + "aviation", + "aviation route", + "connecting flights", + "connection", + "departure", + "destination", + "flight", + "flight path", + "flights", + "fly", + "flying", + "globe", + "hub", + "itinerary", + "journey", + "link", + "location", + "logistics", + "map", + "mode", + "network", + "on", + "path", + "pin", + "plane", + "planes", + "route", + "signal", + "transfer", + "transit", + "transport", + "transportation", + "travel", + "travel route", + "trip", + "world" + ], + "popularity": 2951 + }, + "CONSTRUCTION": { + "tags": [ + "build", + "builder", + "building", + "carpenter", + "construction", + "developing", + "development", + "engineer", + "engineering", + "equipment", + "fix", + "fixing", + "hammer", + "handyman", + "improvement", + "in progress", + "industrial", + "industry", + "maintain", + "maintenance", + "renovate", + "renovation", + "repair", + "site", + "site work", + "technical", + "technician", + "tools", + "tradesman", + "tradesperson", + "under construction", + "work", + "worker", + "working", + "wrench" + ], + "popularity": 52334 + }, + "CONTACT_EMERGENCY": { + "tags": [ + "account", + "alert", + "assistance", + "avatar", + "call", + "caution", + "cell", + "contact", + "contacts", + "critical", + "danger", + "emergency", + "exclamation mark", + "face", + "figure", + "geometry", + "help", + "human", + "important", + "info", + "information", + "mobile", + "notification", + "people", + "person", + "person icon", + "phone", + "profile", + "profile icon", + "profile picture", + "safety", + "security", + "shape", + "support", + "symbol", + "urgent", + "user", + "user icon", + "warning" + ], + "popularity": 2792 + }, + "CONTACT_MAIL": { + "tags": [ + "account", + "address", + "address book", + "avatar", + "business card", + "communicate", + "communication", + "connection", + "contact", + "contact information", + "correspondence", + "details", + "digital mail", + "directory", + "email", + "envelope", + "face", + "human", + "inbox", + "info", + "information", + "letter", + "mail", + "message", + "network", + "online communication", + "people", + "person", + "personal", + "postcard", + "profile", + "receive", + "send", + "user", + "user data", + "user profile" + ], + "popularity": 30537 + }, + "CONTACT_PAGE": { + "tags": [ + "account", + "address book", + "avatar", + "book", + "business", + "circle", + "contact", + "data", + "details", + "directory", + "doc", + "document", + "drive", + "face", + "file", + "folder", + "folders", + "form", + "human", + "icon", + "identity", + "information", + "list", + "office", + "outline", + "page", + "paper", + "people", + "person", + "personal", + "profile", + "record", + "rectangle", + "shape", + "sheet", + "slide", + "square", + "storage", + "symbol", + "user", + "writing" + ], + "popularity": 31528 + }, + "CONTACT_PHONE": { + "tags": [ + "account", + "address book", + "avatar", + "call", + "circle", + "communicate", + "communication", + "contact", + "directory", + "face", + "filled", + "glyph", + "head", + "human", + "info", + "information", + "message", + "mobile", + "outline", + "people", + "person", + "phone", + "profile", + "profile picture", + "round", + "shoulders", + "user" + ], + "popularity": 19422 + }, + "CONTACT_SUPPORT": { + "tags": [ + "?", + "ask", + "assistance", + "bubble", + "bubble icon", + "chat", + "chat bubble", + "chatbot", + "comment", + "communicate", + "communication", + "communication icon", + "contact", + "conversation", + "customer service", + "dialog", + "dialog box", + "faq", + "help", + "help icon", + "info", + "information", + "interaction", + "mark", + "message", + "messaging", + "punctuation", + "query", + "question", + "question icon", + "question mark", + "service", + "speech", + "speech bubble", + "support", + "support icon", + "symbol", + "talk" + ], + "popularity": 58742 + }, + "CONTACTLESS": { + "tags": [ + "banking", + "bluetooth", + "card reader", + "cash", + "commerce", + "connect", + "connection", + "connectivity", + "contact", + "contactless", + "credit", + "data", + "device", + "digital", + "electronic", + "finance", + "link", + "mastercard", + "mobile payment", + "near field communication", + "network", + "nfc", + "pay", + "payment", + "paypass", + "radio waves", + "reader", + "retail", + "secure", + "security", + "shopping", + "signal", + "tap", + "technology", + "terminal", + "transaction", + "transfer", + "visa", + "wave", + "wifi", + "wireless" + ], + "popularity": 9311 + }, + "CONTACTS": { + "tags": [ + "account", + "accounts", + "address book", + "avatar", + "avatars", + "call", + "cell", + "communication", + "connect", + "connection", + "contact", + "contacts", + "directory", + "face", + "figures", + "friends", + "group", + "human", + "humans", + "info", + "information", + "list", + "management", + "member", + "members", + "mobile", + "network", + "people", + "person", + "phone", + "profile", + "profiles", + "silhouette", + "social", + "team", + "user", + "users" + ], + "popularity": 25431 + }, + "CONTENT_COPY": { + "tags": [ + "action", + "clipboard", + "clone", + "content", + "copy", + "copy content", + "create", + "cut", + "data", + "doc", + "document", + "duplicate", + "edit", + "entry", + "file", + "information", + "make copy", + "menu", + "multiple", + "new", + "object", + "option", + "overlapping", + "pages", + "paper", + "paste", + "record", + "rectangle", + "replicate", + "sheet", + "square", + "stack", + "text", + "toolbar" + ], + "popularity": 140656 + }, + "CONTENT_CUT": { + "tags": [ + "action", + "audio", + "blade", + "clip", + "content", + "copy", + "craft", + "cut", + "divide", + "doc", + "document", + "edit", + "file", + "media", + "office", + "paper", + "paste", + "remove", + "scissors", + "segment", + "separate", + "shape", + "sharp", + "snip", + "text", + "tool", + "trim", + "utensil", + "video" + ], + "popularity": 17422 + }, + "CONTENT_PASTE": { + "tags": [ + "action", + "add", + "application", + "attach", + "button", + "clip", + "clipboard", + "content", + "control", + "copy", + "cut", + "data", + "doc", + "document", + "edit", + "entry", + "file", + "fill", + "form", + "function", + "insert", + "memo", + "multiple", + "notes", + "office", + "paper", + "paste", + "productivity", + "record", + "report", + "sheet", + "text", + "tool", + "write" + ], + "popularity": 33663 + }, + "CONTENT_PASTE_GO": { + "tags": [ + "action", + "archive", + "arrow", + "box", + "clipboard", + "content", + "copy", + "data", + "deliver", + "disabled", + "doc", + "document", + "duplicate", + "enabled", + "file", + "folder", + "go", + "import", + "information", + "insert", + "material design", + "move", + "on", + "paper", + "paste", + "process", + "rectangle", + "right arrow", + "send", + "sheet", + "slash", + "square", + "transfer", + "workflow" + ], + "popularity": 5032 + }, + "CONTENT_PASTE_OFF": { + "tags": [ + "blocked", + "cancel paste", + "cannot paste", + "clear", + "clipboard", + "content", + "copy", + "delete", + "denied", + "diagonal line", + "disabled", + "disabled paste", + "doc", + "document", + "duplicate", + "enabled", + "file", + "forbidden", + "form", + "insert", + "no paste", + "off", + "on", + "page", + "paper", + "paste", + "paste off", + "rectangle", + "remove", + "restricted", + "sheet", + "slash", + "text", + "unavailable", + "unpaste" + ], + "popularity": 3270 + }, + "CONTENT_PASTE_SEARCH": { + "tags": [ + "analysis", + "archive", + "clipboard", + "content", + "data", + "discover", + "doc", + "document", + "examine", + "explore", + "file", + "find", + "find content", + "form", + "information", + "inspect", + "investigate", + "lookup", + "lookup data", + "magnifying glass", + "paper", + "paste", + "query", + "record", + "report", + "research", + "review", + "search", + "search document", + "sheet", + "text", + "trace", + "track" + ], + "popularity": 9400 + }, + "CONTRAST": { + "tags": [ + "adjust", + "adjustment", + "balance", + "black", + "bright", + "brightness", + "contrast", + "control", + "dark", + "dark theme", + "dim", + "display", + "dynamic range", + "edit", + "editing", + "effect", + "enhance", + "exposure", + "filter", + "graphic", + "grayscale", + "highlights", + "image", + "images", + "levels", + "light", + "modify", + "photo", + "photography", + "picture", + "pictures", + "screen", + "settings", + "shadows", + "slider", + "tone", + "visual", + "white" + ], + "popularity": 3987 + }, + "CONTROL_CAMERA": { + "tags": [ + "adjust", + "apparatus", + "arrow", + "arrows", + "camera", + "capture", + "center", + "circle", + "configure", + "control", + "device", + "direction", + "equipment", + "film", + "gadget", + "left", + "lens", + "media", + "move", + "multimedia", + "options", + "photo", + "photography", + "preferences", + "record", + "rectangle", + "reposition", + "right", + "settings", + "setup", + "shutter", + "square", + "technology", + "tool", + "video", + "viewfinder" + ], + "popularity": 4501 + }, + "CONTROL_POINT": { + "tags": [ + "+", + "action", + "add", + "append", + "button", + "circle", + "circular", + "content", + "control", + "create", + "data", + "document", + "element", + "entry", + "file", + "form", + "generate", + "increase", + "insert", + "item", + "list", + "make", + "new", + "option", + "outline", + "plus", + "point", + "record", + "round", + "row", + "tool" + ], + "popularity": 16930 + }, + "CONTROL_POINT_DUPLICATE": { + "tags": [ + "+", + "add", + "addmultiple", + "circle", + "circles", + "clone", + "control", + "copy", + "create", + "double", + "duplicate", + "generatemultiples", + "make", + "multiple", + "new", + "overlapping circles", + "overlay", + "plus", + "point", + "replicate", + "symbol", + "two circles" + ], + "popularity": 4184 + }, + "COOKIE": { + "tags": [ + "alert", + "baked goods", + "biscuit", + "chocolate chip cookie", + "circle", + "circle with dots", + "circular", + "compliance", + "consent", + "cookie", + "cookies", + "crumbs", + "data", + "dessert", + "dotted circle", + "food", + "gdpr", + "notification", + "options", + "preferences", + "privacy", + "privacy settings", + "round", + "settings", + "snack", + "sweet", + "tracking", + "treat", + "wafer", + "website data" + ], + "popularity": 6564 + }, + "COPY_ALL": { + "tags": [ + "all", + "clone", + "content", + "copy", + "copy all", + "cut", + "dash", + "dashed", + "data", + "doc", + "document", + "documents", + "duplicate", + "file", + "files", + "layers", + "multiple", + "multiply", + "page", + "paper", + "papers", + "past", + "replicate", + "reproduce", + "select all", + "select content", + "stack", + "text" + ], + "popularity": 9972 + }, + "COPYRIGHT": { + "tags": [ + "agreement", + "alphabet", + "attribution", + "brand", + "c", + "character", + "circle", + "copyright", + "credit", + "disclaimer", + "emblem", + "font", + "identifier", + "identity", + "intellectual property", + "label", + "legal", + "letter c", + "letters", + "licensing", + "logo", + "mark", + "notice", + "owner", + "ownership", + "property", + "protection", + "registered", + "rights", + "seal", + "signature", + "stamp", + "surrounding circle", + "symbol", + "text" + ], + "popularity": 18739 + }, + "CORONAVIRUS": { + "tags": [ + "19", + "bacteria", + "biohazard", + "biology", + "cell", + "circle", + "contagious", + "coronavirus", + "covid", + "covid-19", + "disease", + "epidemic", + "germ", + "germs", + "global", + "health", + "healthcare", + "illness", + "infection", + "medical", + "microbe", + "outbreak", + "pandemic", + "pathogen", + "points", + "research", + "science", + "sick", + "sickness", + "social", + "sphere", + "spikes", + "virus" + ], + "popularity": 18377 + }, + "CORPORATE_FARE": { + "tags": [ + "abstract", + "architecture", + "banking", + "building", + "business", + "city", + "company", + "corporate", + "estate", + "fare", + "finance", + "full", + "government", + "graphic", + "headquarters", + "icon", + "institution", + "law", + "line", + "office", + "organization", + "place", + "real", + "real estate", + "rectangle", + "residence", + "residential", + "shape", + "shelter", + "skyscraper", + "solid", + "structure", + "symbol", + "tower", + "urban" + ], + "popularity": 19952 + }, + "COTTAGE": { + "tags": [ + "abode", + "accommodation", + "architecture", + "beach", + "building", + "cabin", + "cottage", + "countryside", + "door", + "dwelling", + "dwelling place", + "estate", + "home", + "house", + "housing", + "lake", + "lodge", + "lodging.", + "maps", + "place", + "property", + "real", + "rectangle", + "residence", + "residential", + "roof", + "rural", + "shelter", + "simple house", + "small house", + "square", + "stay", + "structure", + "traveling", + "triangle", + "village", + "wall", + "window" + ], + "popularity": 17204 + }, + "COUNTERTOPS": { + "tags": [ + "abstract", + "bathroom", + "block", + "building", + "commercial", + "construction", + "counter", + "countertops", + "decor", + "design element", + "flat", + "furniture", + "home", + "horizontal", + "house", + "interior design", + "kitchen", + "laminate", + "line", + "material", + "outline", + "plane", + "renovation", + "residential", + "room", + "shape", + "simple", + "sink", + "slab", + "solid", + "stone", + "surface", + "table", + "tops", + "wood" + ], + "popularity": 3407 + }, + "CREATE": { + "tags": [ + "action", + "alter", + "author", + "change", + "compose", + "control", + "create", + "document", + "edit", + "editing", + "form", + "glyph", + "input", + "mode", + "mode_edit", + "mode_edit_outline", + "modify", + "new", + "outline", + "pen", + "pencil", + "revise", + "shape", + "stroke", + "text", + "tool", + "update", + "write", + "writing" + ], + "popularity": 39668 + }, + "CREATE_NEW_FOLDER": { + "tags": [ + "+", + "add", + "addition", + "archive", + "build", + "collection", + "content", + "create", + "data", + "directory", + "doc", + "document", + "drive", + "file", + "folder", + "generate", + "group", + "library", + "make", + "management", + "new", + "organization", + "plus", + "produce", + "rectangle", + "save", + "sheet", + "slide", + "storage", + "symbol", + "tab" + ], + "popularity": 16774 + }, + "CREDIT_CARD": { + "tags": [ + "account", + "account information", + "amex", + "balance", + "bank", + "banking", + "bill", + "buy", + "card", + "cash", + "checkout", + "chip", + "coin", + "commerce", + "cost", + "credit", + "credit card", + "currency", + "discover", + "dollars", + "e-commerce", + "finance", + "financial", + "funding", + "mastercard", + "money", + "online", + "pay", + "payment", + "plastic", + "price", + "purchase", + "rectangle", + "secure", + "shopping", + "spend", + "stripe", + "symbol", + "transaction", + "visa", + "wallet" + ], + "popularity": 95946 + }, + "CREDIT_CARD_OFF": { + "tags": [ + "banking", + "bill", + "blocked", + "broken", + "cancelled", + "card", + "cash", + "coin", + "commerce", + "cost", + "credit", + "credit card", + "currency", + "deactivated", + "decline", + "disabled", + "dollars", + "enabled", + "error", + "failure", + "finance", + "financial", + "forbidden", + "glyph", + "icon", + "invalid", + "line", + "money", + "no access", + "off", + "online", + "outline", + "pay", + "payment", + "payment card", + "price", + "rectangle", + "rejected", + "restricted", + "shape", + "shopping", + "slash", + "stop", + "symbol", + "unavailable" + ], + "popularity": 6029 + }, + "CREDIT_SCORE": { + "tags": [ + "analysis", + "approve", + "assessment", + "banking", + "bill", + "card", + "cash", + "check", + "circle", + "coin", + "commerce", + "complete", + "cost", + "credit", + "credit score", + "currency", + "debt", + "dial", + "digits", + "dollars", + "done", + "evaluation", + "ficoscore", + "finance", + "financial", + "gauge", + "indicator", + "level", + "loan", + "mark", + "measurement", + "meter", + "money", + "number", + "numerical", + "ok", + "online", + "pay", + "payment", + "performance", + "personal finance", + "progress", + "ranking", + "rating", + "report", + "score", + "select", + "summary", + "symbol", + "three digits", + "tick", + "validate", + "verified", + "yes" + ], + "popularity": 24485 + }, + "CRIB": { + "tags": [ + "babies", + "baby", + "baby bed", + "basic", + "bassinet", + "bed", + "bedroom", + "box", + "child", + "child bed", + "children", + "cradle", + "crib", + "drawing", + "furniture", + "infant", + "infant bed", + "kid", + "lines", + "minimal", + "newborn", + "nursery", + "object", + "outline", + "rectangle", + "silhouette", + "simple", + "sleep", + "sleeping", + "square", + "stroke", + "toddler" + ], + "popularity": 1996 + }, + "CRISIS_ALERT": { + "tags": [ + "!", + "alarm", + "alert", + "attention", + "bullseye", + "caution", + "crisis", + "critical", + "danger", + "emergency", + "error", + "errors", + "exclamation", + "exclamation point", + "feedback", + "hazard", + "important", + "information", + "issues", + "mark", + "mistakes", + "note", + "notification", + "problems", + "risks", + "safety", + "security", + "sign", + "status", + "symbol", + "system", + "target", + "threat", + "triangle", + "urgent", + "warning" + ], + "popularity": 3702 + }, + "CROP": { + "tags": [ + "adjust", + "adjustments", + "area", + "boundary", + "clip", + "corners", + "crop", + "cropping", + "cut", + "edit", + "editing", + "editor", + "format", + "frame", + "graphic", + "image", + "images", + "media", + "modify", + "outline", + "photo", + "photos", + "picture", + "proportion", + "rectangle", + "reframe", + "resize", + "selection", + "settings", + "shape", + "size", + "square", + "tool", + "transform", + "trim", + "video" + ], + "popularity": 7388 + }, + "CROP_16_9": { + "tags": [ + "16:9", + "adjust", + "adjustments", + "area", + "aspect ratio", + "by", + "canvas", + "cinema", + "crop", + "cropping", + "custom", + "dimensions", + "edit", + "editing", + "editor", + "format", + "frame", + "image", + "images", + "media", + "movie", + "photo", + "photography", + "photos", + "ratio", + "rectangle", + "resize", + "screen", + "selection", + "settings", + "shape", + "size", + "square", + "tools", + "transform", + "video", + "videography", + "widescreen" + ], + "popularity": 3022 + }, + "CROP_3_2": { + "tags": [ + "3 by 2", + "3:2", + "3x2", + "adjust", + "adjustments", + "area", + "aspect ratio", + "by", + "crop", + "dimensions", + "edit", + "editing", + "format", + "frame", + "framing", + "height", + "horizontal", + "image", + "image editing", + "images", + "landscape", + "media", + "overlapping squares", + "photo", + "photo editing", + "photograph", + "photos", + "picture", + "proportion", + "rectangle", + "resize", + "scale", + "settings", + "size", + "square", + "two squares", + "width" + ], + "popularity": 1896 + }, + "CROP_5_4": { + "tags": [ + "5:4", + "adjust", + "adjustments", + "area", + "aspect ratio", + "border", + "boundary", + "by", + "crop", + "dimension", + "edit", + "editing", + "editing tools", + "five by four", + "format", + "frame", + "framing", + "graphic", + "image", + "image editing", + "images", + "media", + "modify", + "outline", + "photo", + "photo editing", + "photos", + "picture", + "ratio", + "rectangle", + "resize", + "settings", + "shape", + "size", + "square", + "transform", + "trim", + "video", + "video editing" + ], + "popularity": 2198 + }, + "CROP_7_5": { + "tags": [ + "7:5 ratio", + "adjust", + "adjustments", + "area", + "art", + "aspect ratio", + "bounding box", + "by", + "crop", + "edit", + "editing", + "editor", + "frame", + "graphic", + "horizontal", + "image", + "images", + "landscape", + "media", + "photo", + "photography", + "photos", + "picture", + "rectangle", + "resize", + "selection", + "settings", + "seven by five", + "shape", + "size", + "square", + "tool", + "wide" + ], + "popularity": 2480 + }, + "CROP_DIN": { + "tags": [ + "adjust", + "adjustments", + "area", + "area selection", + "aspect ratio", + "border", + "boundary", + "contract", + "crop", + "cut", + "din", + "edit", + "editing", + "editor", + "expand", + "extend", + "frame", + "framing", + "geometric", + "image", + "images", + "manipulate", + "media", + "modify", + "photo", + "photos", + "picture", + "rectangle", + "resize", + "settings", + "shape", + "shrink", + "size", + "square", + "square crop", + "tool", + "transform", + "trim" + ], + "popularity": 4306 + }, + "CROP_FREE": { + "tags": [ + "adjust", + "adjustments", + "area", + "bounding box", + "box", + "corners", + "crop", + "crop free", + "display", + "edit", + "editing", + "enlarge", + "exit full screen", + "exit fullscreen", + "expand", + "focus", + "frame", + "free", + "full screen", + "fullscreen", + "image", + "lines", + "maximize", + "outline", + "photo", + "photos", + "picture", + "resize", + "select", + "selection", + "settings", + "size", + "square", + "ui", + "zoom" + ], + "popularity": 10836 + }, + "CROP_LANDSCAPE": { + "tags": [ + "adjust", + "adjustments", + "area", + "aspect ratio", + "border", + "crop", + "crop landscape", + "dimensions", + "edit", + "edit tool", + "editing", + "frame", + "framing", + "horizontal", + "image", + "image editing", + "images", + "landscape", + "landscape mode", + "media", + "media editing", + "modify", + "orientation", + "outline", + "photo", + "photo editing", + "photos", + "picture", + "picture editing", + "rectangle", + "rectangular", + "reframe", + "resize", + "settings", + "shape", + "size", + "tool", + "visual", + "wide ratio", + "wide screen" + ], + "popularity": 1881 + }, + "CROP_ORIGINAL": { + "tags": [ + "add", + "adjust", + "adjustments", + "album", + "area", + "asset", + "camera", + "collection", + "crop", + "display", + "edit", + "editing", + "editor", + "file", + "frame", + "gallery", + "graphic", + "image", + "images", + "import", + "insert", + "landscape", + "library", + "media", + "original", + "photo", + "photography", + "photos", + "picture", + "rectangle", + "restore", + "settings", + "size", + "square", + "upload", + "view", + "visual" + ], + "popularity": 6578 + }, + "CROP_PORTRAIT": { + "tags": [ + "adjust", + "adjustments", + "area", + "aspect ratio", + "crop", + "dimensions", + "edit", + "editing", + "editor", + "format", + "frame", + "framing", + "image", + "images", + "media", + "modify", + "photo", + "photography", + "photos", + "picture", + "portrait", + "rectangle", + "reframe", + "resize", + "settings", + "shape", + "size", + "square", + "tool" + ], + "popularity": 2635 + }, + "CROP_ROTATE": { + "tags": [ + "adjust", + "adjustments", + "area", + "arrow", + "arrows", + "aspect ratio", + "canvas", + "circle", + "clockwise", + "corners", + "counter-clockwise", + "crop", + "direction", + "edit", + "editing", + "frame", + "graphic", + "image", + "images", + "manipulate", + "modify", + "orientation", + "photo", + "photos", + "picture", + "rearrange", + "reorient", + "resize", + "rotate", + "settings", + "size", + "square", + "tool", + "transform", + "turn", + "visual" + ], + "popularity": 2310 + }, + "CROP_SQUARE": { + "tags": [ + "adjust", + "adjustments", + "app", + "application", + "area", + "area selection", + "aspect ratio", + "border", + "boundary", + "components", + "contract", + "crop", + "cut", + "design", + "edit", + "editing", + "editor", + "expand", + "extend", + "frame", + "framing", + "geometric", + "image", + "images", + "interface", + "manipulate", + "media", + "modify", + "open", + "photo", + "photos", + "picture", + "rectangle", + "resize", + "screen", + "settings", + "shape", + "shapes", + "shrink", + "site", + "size", + "square", + "square crop", + "tool", + "transform", + "trim", + "ui", + "ux", + "web", + "website", + "window" + ], + "popularity": 9903 + }, + "CRUELTY_FREE": { + "tags": [ + "animal", + "animal friendly", + "animal testing", + "animal welfare", + "beauty", + "bunny", + "care", + "cosmetics", + "cruelty", + "cruelty free", + "eco", + "ethical", + "ethical products", + "ethical shopping", + "free", + "humane", + "ingredients", + "jump", + "jumping", + "leaping", + "leaping bunny", + "nature", + "no animal testing", + "personal care", + "rabbit", + "responsible", + "social", + "sustainability", + "sustainable", + "testing", + "toiletries", + "vegan", + "vegetarian" + ], + "popularity": 7452 + }, + "CSS": { + "tags": [ + "alphabet", + "brackets", + "browser", + "cascading stylesheets", + "character", + "code", + "coding", + "computer language", + "computing", + "css", + "design", + "develop", + "developer", + "digital", + "engineer", + "engineering", + "font", + "frontend", + "html", + "internet", + "layout", + "letters", + "markup", + "platform", + "programming", + "programming language", + "software development", + "stylesheets", + "styling", + "symbol", + "technology", + "text", + "type", + "web code", + "web design", + "web development", + "web standards", + "website" + ], + "popularity": 2436 + }, + "CURRENCY_BITCOIN": { + "tags": [ + "bill", + "bitcoin", + "blockchain", + "card", + "cash", + "circle", + "coin", + "commerce", + "cost", + "credit", + "crypto", + "cryptocurrency", + "currency", + "digital", + "digital asset", + "digital currency", + "dollar", + "dollars", + "economics", + "finance", + "financial symbol", + "franc", + "investment", + "letter b", + "money", + "online", + "online payment", + "oval", + "pay", + "payment", + "price", + "shopping", + "stripes", + "symbol", + "trading", + "two lines", + "virtual currency", + "wealth" + ], + "popularity": 4366 + }, + "CURRENCY_EXCHANGE": { + "tags": [ + "360", + "around", + "arrow", + "arrows", + "banking", + "buy", + "cash", + "coin", + "commerce", + "conversion", + "convert", + "currency", + "currency exchange", + "direction", + "dollar", + "dollars", + "economy", + "euro", + "exchange", + "finance", + "financial", + "foreign exchange", + "forex", + "inprogress", + "international money", + "investment", + "left arrow", + "money", + "money transfer", + "pay", + "payment", + "pound", + "renew", + "right arrow", + "rotate", + "sell", + "swap", + "sync", + "trade", + "transaction", + "transfer", + "turn", + "universal", + "yen" + ], + "popularity": 23288 + }, + "CURRENCY_FRANC": { + "tags": [ + "banking", + "bill", + "budget", + "capital", + "card", + "cash", + "coin", + "commerce", + "cost", + "credit", + "currency", + "dollar", + "dollars", + "economic", + "euro", + "exchange", + "finance", + "financial", + "foreign", + "franc", + "global", + "income", + "international", + "investment", + "market", + "monetary", + "money", + "online", + "pay", + "payment", + "price", + "savings", + "shopping", + "swiss", + "symbol", + "trade", + "transaction", + "value", + "wealth" + ], + "popularity": 817 + }, + "CURRENCY_LIRA": { + "tags": [ + "bar", + "bill", + "buy", + "capital letter", + "card", + "cash", + "coin", + "commerce", + "cost", + "credit", + "currency", + "dollar", + "dollars", + "economic", + "economy", + "exchange", + "finance", + "financial", + "foreign currency", + "international currency", + "l", + "letter", + "lines", + "lira", + "money", + "online", + "pay", + "payment", + "price", + "sell", + "shopping", + "stack", + "stacked", + "symbol", + "t", + "three lines", + "tl symbol", + "transaction", + "turkish lira", + "value" + ], + "popularity": 1125 + }, + "CURRENCY_POUND": { + "tags": [ + "accounting", + "alphabet", + "banking", + "bill", + "british pound", + "budget", + "card", + "cash", + "coin", + "commerce", + "cost", + "credit", + "currency", + "dollar", + "dollars", + "economics", + "exchange", + "finance", + "financial", + "gbp", + "great britain", + "letter", + "money", + "online", + "pay", + "payment", + "pound", + "price", + "shopping", + "sign", + "sterling", + "symbol", + "transaction", + "typography", + "united kingdom", + "value", + "wealth" + ], + "popularity": 3344 + }, + "CURRENCY_RUBLE": { + "tags": [ + "banking", + "bill", + "billing", + "budget", + "business", + "card", + "cash", + "character", + "coin", + "commerce", + "cost", + "credit", + "currency", + "dollar", + "dollars", + "economy", + "exchange", + "fiat currency", + "finance", + "financial", + "foreign exchange", + "letter", + "money", + "online", + "pay", + "payment", + "payment methods", + "price", + "price tag", + "purchase", + "rate", + "rouble", + "ruble", + "russian currency", + "sale", + "shopping", + "symbol", + "trade", + "transaction" + ], + "popularity": 2386 + }, + "CURRENCY_RUPEE": { + "tags": [ + "bank", + "banking", + "bill", + "buy", + "card", + "cash", + "coin", + "commerce", + "cost", + "credit", + "currency", + "dollar", + "dollars", + "economic", + "economy", + "finance", + "financial", + "india", + "indian currency", + "indian money", + "indian rupee", + "investment", + "market", + "money", + "online", + "pay", + "payment", + "price", + "purchase", + "rupee", + "sell", + "shop", + "shopping", + "store", + "symbol", + "transaction", + "wealth" + ], + "popularity": 10887 + }, + "CURRENCY_YEN": { + "tags": [ + "bank", + "banking", + "bill", + "capital", + "card", + "cash", + "coin", + "commerce", + "cost", + "credit", + "currency", + "dollar", + "dollars", + "economic", + "exchange", + "finance", + "financial", + "income", + "japan", + "japanese", + "money", + "online", + "pay", + "payment", + "price", + "rate", + "shopping", + "sign", + "symbol", + "transaction", + "value", + "wealth", + "yen" + ], + "popularity": 4408 + }, + "CURRENCY_YUAN": { + "tags": [ + "banking", + "bill", + "business", + "buy", + "card", + "cash", + "character", + "china", + "chinese", + "coin", + "commerce", + "cost", + "credit", + "currency", + "dollar", + "dollars", + "economic", + "exchange", + "finance", + "financial", + "investment", + "money", + "online", + "pay", + "payment", + "price", + "renminbi", + "rmb", + "sell", + "shopping", + "sign", + "symbol", + "text", + "trade", + "transaction", + "type", + "value", + "yuan" + ], + "popularity": 1128 + }, + "CURTAINS": { + "tags": [ + "bedroom", + "blinds", + "closed", + "cover", + "curtains", + "decor", + "decoration", + "drapes", + "drawn", + "event", + "fabric", + "fold", + "home", + "house", + "interior", + "light", + "living room", + "nest", + "open", + "panel", + "pleated", + "privacy", + "residential", + "room", + "shade", + "show", + "shutter", + "soft", + "stage", + "sunshade", + "textile", + "theater", + "window", + "window covering" + ], + "popularity": 797 + }, + "CURTAINS_CLOSED": { + "tags": [ + "barrier", + "blinds", + "block", + "closed", + "cloth", + "cover", + "covering", + "curtains", + "darken", + "decor", + "divide", + "domestic", + "drapes", + "fabric", + "fold", + "hang", + "home", + "house", + "interior", + "light", + "nest", + "panel", + "privacy", + "room", + "shade", + "shades", + "shutter", + "soft", + "sunlight", + "sunshade", + "textile", + "wave", + "window" + ], + "popularity": 734 + }, + "CYCLONE": { + "tags": [ + "air", + "airflow", + "alert", + "atmosphere", + "chaos", + "circular motion", + "climate", + "crisis", + "cyclone", + "danger", + "destruction", + "disaster", + "dynamic", + "force", + "forecast", + "funnel", + "hurricane", + "movement", + "natural", + "natural disaster", + "nature", + "powerful", + "rain", + "spinning", + "spiral", + "storm", + "tornado", + "twister", + "vortex", + "warning", + "water", + "weather", + "weather icon", + "wind", + "winds", + "windstorm" + ], + "popularity": 1681 + }, + "DANGEROUS": { + "tags": [ + "alarming", + "alert", + "attention", + "be careful", + "broken", + "caution", + "critical", + "danger", + "dangerous", + "error", + "exclamation", + "fix", + "flag", + "forbidden", + "halt", + "hazard", + "important", + "issue", + "mark", + "no", + "note", + "notification", + "point", + "pointy", + "problem", + "restricted", + "risk", + "sharp", + "sign", + "stop", + "symbol", + "triangle", + "update", + "urgent", + "warning", + "watch out", + "wrong", + "x" + ], + "popularity": 22790 + }, + "DARK_MODE": { + "tags": [ + "accessibility", + "ambient", + "app", + "appearance", + "application", + "atmosphere", + "bedtime", + "circle", + "comfort", + "contrast", + "crescent", + "customization", + "dark", + "dark mode", + "darkness", + "device", + "display", + "element", + "evening", + "eye strain", + "graphic", + "interface", + "low light", + "mode", + "moon", + "night", + "part", + "personalization", + "settings", + "shape", + "silent", + "switch", + "theme", + "toggle", + "ui", + "ux", + "view", + "visual", + "website" + ], + "popularity": 51909 + }, + "DASHBOARD": { + "tags": [ + "add", + "administration", + "analytics", + "cards", + "chart", + "circle", + "control", + "dashboard", + "data", + "dial", + "display", + "format", + "gauge", + "graph", + "grid", + "indicator", + "layout", + "management", + "measurement", + "meter", + "metrics", + "monitor", + "needle", + "overview", + "panel", + "performance", + "plus", + "pointer", + "progress", + "rectangle", + "report", + "round", + "shapes", + "speed", + "speedometer", + "square", + "statistics", + "summary", + "tachometer", + "view", + "web", + "website" + ], + "popularity": 144072 + }, + "DASHBOARD_CUSTOMIZE": { + "tags": [ + "adjust", + "arrange", + "blocks", + "boxes", + "cards", + "change", + "configure", + "control", + "customize", + "dashboard", + "edit", + "format", + "grid", + "layout", + "management", + "modify", + "modules", + "options", + "organize", + "panel", + "personalize", + "preferences", + "rectangle", + "reorganize", + "settings", + "setup", + "shapes", + "square", + "squares", + "tailor", + "tiles", + "view", + "web", + "website", + "widget" + ], + "popularity": 24455 + }, + "DATA_ARRAY": { + "tags": [ + "array", + "block", + "brackets", + "code", + "coder", + "coding", + "collection", + "computer", + "data", + "data structure", + "developer", + "development", + "digital", + "document", + "file", + "grouping", + "hierarchy", + "information", + "it", + "list", + "organization", + "parentheses", + "programming", + "script", + "software", + "square brackets", + "structure", + "syntax", + "technical", + "technology" + ], + "popularity": 2192 + }, + "DATA_EXPLORATION": { + "tags": [ + "analysis", + "analytics", + "arrow", + "bi", + "business intelligence", + "chart", + "curve", + "dashboard", + "data", + "data exploration", + "data visualization", + "diagram", + "discovery", + "exploration", + "explore", + "graph", + "growth", + "increase", + "infographic", + "information", + "insight", + "investigate", + "knowledge", + "line", + "line graph", + "measure", + "metrics", + "report", + "research", + "statistics", + "study", + "tracking", + "trends", + "visualization" + ], + "popularity": 8348 + }, + "DATA_OBJECT": { + "tags": [ + "access", + "analytics", + "brackets", + "categorize", + "cloud", + "code", + "coder", + "columns", + "computing", + "data", + "data object", + "database", + "dataset", + "digital", + "document", + "engineering", + "file", + "filter", + "information", + "management", + "network", + "object", + "organization", + "organize", + "parentheses", + "query", + "record", + "retrieve", + "rows", + "science", + "server", + "sort", + "storage", + "structure", + "table", + "technology" + ], + "popularity": 6040 + }, + "DATA_SAVER_OFF": { + "tags": [ + "analytics", + "bar", + "bars", + "blocking", + "canceled", + "cellular", + "chart", + "configuration", + "connectivity", + "consumption", + "data", + "data saver off", + "data saving", + "data usage", + "denied", + "diagonal line", + "diagram", + "disabled", + "donut", + "graph", + "infographic", + "internet", + "limit", + "limitation", + "measure", + "metrics", + "mobile data", + "network", + "off", + "on", + "options", + "restricted", + "ring", + "saver", + "setting", + "slashed", + "statistics", + "strike through", + "switch", + "three lines", + "toggle", + "tracking", + "usage" + ], + "popularity": 3413 + }, + "DATA_SAVER_ON": { + "tags": [ + "+", + "active", + "add", + "analytics", + "arrow", + "bandwidth", + "bandwidth saver", + "chart", + "circle", + "connection", + "conserve data", + "data", + "data saver", + "data usage", + "diagram", + "direction", + "enabled", + "globe", + "graph", + "increase", + "infographic", + "internet", + "limit data", + "map", + "measure", + "metrics", + "mobile data", + "network", + "network data", + "new", + "on", + "plus", + "polygon", + "reduce data", + "ring", + "saver", + "savings", + "sphere", + "statistics", + "symbol", + "tracking", + "triangle", + "up arrow", + "world" + ], + "popularity": 3263 + }, + "DATA_THRESHOLDING": { + "tags": [ + "analysis", + "chart", + "configuration", + "controls", + "criteria", + "data", + "data analysis", + "data control", + "data filter", + "data limits", + "data management", + "data points", + "data range", + "data representation", + "data selection", + "data settings", + "data thresholding", + "evaluation", + "filter", + "graph", + "hidden", + "limits", + "measurement", + "metrics", + "parameters", + "privacy", + "range", + "selection", + "settings", + "statistics", + "threshold", + "thresholding", + "thresold", + "visualization" + ], + "popularity": 2903 + }, + "DATA_USAGE": { + "tags": [ + "analytics", + "blocking", + "canceled", + "cellular", + "chart", + "configuration", + "connectivity", + "consumption", + "data", + "data saver off", + "data saving", + "data usage", + "denied", + "diagonal line", + "diagram", + "disabled", + "graph", + "infographic", + "internet", + "limit", + "limitation", + "measure", + "metrics", + "mobile data", + "network", + "off", + "options", + "restricted", + "setting", + "slashed", + "statistics", + "strike through", + "switch", + "three lines", + "toggle", + "tracking", + "usage" + ], + "popularity": 7655 + }, + "DATASET": { + "tags": [ + "archive", + "cloud", + "collection", + "columns", + "data", + "data entry", + "data management", + "database", + "dataset", + "digital", + "digital data", + "document", + "electronic data", + "entry", + "file", + "flat data", + "grid", + "information", + "list", + "management", + "organized data", + "record", + "records", + "rows", + "server", + "spreadsheet", + "storage", + "structured data", + "table" + ], + "popularity": 2389 + }, + "DATASET_LINKED": { + "tags": [ + "browser", + "chain", + "chain link", + "connect", + "connected", + "connection", + "data", + "document", + "external link", + "file", + "hyperlink", + "internet", + "link", + "navigation", + "network", + "new tab", + "online", + "open", + "outside", + "redirect", + "share", + "sharing", + "social media", + "url", + "web", + "web link", + "website", + "window", + "world wide web", + "wwww" + ], + "popularity": 1315 + }, + "DATE_RANGE": { + "tags": [ + "agenda", + "appointment", + "booking", + "calendar", + "calendar grid", + "calendar picker", + "calendar view", + "choose date", + "date", + "date selection", + "day", + "deadline", + "event", + "lines", + "month", + "period", + "planner", + "range", + "rectangle", + "remember", + "reminder", + "reservation", + "schedule", + "select date", + "square", + "time", + "timeline", + "today", + "week", + "year" + ], + "popularity": 107531 + }, + "DEBLUR": { + "tags": [ + "adjust", + "adjustment", + "application", + "button", + "clarity", + "contrast", + "control", + "correction", + "deblur", + "detail", + "edit", + "editing", + "effect", + "enhance", + "face", + "filter", + "focus", + "graphic", + "horizontal lines", + "image", + "lines", + "photo", + "photography", + "sharpen", + "software", + "squiggly lines", + "straight lines", + "tool", + "visual", + "waves" + ], + "popularity": 1284 + }, + "DECK": { + "tags": [ + "aligned", + "angled", + "bridge", + "cards", + "cards deck", + "chairs", + "collection", + "deck", + "deck of cards", + "depth", + "diagonal", + "entertainment", + "gambling", + "game", + "group", + "home", + "house", + "layered", + "layered squares", + "layers", + "multiple", + "organized", + "outdoors", + "outside", + "overlapping", + "patio", + "perspective", + "pile", + "playing cards", + "poker", + "rectangle", + "set", + "social", + "solitaire", + "square", + "stack", + "terrace", + "umbrella", + "yard" + ], + "popularity": 5789 + }, + "DEHAZE": { + "tags": [ + "adjust", + "adjustments", + "air", + "atmospheric", + "clarity", + "clear", + "dehaze", + "edit", + "editing", + "effect", + "enhance", + "filter", + "fog", + "forecast", + "graphic", + "hamburger menu", + "haze", + "icon", + "image", + "lines", + "menu", + "photo", + "photography", + "pictogram", + "picture", + "remove", + "sharpen", + "sky", + "symbol", + "unfog", + "visibility", + "vision", + "weather" + ], + "popularity": 6648 + }, + "DELETE": { + "tags": [ + "action", + "basket", + "bin", + "can", + "cancel", + "clean up", + "clear", + "control", + "delete", + "delete content", + "delete file", + "destroy", + "discard", + "dispose", + "dustbin", + "edit", + "eliminate", + "empty", + "erase", + "garbage", + "get rid of", + "junk", + "management", + "obliterate", + "outline", + "recycle", + "remove", + "remove item", + "trash", + "waste" + ], + "popularity": 387752 + }, + "DELETE_FOREVER": { + "tags": [ + "action", + "archive", + "bin", + "button", + "can", + "cancel", + "clean", + "clear", + "clear all", + "control", + "delete", + "delete forever", + "destroy", + "discard", + "dispose", + "eliminate", + "erase", + "exit", + "forever", + "garbage", + "get rid of", + "glyph", + "icon", + "interface", + "management", + "obliterate", + "purge", + "remove", + "storage", + "sweep", + "symbol", + "trash", + "wipe out", + "x", + "zero out" + ], + "popularity": 69832 + }, + "DELETE_OUTLINE": { + "tags": [ + "action", + "basket", + "bin", + "can", + "cancel", + "clean up", + "clear", + "control", + "delete", + "delete content", + "delete file", + "destroy", + "discard", + "dispose", + "dustbin", + "edit", + "eliminate", + "empty", + "erase", + "garbage", + "get rid of", + "junk", + "management", + "obliterate", + "outline", + "recycle", + "remove", + "remove item", + "trash", + "waste" + ], + "popularity": 91813 + }, + "DELETE_SWEEP": { + "tags": [ + "batch delete", + "batch remove", + "bin", + "broom", + "bulk delete", + "bulk remove", + "can", + "clean", + "clear", + "clear all", + "delete", + "delete sweep", + "discard", + "disposal", + "eliminate", + "empty", + "erase", + "garbage", + "mass delete", + "mass remove", + "multiple delete", + "multiple remove", + "obliterate", + "permanently delete", + "remove", + "remove all", + "sweep", + "trash", + "waste", + "wipe" + ], + "popularity": 13356 + }, + "DELIVERY_DINING": { + "tags": [ + "buy", + "commerce", + "courier", + "delivery", + "dining", + "dispatch", + "driving", + "drop off", + "fast", + "food", + "line icon", + "logistics", + "meal", + "moped", + "motorcycle", + "movement", + "order", + "pick up", + "purchase", + "quick", + "restaurant", + "riding", + "scooter", + "service", + "shipping", + "shop", + "store", + "takeout", + "transport", + "transportation", + "travel", + "two-wheeled", + "urban", + "vehicle", + "vespa" + ], + "popularity": 17022 + }, + "DENSITY_LARGE": { + "tags": [ + "bars", + "block", + "collapse", + "density", + "density large", + "display", + "expand", + "horizontal", + "items", + "large", + "layout", + "lines", + "list", + "menu", + "more space", + "options", + "parallel", + "rows", + "rule", + "rules", + "settings", + "size", + "spacing", + "thick", + "thick lines", + "thickness", + "three bars", + "three lines", + "view", + "wide lines" + ], + "popularity": 1483 + }, + "DENSITY_MEDIUM": { + "tags": [ + "adjust", + "arrangement", + "bars", + "compact", + "content density", + "default", + "density", + "density medium", + "display", + "horizontal", + "layout", + "line spacing", + "lines", + "list", + "medium", + "medium spacing", + "menu", + "options", + "paragraph spacing", + "parallel", + "preference", + "rule", + "rules", + "setting", + "spacing", + "text density", + "three lines", + "typography", + "view" + ], + "popularity": 7294 + }, + "DENSITY_SMALL": { + "tags": [ + "compact", + "condensed", + "dense", + "density", + "horizontal", + "horizontal lines", + "layout", + "less", + "lines", + "list", + "menu", + "minimal", + "more density", + "narrow", + "options", + "reduced", + "rows", + "rule", + "rules", + "small", + "small density", + "spacing", + "three lines", + "tight", + "tight spacing", + "view" + ], + "popularity": 2961 + }, + "DEPARTURE_BOARD": { + "tags": [ + "airport", + "arrival board", + "arrivals", + "automobile", + "board", + "bus", + "bus station", + "car", + "cars", + "clock", + "data", + "departure", + "departure board", + "departures", + "destinations", + "display", + "information board", + "itinerary", + "journeys", + "lines", + "list", + "maps", + "public", + "public transit", + "rectangle", + "rows", + "schedule", + "sign", + "status", + "terminal", + "time", + "time table", + "train station", + "transit", + "transportation", + "travel", + "updates", + "vehicle" + ], + "popularity": 5256 + }, + "DESCRIPTION": { + "tags": [ + "article", + "attributes", + "content", + "data", + "description", + "details", + "doc", + "document", + "drive", + "explore", + "file", + "find", + "folder", + "folders", + "information", + "inspect", + "list", + "lookup", + "magnify", + "magnifying glass", + "metadata", + "note", + "notes", + "open", + "page", + "paper", + "readme", + "search", + "sheet", + "slide", + "text", + "view", + "writing", + "zoom" + ], + "popularity": 268075 + }, + "DESELECT": { + "tags": [ + "all", + "blank", + "box", + "cancel", + "checkbox", + "choices", + "clear", + "delete", + "deselect", + "disable", + "disabled", + "empty", + "enabled", + "erase", + "none", + "null", + "off", + "on", + "options", + "outline", + "remove", + "reset", + "selection", + "slash", + "square", + "toggle off", + "tool", + "uncheck", + "unchecked", + "undo", + "unmark", + "untick", + "void" + ], + "popularity": 1981 + }, + "DESIGN_SERVICES": { + "tags": [ + "architecture", + "art", + "build", + "compose", + "create", + "design", + "draft", + "drafting", + "draw", + "drawing", + "edit", + "editing", + "education", + "engineering", + "geometry", + "graphic", + "illustration", + "implements", + "input", + "instrument", + "learn", + "line", + "measure", + "object", + "office", + "pen", + "pencil", + "ruler", + "school", + "service", + "services", + "shape", + "sketch", + "stationery", + "tools", + "triangle", + "work", + "write", + "writing" + ], + "popularity": 18085 + }, + "DESK": { + "tags": [ + "business", + "computer desk", + "desk", + "education", + "equipment", + "flat surface", + "four legs", + "furniture", + "home office", + "indoor", + "interior", + "learning", + "line art", + "minimal", + "object", + "office", + "organization", + "planning", + "productivity", + "rectangular", + "silhouette", + "simple", + "storage", + "study", + "table", + "work", + "workspace" + ], + "popularity": 831 + }, + "DESKTOP_ACCESS_DISABLED": { + "tags": [ + "access", + "android", + "barring", + "blocked", + "cancellation", + "chrome", + "computer", + "connection", + "denied", + "desktop", + "device", + "diagonal line", + "disabled", + "disconnected", + "display", + "electronic", + "enabled", + "forbidden", + "hardware", + "hindering", + "ios", + "mac", + "monitor", + "no", + "obstruction", + "off", + "offline", + "on", + "os", + "panel", + "prohibition", + "restricted", + "restriction", + "screen", + "slash", + "technology", + "unavailable", + "web", + "window" + ], + "popularity": 2508 + }, + "DESKTOP_MAC": { + "tags": [ + "all-in-one", + "android", + "base", + "chrome", + "computer", + "computing", + "desktop", + "device", + "digital", + "display", + "electronic", + "hardware", + "home", + "imac", + "ios", + "mac", + "macintosh", + "modern", + "monitor", + "office", + "os", + "pc", + "personal computer", + "rectangle", + "screen", + "setup", + "stand", + "technology", + "web", + "window", + "work", + "workstation" + ], + "popularity": 7118 + }, + "DESKTOP_WINDOWS": { + "tags": [ + "android", + "cast", + "chrome", + "computer", + "desktop", + "device", + "digital", + "display", + "electronic", + "hardware", + "home", + "ios", + "mac", + "mirroring", + "monitor", + "office", + "os", + "pc", + "presentation", + "rectangular", + "remote", + "screen", + "sharing", + "technology", + "television", + "tv", + "web", + "window", + "windows", + "work", + "workstation" + ], + "popularity": 30625 + }, + "DETAILS": { + "tags": [ + "additional", + "data", + "data icon", + "detail", + "details", + "dots", + "edit", + "editing", + "ellipsis", + "enhance", + "expand", + "expand details", + "explore", + "extra", + "further details", + "horizontal dots", + "image", + "information", + "information icon", + "menu", + "menu icon", + "more", + "more menu", + "open", + "options", + "options icon", + "overflow icon", + "overflow menu", + "photo", + "photography", + "reveal", + "settings", + "settings icon", + "sharpen", + "show more", + "three dot menu", + "three dots", + "triangle", + "view" + ], + "popularity": 5588 + }, + "DEVELOPER_BOARD": { + "tags": [ + "board", + "build", + "chip", + "circuit board", + "code", + "coding", + "component", + "computer", + "computing", + "cpu", + "developer", + "developer board", + "development", + "development board", + "development tool", + "electronic board", + "electronics", + "engineering", + "hardware", + "integrated circuit", + "mainboard", + "microchip", + "motherboard", + "pcb", + "processor", + "programming", + "prototype", + "server", + "tech", + "tech board", + "technology", + "technology board", + "test" + ], + "popularity": 10836 + }, + "DEVELOPER_BOARD_OFF": { + "tags": [ + "board", + "chip", + "circuit", + "circuit board", + "component", + "computer", + "cross", + "developer", + "developer board", + "development", + "device", + "disable", + "disabled", + "disconnected", + "electronic", + "electronics", + "enabled", + "error", + "hardware", + "inactive", + "integrated circuit", + "microchip", + "no entry", + "not connected", + "off", + "on", + "processor", + "programming", + "slash", + "stop", + "technology", + "unavailable", + "warning" + ], + "popularity": 1198 + }, + "DEVELOPER_MODE": { + "tags": [ + "advanced settings", + "android", + "angle bracket", + "bracket", + "cell", + "code", + "coding", + "command line", + "computer science", + "developer", + "developer mode", + "developer options", + "development", + "device", + "engineer", + "engineering", + "greater than", + "hardware", + "ios", + "it", + "left bracket", + "less than", + "mobile", + "mobile code", + "mode", + "os", + "phone", + "programming", + "right bracket", + "settings", + "smartphone", + "software", + "tablet", + "technical", + "technology", + "terminal" + ], + "popularity": 6970 + }, + "DEVICE_HUB": { + "tags": [ + "android", + "architecture", + "center", + "central point", + "circle", + "computer", + "configuration", + "connected devices", + "connection", + "connection points", + "connections", + "control", + "desktop", + "device", + "device hub", + "diagram", + "digital", + "hardware", + "hub", + "infrastructure", + "internet of things", + "ios", + "iot", + "laptop", + "lines", + "links", + "management", + "map", + "mobile", + "monitor", + "network", + "networking", + "nodes", + "os", + "phone", + "points", + "settings", + "smart home", + "square", + "system", + "tablet", + "technology", + "triangle", + "watch", + "wearable", + "web" + ], + "popularity": 8604 + }, + "DEVICE_THERMOSTAT": { + "tags": [ + "adjust", + "automation", + "celsius", + "circle", + "climate", + "comfort", + "control", + "cooling", + "device", + "dial", + "energy", + "environment", + "fahrenheit", + "gauge", + "heating", + "home automation", + "hvac", + "indicator", + "instrument", + "lines", + "measure", + "meter", + "monitor", + "regulator", + "settings", + "smart home", + "system", + "temp", + "temperature", + "thermometer", + "thermostat", + "weather" + ], + "popularity": 8175 + }, + "DEVICE_UNKNOWN": { + "tags": [ + "?", + "android", + "assistance", + "cell", + "communication", + "connection", + "device", + "digital", + "electronic", + "glyph", + "handheld", + "hardware", + "help", + "icon", + "info", + "information", + "inquiry", + "ios", + "issue", + "mobile", + "os", + "outline", + "phone", + "portable", + "punctuation", + "query", + "question", + "question mark", + "rectangular", + "screen", + "status", + "support", + "symbol", + "tablet", + "technical", + "troubleshoot", + "unknown" + ], + "popularity": 3285 + }, + "DEVICES": { + "tags": [ + "android", + "cast", + "communication", + "computer", + "connect", + "connection", + "connectivity", + "data transfer", + "desktop", + "device", + "devices", + "display", + "hardware", + "ios", + "laptop", + "link", + "mobile", + "monitor", + "multiple devices", + "network", + "os", + "phone", + "remote control", + "screen", + "screen mirroring", + "sharing", + "smartphone", + "streaming", + "sync", + "synchronize", + "tablet", + "technology", + "transfer", + "watch", + "wearable", + "web" + ], + "popularity": 33842 + }, + "DEVICES_FOLD": { + "tags": [ + "android", + "cell", + "closed", + "computer", + "dash", + "dashed", + "device", + "display", + "dual screen", + "electronic", + "expanding", + "flexible", + "fold", + "foldable", + "gadget", + "hardware", + "hinge", + "ios", + "landscape", + "laptop", + "layout", + "media", + "mobile", + "monitor", + "open", + "orientation", + "os", + "panel", + "phone", + "portrait", + "screen", + "smartphone", + "tablet", + "technology", + "transform", + "unfold", + "view" + ], + "popularity": 728 + }, + "DEVICES_OTHER": { + "tags": [ + "android", + "ar", + "audio", + "casting", + "casting devices", + "cell", + "chrome", + "communication", + "computer", + "connection", + "connectivity", + "desktop", + "device", + "devices", + "digital", + "display", + "electronics", + "gadget", + "gadgets", + "hardware", + "ios", + "ipad", + "mac", + "media", + "mirroring", + "mobile", + "monitor", + "multiple devices", + "network", + "os", + "other", + "other devices", + "peripherals", + "phone", + "screen", + "screensharing", + "smart devices", + "sync", + "tablet", + "technology", + "video", + "virtual_reality", + "vr", + "watch", + "wearables", + "window" + ], + "popularity": 6693 + }, + "DIALER_SIP": { + "tags": [ + "alphabet", + "button", + "call", + "call icon", + "cell", + "character", + "communication", + "communication icon", + "connection", + "contact", + "device", + "dial", + "dialer", + "font", + "hardware", + "icon", + "initiation", + "internet", + "internet icon", + "ip", + "letters", + "line", + "mobile", + "network", + "network icon", + "outline", + "over", + "phone", + "phone icon", + "protocol", + "routing", + "session", + "sip", + "sip call", + "square", + "symbol", + "telephone", + "telephone icon", + "text", + "type", + "voice", + "voip", + "voip call" + ], + "popularity": 1979 + }, + "DIALPAD": { + "tags": [ + "button", + "buttons", + "call", + "communication", + "contact", + "control", + "device", + "dial", + "dialing", + "dialpad", + "digit", + "dots", + "entering numbers", + "grid", + "grid layout", + "input", + "interactive", + "keypad", + "landline", + "layout", + "matrix", + "mobile", + "number", + "numbers", + "numeric", + "pad", + "phone", + "rectangle", + "smartphone", + "square", + "telecommunications", + "telephone", + "ten keys" + ], + "popularity": 9885 + }, + "DIAMOND": { + "tags": [ + "award", + "brilliant", + "clean", + "crystal", + "cut", + "diamond", + "exclusive", + "expensive", + "facet", + "fashion", + "gem", + "gems", + "geometric", + "jewel", + "jewelry", + "logo", + "luxury", + "pointed", + "polygon", + "precious", + "premium", + "prize", + "quality", + "retail", + "shape", + "sharp", + "simple", + "special", + "stone", + "valuable", + "valuables", + "value" + ], + "popularity": 13559 + }, + "DIFFERENCE": { + "tags": [ + "choice", + "compare", + "content", + "contrast", + "copy", + "cut", + "diff", + "difference", + "doc", + "document", + "duplicate", + "file", + "layers", + "multiple", + "options", + "overlay", + "past", + "selection", + "split", + "stack", + "variations", + "versions" + ], + "popularity": 4363 + }, + "DINING": { + "tags": [ + "beverage", + "bistro", + "breakfast", + "cafe", + "cafeteria", + "canteen", + "cuisine", + "cutlery", + "diner", + "dining", + "dinner", + "drink", + "eat", + "eating", + "fine dining", + "food", + "fork", + "hunger", + "kitchen", + "knife", + "lunch", + "meal", + "nourish", + "plateware", + "restaurant", + "room", + "satisfy", + "service", + "serving", + "silverware", + "spoon", + "table", + "taste" + ], + "popularity": 5378 + }, + "DINNER_DINING": { + "tags": [ + "beverage", + "breakfast", + "cafe", + "cooking", + "cuisine", + "culinary", + "cutlery", + "dining", + "dining room", + "dinner", + "drink", + "eat", + "eating", + "fine dining", + "food", + "fork", + "gourmet", + "kitchen", + "knife", + "lunch", + "meal", + "menu", + "pasta", + "place setting", + "reservation", + "restaurant", + "serving", + "silverware", + "snack", + "spaghetti", + "table", + "utensils" + ], + "popularity": 6636 + }, + "DIRECTIONS": { + "tags": [ + "address", + "arrow", + "compass", + "course", + "destination", + "directions", + "exploring", + "finding", + "gps", + "guidance", + "guide", + "itinerary", + "journey", + "locate", + "location", + "map", + "maps", + "mobility", + "move", + "moving", + "navigation", + "path", + "position", + "right", + "roadmap", + "route", + "sign", + "street", + "traffic", + "transport", + "travel", + "turn", + "wayfinding" + ], + "popularity": 11471 + }, + "DIRECTIONS_BIKE": { + "tags": [ + "activity", + "bicycle", + "bike", + "cycling", + "direction", + "directions", + "exercise", + "fitness", + "green transport", + "health", + "human", + "journey", + "map", + "maps", + "mobility", + "navigation", + "outdoor", + "path", + "person", + "public", + "recreation", + "ride", + "riding", + "road", + "route", + "sport", + "street", + "transport", + "transportation", + "travel", + "two wheels", + "urban", + "vehicle", + "workout" + ], + "popularity": 15552 + }, + "DIRECTIONS_BOAT": { + "tags": [ + "automobile", + "boat", + "boating", + "car", + "cars", + "cruise", + "direction", + "directions", + "ferry", + "journey", + "lake", + "maps", + "marine", + "maritime", + "nautical", + "navigation", + "ocean", + "path", + "public", + "recreation", + "river", + "route", + "sailing", + "sea", + "ship", + "tourism", + "transport", + "transportation", + "travel", + "trip", + "vehicle", + "vessel", + "water" + ], + "popularity": 10643 + }, + "DIRECTIONS_BOAT_FILLED": { + "tags": [ + "automobile", + "boat", + "boating", + "car", + "cars", + "cruise", + "direction", + "directions", + "ferry", + "journey", + "lake", + "maps", + "marine", + "maritime", + "nautical", + "navigation", + "ocean", + "path", + "public", + "recreation", + "river", + "route", + "sailing", + "sea", + "ship", + "tourism", + "transport", + "transportation", + "travel", + "trip", + "vehicle", + "vessel", + "water" + ], + "popularity": 3618 + }, + "DIRECTIONS_BUS": { + "tags": [ + "automobile", + "bus", + "car", + "cars", + "commute", + "directions", + "filled", + "journey", + "maps", + "navigation", + "passenger", + "public", + "public transport", + "rectangle", + "ride", + "road", + "rounded corners", + "route", + "solid", + "street", + "transportation", + "travel", + "vehicle", + "wheel", + "window" + ], + "popularity": 18741 + }, + "DIRECTIONS_BUS_FILLED": { + "tags": [ + "automobile", + "bus", + "car", + "cars", + "commute", + "directions", + "filled", + "journey", + "maps", + "navigation", + "passenger", + "public", + "public transport", + "rectangle", + "ride", + "road", + "rounded corners", + "route", + "solid", + "street", + "transportation", + "travel", + "vehicle", + "wheel", + "window" + ], + "popularity": 7553 + }, + "DIRECTIONS_CAR": { + "tags": [ + "auto", + "automobile", + "automotive", + "car", + "car symbol", + "cars", + "destination", + "direction", + "directions", + "drive", + "drive time", + "driving", + "estimated time", + "eta", + "journey", + "maps", + "mobility", + "navigate", + "navigation", + "passenger vehicle", + "public", + "road", + "route", + "sedan", + "time", + "transport", + "transport symbol", + "transportation", + "travel", + "travel time", + "trip", + "vehicle", + "vehicle icon" + ], + "popularity": 44572 + }, + "DIRECTIONS_CAR_FILLED": { + "tags": [ + "auto", + "automobile", + "automotive", + "car", + "car symbol", + "cars", + "destination", + "direction", + "directions", + "drive", + "drive time", + "driving", + "estimated time", + "eta", + "journey", + "maps", + "mobility", + "navigate", + "navigation", + "passenger vehicle", + "public", + "road", + "route", + "sedan", + "time", + "transport", + "transport symbol", + "transportation", + "travel", + "travel time", + "trip", + "vehicle", + "vehicle icon" + ], + "popularity": 15384 + }, + "DIRECTIONS_OFF": { + "tags": [ + "arrow", + "blocked", + "cancel", + "circle with slash", + "clear route", + "close", + "cross out", + "denied", + "directions", + "directions off", + "disable directions", + "disabled", + "enabled", + "end", + "forbidden", + "gps off", + "guidance off", + "line with slash", + "location off", + "map off", + "maps", + "navigation off", + "no entry", + "not allowed", + "off", + "on", + "path off", + "prohibited", + "remove route", + "right", + "route", + "route off", + "sign", + "slash", + "stop", + "stop navigation", + "traffic", + "travel off", + "turn off", + "x mark" + ], + "popularity": 1064 + }, + "DIRECTIONS_RAILWAY": { + "tags": [ + "automobile", + "car", + "cars", + "commuter", + "commuting", + "direction", + "directions", + "express", + "journey", + "light rail", + "locomotive", + "map", + "maps", + "metro", + "navigation", + "passenger", + "platform", + "public", + "public transport", + "rail", + "railroad", + "rails", + "railway", + "route", + "station", + "subway", + "track", + "train", + "tram", + "transit", + "transport", + "transportation", + "travel", + "trip", + "trolley", + "vehicle" + ], + "popularity": 1811 + }, + "DIRECTIONS_RAILWAY_FILLED": { + "tags": [ + "automobile", + "car", + "cars", + "commuter", + "commuting", + "direction", + "directions", + "express", + "journey", + "light rail", + "locomotive", + "map", + "maps", + "metro", + "navigation", + "passenger", + "platform", + "public", + "public transport", + "rail", + "railroad", + "rails", + "railway", + "route", + "station", + "subway", + "track", + "train", + "tram", + "transit", + "transport", + "transportation", + "travel", + "trip", + "trolley", + "vehicle" + ], + "popularity": 1225 + }, + "DIRECTIONS_RUN": { + "tags": [ + "activity", + "athlete", + "beginning", + "body", + "destination", + "directions", + "exercise", + "figure", + "fitness", + "human", + "jogging", + "location", + "map", + "maps", + "marathon", + "movement", + "navigation", + "path", + "people", + "person", + "pin", + "point", + "race", + "route", + "run", + "running", + "silhouette", + "sports", + "sprint", + "start", + "track", + "training", + "walk", + "walking" + ], + "popularity": 27056 + }, + "DIRECTIONS_SUBWAY": { + "tags": [ + "automobile", + "car", + "cars", + "city", + "commute", + "connection", + "destination", + "direction", + "directions", + "journey", + "line", + "locomotion", + "maps", + "metro", + "movement", + "navigation", + "passengers", + "path", + "public", + "public transportation", + "rail", + "railway", + "route", + "station", + "subway", + "system", + "train", + "tram", + "transit", + "transport", + "transportation", + "travel", + "trolley", + "underground", + "urban", + "vehicle" + ], + "popularity": 2103 + }, + "DIRECTIONS_SUBWAY_FILLED": { + "tags": [ + "automobile", + "car", + "cars", + "city", + "commute", + "connection", + "destination", + "direction", + "directions", + "journey", + "line", + "locomotion", + "maps", + "metro", + "movement", + "navigation", + "passengers", + "path", + "public", + "public transportation", + "rail", + "railway", + "route", + "station", + "subway", + "system", + "train", + "tram", + "transit", + "transport", + "transportation", + "travel", + "trolley", + "underground", + "urban", + "vehicle" + ], + "popularity": 1270 + }, + "DIRECTIONS_TRANSIT": { + "tags": [ + "automobile", + "car", + "cars", + "city", + "commute", + "connection", + "destination", + "direction", + "directions", + "journey", + "line", + "locomotion", + "maps", + "metro", + "movement", + "navigation", + "passengers", + "path", + "public", + "public transportation", + "rail", + "railway", + "route", + "station", + "subway", + "system", + "train", + "tram", + "transit", + "transport", + "transportation", + "travel", + "trolley", + "underground", + "urban", + "vehicle" + ], + "popularity": 2760 + }, + "DIRECTIONS_TRANSIT_FILLED": { + "tags": [ + "automobile", + "car", + "cars", + "city", + "commute", + "connection", + "destination", + "direction", + "directions", + "journey", + "line", + "locomotion", + "maps", + "metro", + "movement", + "navigation", + "passengers", + "path", + "public", + "public transportation", + "rail", + "railway", + "route", + "station", + "subway", + "system", + "train", + "tram", + "transit", + "transport", + "transportation", + "travel", + "trolley", + "underground", + "urban", + "vehicle" + ], + "popularity": 1380 + }, + "DIRECTIONS_WALK": { + "tags": [ + "activity", + "assist", + "body", + "direction", + "directions", + "exercise", + "figure", + "find", + "fitness", + "foot", + "go", + "guide", + "human", + "jogging", + "journey", + "lead", + "locate", + "map", + "maps", + "move", + "movement", + "navigation", + "outdoor", + "path", + "pedestrian", + "people", + "person", + "point a to point b", + "route", + "run", + "steps", + "stick figure", + "travel", + "walk", + "walking" + ], + "popularity": 22915 + }, + "DIRTY_LENS": { + "tags": [ + "alert", + "blurred", + "camera", + "capture", + "circle", + "cleaning", + "dirt", + "dirty", + "equipment", + "focus", + "image", + "issue", + "lens", + "maintenance", + "media", + "notification", + "object", + "obscured", + "optical", + "outline", + "photo", + "photography", + "picture", + "problem", + "smudge", + "splat", + "spot", + "stain", + "unclear", + "warning" + ], + "popularity": 1178 + }, + "DISABLED_BY_DEFAULT": { + "tags": [ + "access denied", + "alert", + "blocked", + "box", + "by", + "cancel", + "caution", + "clear", + "close", + "cross", + "default", + "denied", + "diagonal", + "disabled", + "error", + "exit", + "failure", + "forbidden", + "inactive", + "indicator", + "invalid", + "issue", + "line", + "no", + "not allowed", + "off", + "problem", + "quit", + "rejected", + "remove", + "restricted", + "shape", + "square", + "state", + "status", + "stop", + "symbol", + "ui control", + "unavailable", + "warning", + "x" + ], + "popularity": 20939 + }, + "DISABLED_VISIBLE": { + "tags": [ + "accessibility", + "block view", + "cancel", + "close", + "control", + "disabled", + "excluded", + "exit", + "eye", + "eye crossed out", + "eye with line", + "hidden", + "hide", + "inactive", + "invisible", + "look", + "no", + "no view", + "not visible", + "obscured", + "off", + "on", + "privacy", + "private", + "quit", + "remove", + "restricted", + "reveal", + "secret", + "security", + "see", + "show", + "slashed eye", + "stop", + "unavailable", + "view", + "visibility", + "visible" + ], + "popularity": 5953 + }, + "DISC_FULL": { + "tags": [ + "!", + "album", + "alert", + "analog", + "attention", + "audio", + "backup", + "capacity", + "caution", + "cd", + "circle", + "computer", + "danger", + "data", + "digital", + "disc", + "drive", + "dvd", + "entertainment", + "error", + "exclamation", + "file", + "full", + "important", + "mark", + "media", + "media player", + "memory", + "music", + "notification", + "record", + "retro", + "sound", + "space", + "storage", + "symbol", + "technology", + "vintage", + "warning" + ], + "popularity": 1961 + }, + "DISCOUNT": { + "tags": [], + "popularity": 8368 + }, + "DISPLAY_SETTINGS": { + "tags": [ + "adjustments", + "android", + "application", + "brightness", + "change", + "chrome", + "cog", + "computer", + "configuration", + "contrast", + "control", + "customization", + "desktop", + "details", + "device", + "display", + "display adjustments", + "display control", + "electronic", + "gear", + "hardware", + "info", + "information", + "ios", + "mac", + "monitor", + "monitor settings", + "options", + "os", + "panel", + "personal", + "preferences", + "resolution", + "screen", + "screen options", + "screen settings", + "service", + "settings", + "setup", + "technology", + "web", + "window" + ], + "popularity": 6098 + }, + "DIVERSITY_1": { + "tags": [ + "account", + "avatar", + "characters", + "circle", + "collaboration", + "collective", + "committee", + "community", + "crowd", + "diverse", + "diversity", + "faces", + "family", + "figures", + "friends", + "group", + "groups", + "head", + "heart", + "humans", + "identity", + "inclusion", + "individuals", + "multiple", + "network", + "people", + "person", + "persons", + "population", + "profile", + "representation", + "silhouette", + "social", + "team", + "team building", + "together", + "users" + ], + "popularity": 7012 + }, + "DIVERSITY_2": { + "tags": [ + "avatars", + "collaboration", + "committee", + "community", + "diverse", + "diversity", + "equal", + "equality", + "faces", + "family", + "figures", + "friends", + "group", + "groups", + "heads", + "heart", + "human", + "humans", + "inclusion", + "interconnected", + "multicultural", + "multiracial", + "network", + "outlines", + "people", + "persons", + "population", + "profiles", + "relationships", + "representation", + "shapes", + "social", + "team", + "together", + "users", + "variety" + ], + "popularity": 4490 + }, + "DIVERSITY_3": { + "tags": [ + "committee", + "community", + "community icon", + "crowd", + "culture", + "different", + "different people", + "diverse", + "diversity", + "diversity icon", + "ethnicity", + "family", + "friends", + "group", + "group icon", + "groups", + "humans", + "inclusion", + "mixed", + "network", + "people", + "people icon", + "persons", + "profile", + "social", + "team", + "team members", + "user group", + "users", + "users icon", + "varied" + ], + "popularity": 10306 + }, + "DNS": { + "tags": [ + "abstract", + "address", + "administration", + "bars", + "circles", + "communication", + "configuration", + "connection", + "data", + "dns", + "domain", + "domain name system", + "dots", + "globe", + "hostname", + "information", + "internet", + "ip", + "ip address", + "list", + "lookup", + "name", + "network", + "resolution", + "server", + "settings", + "symbol", + "system", + "technology", + "url", + "website", + "world" + ], + "popularity": 34517 + }, + "DO_DISTURB": { + "tags": [ + "alert", + "ban", + "block", + "cancel", + "circle", + "close", + "control", + "denied", + "deny", + "diagonal", + "disable", + "disturb", + "do", + "do not disturb", + "exclude", + "forbidden", + "interrupt", + "limit", + "line", + "mute", + "notification", + "off", + "preference", + "prohibited", + "quiet", + "remove", + "restricted", + "setting", + "silence", + "silent", + "slash", + "state", + "status", + "stop", + "unavailable" + ], + "popularity": 5672 + }, + "DO_DISTURB_ALT": { + "tags": [ + "alert", + "bell", + "block", + "cancel", + "circle", + "close", + "denied", + "deny", + "diagonal line", + "disable", + "disturb", + "do", + "do not disturb", + "exclude", + "forbidden", + "ignore", + "interrupt", + "line", + "mute", + "no access", + "no entry", + "notification", + "off", + "offline", + "pause", + "prohibit", + "quiet", + "remove", + "restriction", + "silence", + "slash", + "snooze", + "stop", + "unavailable", + "warning" + ], + "popularity": 3932 + }, + "DO_DISTURB_OFF": { + "tags": [ + "accessibility", + "active", + "allow notifications", + "available", + "bar", + "cancel", + "circle", + "close", + "denied", + "deny", + "diagonal line", + "disabled", + "disturb", + "disturb off", + "dnd off", + "do", + "do not disturb off", + "enabled", + "focus off", + "inactive", + "no alerts", + "not silenced", + "notifications off", + "off", + "off state", + "on", + "options", + "quiet mode off", + "receive alerts", + "remove", + "ringing", + "settings", + "silence", + "silent mode off", + "slash", + "sound on", + "stop", + "toggle off", + "turn off dnd", + "turn off quiet mode", + "turn off silent", + "uninterrupted", + "volume on" + ], + "popularity": 1509 + }, + "DO_DISTURB_ON": { + "tags": [ + "action", + "alert", + "ban", + "block", + "cancel", + "caution", + "circle", + "clear", + "close", + "control", + "dash", + "delete", + "denied", + "deny", + "disable", + "disabled", + "disturb", + "do", + "do not disturb", + "enabled", + "error", + "exclude", + "forbidden", + "horizontal line", + "minus", + "negative", + "off", + "on", + "pause", + "prohibit", + "remove", + "restrict", + "revoke", + "round", + "silence", + "slash", + "stop", + "subtract", + "warning" + ], + "popularity": 7829 + }, + "DO_NOT_DISTURB": { + "tags": [ + "alert", + "bell", + "block", + "cancel", + "circle", + "close", + "denied", + "deny", + "diagonal line", + "disable", + "disturb", + "do", + "do not disturb", + "exclude", + "forbidden", + "ignore", + "interrupt", + "line", + "mute", + "neutral", + "no access", + "no entry", + "notification", + "off", + "offline", + "pause", + "prohibit", + "quiet", + "remove", + "restriction", + "silence", + "slash", + "snooze", + "stop", + "unavailable", + "warning" + ], + "popularity": 9432 + }, + "DO_NOT_DISTURB_ALT": { + "tags": [ + "alert", + "ban", + "block", + "cancel", + "circle", + "close", + "control", + "denied", + "deny", + "diagonal", + "disable", + "disturb", + "do", + "do not disturb", + "exclude", + "forbidden", + "interrupt", + "limit", + "line", + "mute", + "neutral", + "notification", + "off", + "preference", + "prohibited", + "quiet", + "remove", + "restricted", + "setting", + "silence", + "silent", + "slash", + "state", + "status", + "stop", + "unavailable" + ], + "popularity": 3633 + }, + "DO_NOT_DISTURB_OFF": { + "tags": [ + "accessibility", + "active", + "allow notifications", + "available", + "bar", + "cancel", + "circle", + "close", + "dash", + "denied", + "deny", + "diagonal line", + "disabled", + "disturb", + "disturb off", + "dnd off", + "do", + "do not disturb off", + "enabled", + "focus off", + "inactive", + "no alerts", + "not silenced", + "notifications off", + "off", + "off state", + "on", + "options", + "quiet mode off", + "receive alerts", + "remove", + "ringing", + "settings", + "silence", + "silent mode off", + "sound on", + "stop", + "toggle off", + "turn off dnd", + "turn off quiet mode", + "turn off silent", + "uninterrupted", + "volume on" + ], + "popularity": 1658 + }, + "DO_NOT_DISTURB_ON": { + "tags": [ + "action", + "alert", + "ban", + "block", + "cancel", + "caution", + "circle", + "clear", + "close", + "control", + "dash", + "delete", + "denied", + "deny", + "disable", + "disabled", + "disturb", + "do", + "do not disturb", + "enabled", + "error", + "exclude", + "forbidden", + "horizontal line", + "minus", + "negative", + "off", + "on", + "pause", + "prohibit", + "remove", + "restrict", + "revoke", + "round", + "silence", + "stop", + "subtract", + "warning" + ], + "popularity": 12662 + }, + "DO_NOT_DISTURB_ON_TOTAL_SILENCE": { + "tags": [ + "alert", + "ban", + "bell", + "blocked", + "busy", + "circle", + "communication", + "diagonal line", + "disable", + "disturb", + "dnd", + "do", + "do not disturb", + "line", + "mobile", + "mode", + "mute", + "no", + "no sound", + "not", + "notification", + "off", + "on total", + "phone", + "prohibition", + "quiet", + "ring", + "setting", + "silence", + "slash", + "status", + "stop", + "toggle", + "total silence", + "unavailable" + ], + "popularity": 1901 + }, + "DO_NOT_STEP": { + "tags": [ + "alert", + "boot", + "boundary", + "caution", + "circle", + "danger", + "disabled", + "do", + "do not step", + "enabled", + "feet", + "floor", + "foot", + "footprint", + "forbidden", + "ground", + "hazard", + "limit", + "movement", + "no access", + "no stepping", + "not", + "off", + "off limits", + "on", + "prohibition", + "restricted", + "restricted area", + "safety", + "shoe", + "shoe print", + "sign", + "slash", + "sneaker", + "standing", + "step", + "steps", + "stop", + "symbol", + "walking", + "warning" + ], + "popularity": 1813 + }, + "DO_NOT_TOUCH": { + "tags": [ + "access denied", + "barrier", + "beware", + "blocked", + "caution", + "constraint", + "control", + "cursor", + "delicate", + "disabled", + "do", + "don't touch", + "enabled", + "exclusion", + "finger", + "fingers", + "forbidden", + "gesture", + "halt", + "hand", + "interaction", + "limitation", + "no touching", + "not", + "not allowed", + "off", + "off limits", + "on", + "pointer", + "prevented", + "prohibit", + "restricted", + "restricted access", + "safety", + "sensitive", + "slash", + "stop", + "touch", + "warning" + ], + "popularity": 2747 + }, + "DOCK": { + "tags": [ + "accessory", + "android", + "base", + "button", + "cell", + "charger", + "charging", + "circle", + "connection", + "connector", + "cradle", + "desktop", + "device", + "dock", + "hardware", + "holder", + "ios", + "mobile", + "mount", + "os", + "peripheral", + "phone", + "power", + "rounded rectangle", + "screen", + "smartphone", + "stand", + "station", + "sync", + "synchronization", + "tablet", + "vertical" + ], + "popularity": 1530 + }, + "DOCUMENT_SCANNER": { + "tags": [ + "app", + "application", + "article", + "border", + "business", + "camera", + "capture", + "corners", + "data", + "device", + "digital", + "doc", + "document", + "drive", + "file", + "folder", + "folders", + "frame", + "graphic", + "image", + "interface", + "lines", + "mobile", + "notes", + "office", + "optical", + "page", + "paper", + "phone", + "photography", + "pictogram", + "picture", + "reader", + "rectangle", + "scan", + "scanner", + "sheet", + "slide", + "symbol", + "technology", + "text", + "ui", + "ux", + "vector", + "writing" + ], + "popularity": 13124 + }, + "DOMAIN": { + "tags": [ + "address", + "apartment", + "architecture", + "building", + "business", + "circle", + "communication", + "concept", + "connection", + "domain", + "estate", + "global", + "globe", + "home", + "icon", + "internet", + "link", + "navigation", + "network", + "online", + "place", + "real", + "representation", + "residence", + "residential", + "round", + "shelter", + "sphere", + "symbol", + "technology", + "ui", + "url", + "web", + "web address", + "website", + "world", + "www" + ], + "popularity": 16109 + }, + "DOMAIN_ADD": { + "tags": [ + "+", + "add", + "add domain", + "add site", + "add website", + "apartment", + "append", + "architecture", + "building", + "business", + "circle", + "connection", + "connectivity", + "create", + "domain", + "estate", + "expand", + "globe", + "home", + "host", + "hosting", + "include", + "internet", + "ip address", + "join", + "link", + "network", + "new", + "place", + "plus", + "real", + "register", + "residence", + "residential", + "server", + "shelter", + "signup", + "sphere", + "symbol", + "url", + "web", + "website", + "world", + "www" + ], + "popularity": 3640 + }, + "DOMAIN_DISABLED": { + "tags": [ + "access denied", + "apartment", + "architecture", + "blocked", + "building", + "business", + "circle", + "company", + "diagonal line", + "disabled", + "domain", + "domain access denied", + "domain block", + "domain disabled", + "domain privacy", + "domain restricted", + "domain security", + "domain unauthorized", + "enabled", + "estate", + "globe", + "home", + "internet", + "internet access denied", + "internet block", + "internet disabled", + "internet restricted", + "internet unauthorized", + "maps", + "off", + "office", + "offline", + "on", + "place", + "privacy", + "real", + "residence", + "residential", + "restricted", + "security", + "slash", + "sphere", + "unauthorized", + "web", + "web access disabled", + "web privacy", + "web security", + "website", + "website disabled" + ], + "popularity": 2634 + }, + "DOMAIN_VERIFICATION": { + "tags": [ + "access", + "app", + "application desktop", + "approve", + "approved", + "authenticated", + "certified", + "check", + "circle", + "complete", + "confirmed", + "connectivity", + "design", + "domain", + "done", + "global", + "globe", + "interface", + "international", + "internet", + "layout", + "map", + "mark", + "network", + "ok", + "planet", + "screen", + "security", + "select", + "site", + "tick", + "trusted", + "ui", + "ux", + "validate", + "validated", + "verification", + "verified", + "verify", + "web", + "website", + "window", + "world", + "www", + "yes" + ], + "popularity": 5547 + }, + "DONE": { + "tags": [ + "accepted", + "accomplished", + "acknowledgement", + "agree", + "approval", + "approve", + "approved", + "assent", + "check", + "complete", + "completed", + "confirmation", + "confirmed", + "correct", + "disable_ios", + "done", + "executed", + "final", + "finished", + "mark", + "ok", + "positive", + "right", + "select", + "sign off", + "submitted", + "success", + "task", + "tick", + "validate", + "validation", + "verified", + "yes" + ], + "popularity": 528531 + }, + "DONE_ALL": { + "tags": [ + "achievement", + "all", + "all done", + "approval", + "approve", + "approved", + "check", + "checked", + "checkmarks", + "complete", + "completion", + "confirmation", + "confirmed", + "correct", + "done", + "double check", + "finished", + "indicator", + "layers", + "list", + "mark", + "message", + "multiple", + "ok", + "process", + "read", + "select", + "sent", + "stack", + "status", + "success", + "task", + "task complete", + "tick", + "tick marks", + "two checks", + "valid", + "validate", + "validation", + "verified", + "workflow", + "yes" + ], + "popularity": 55514 + }, + "DONE_OUTLINE": { + "tags": [ + "accepted", + "achievement", + "agreement", + "all", + "approval", + "approve", + "approved", + "check", + "checkbox", + "complete", + "completed", + "confirmed", + "consent", + "correct", + "done", + "finished", + "green light", + "mark", + "ok", + "outline", + "right", + "select", + "selection", + "sign", + "status", + "success", + "task", + "task complete", + "tick", + "validate", + "validation", + "verification", + "verified", + "yes" + ], + "popularity": 39415 + }, + "DONUT_LARGE": { + "tags": [ + "activity", + "activity indicator", + "analytics", + "chart", + "circle", + "complete", + "completed", + "data", + "diagram", + "display", + "donut", + "donut large", + "fill", + "filled circle", + "full", + "fullscreen", + "graph", + "infographic", + "inprogress", + "large", + "large circle", + "loading", + "loading indicator", + "measure", + "metrics", + "pie", + "pie chart", + "progress", + "progress indicator", + "ring", + "screen", + "show", + "statistics", + "status", + "status indicator", + "tracking", + "visualization", + "visualize" + ], + "popularity": 13476 + }, + "DONUT_SMALL": { + "tags": [ + "analytics", + "chart", + "circle", + "circular", + "dashboard", + "data", + "diagram", + "donut", + "donut chart", + "graph", + "hole", + "incomplete", + "info", + "infographic", + "inprogress", + "measure", + "metrics", + "overview", + "partial", + "percentage", + "pie", + "progress", + "radial", + "report", + "ring", + "round", + "sections", + "segmented", + "small", + "statistics", + "status", + "summary", + "tracking", + "visualization" + ], + "popularity": 9298 + }, + "DOOR_BACK": { + "tags": [ + "access", + "back", + "barrier", + "close", + "closed", + "diagonal line", + "door", + "doorway", + "egress", + "entrance", + "entry", + "escape", + "exit", + "go back", + "handle", + "home", + "horizontal line", + "house", + "knob", + "leave", + "move backward", + "navigate back", + "open", + "opening", + "passage", + "portal", + "previous", + "rectangle", + "return", + "shut", + "way", + "way out" + ], + "popularity": 3497 + }, + "DOOR_FRONT": { + "tags": [ + "access", + "access point", + "building", + "close", + "closed", + "door", + "doorway", + "dwelling", + "entrance", + "entry", + "entry point", + "exit", + "front", + "front door", + "gateway", + "handle", + "home", + "house", + "leave", + "open", + "opening", + "passage", + "portal", + "property", + "rectangle", + "rectangle with handle", + "security", + "shelter", + "structure", + "threshold", + "way", + "welcome" + ], + "popularity": 6441 + }, + "DOOR_SLIDING": { + "tags": [ + "access", + "architecture", + "auto", + "automatic", + "barrier", + "basic", + "building", + "close", + "door", + "doorway", + "double", + "entrance", + "entry", + "exit", + "frame", + "furniture", + "gateway", + "glass", + "home", + "horizontal", + "house", + "interior", + "lines", + "open", + "opening", + "panel", + "passage", + "portal", + "rectangular", + "room", + "simple", + "sliding", + "sliding door", + "threshold", + "two", + "vertical" + ], + "popularity": 3698 + }, + "DOORBELL": { + "tags": [ + "alarm", + "alert", + "app icon", + "basic", + "bell", + "button", + "chime", + "door", + "doorbell", + "entrance", + "graphic", + "home", + "house", + "icon", + "illustration", + "notification", + "outline", + "rectangle", + "rectangular", + "ring", + "ringing", + "security", + "silhouette", + "simple", + "smart home", + "sound", + "symbol", + "ui icon", + "visitor", + "website icon" + ], + "popularity": 3249 + }, + "DOUBLE_ARROW": { + "tags": [ + "abstract", + "arrow", + "arrowheads", + "arrows", + "bidirectional", + "direction", + "double", + "double arrow", + "exchange", + "flow", + "geometric", + "indicator", + "line", + "minimal", + "move", + "movement", + "multiple", + "navigation", + "opposite", + "path", + "pointed", + "pointer", + "reverse", + "right", + "rotate", + "shift", + "sign", + "simple", + "swap", + "switch", + "symbol", + "transfer", + "transport" + ], + "popularity": 34417 + }, + "DOWNHILL_SKIING": { + "tags": [ + "abstract", + "activity", + "athlete", + "athletic", + "body", + "downhill", + "entertainment", + "exercise", + "figure", + "graphic", + "hobby", + "human", + "icon", + "line", + "mountain", + "outdoor", + "outline", + "people", + "person", + "recreation", + "shape", + "silhouette", + "ski social", + "skier", + "skiing", + "slope", + "snow", + "sport", + "sports", + "symbol", + "travel", + "vacation", + "winter" + ], + "popularity": 3781 + }, + "DOWNLOAD": { + "tags": [ + "acquire", + "action", + "app", + "application", + "archive", + "arrow", + "bar", + "button", + "cloud", + "computer", + "control", + "data", + "document", + "down", + "download", + "downloads", + "drive", + "file", + "get", + "incoming", + "install", + "internet", + "line", + "move", + "network", + "obtain", + "pointed", + "receive", + "save", + "storage", + "symbol", + "transfer", + "underscore", + "upload" + ], + "popularity": 80422 + }, + "DOWNLOAD_DONE": { + "tags": [ + "arrow", + "arrow and check", + "arrows", + "check", + "checkmark", + "complete", + "completed download", + "completed file download", + "confirmation", + "document", + "document and check", + "done", + "down", + "down arrow", + "down arrow and check", + "download", + "download complete", + "download done", + "download finished", + "download successful", + "downloads", + "drive", + "file", + "file download complete", + "file download done", + "file download finished", + "file download successful", + "finished", + "finished download", + "finished file download", + "install", + "installed", + "ok", + "paper", + "paper and check", + "success", + "successful download", + "successful file download", + "tick", + "upload" + ], + "popularity": 9868 + }, + "DOWNLOAD_FOR_OFFLINE": { + "tags": [ + "access", + "arrow", + "available offline", + "backup", + "caching", + "circle", + "cloud", + "cloud arrow", + "cloud icon", + "connection", + "data transfer", + "down", + "download", + "download cloud", + "download icon", + "file transfer", + "for offline", + "get file", + "install", + "internet", + "network", + "no internet", + "offline", + "offline icon", + "retrieve", + "retrieve data", + "save", + "save icon", + "storage", + "store", + "sync", + "synchronization", + "transfer", + "upload" + ], + "popularity": 19003 + }, + "DOWNLOADING": { + "tags": [ + "arrow", + "circle", + "cloud", + "cloud download", + "data", + "down", + "down arrow", + "download", + "download data", + "download file", + "download indicator", + "downloading", + "downloading progress", + "downloads", + "file transfer", + "indicator", + "install", + "internet", + "internet download", + "loading", + "network", + "pending", + "processing", + "progress", + "progress bar", + "queue", + "receive", + "retrieve", + "status", + "syncing", + "transfer", + "transfer data", + "transfer file", + "upload", + "waiting", + "web download" + ], + "popularity": 14293 + }, + "DRAFTS": { + "tags": [ + "archive", + "communication", + "composing", + "creating", + "data", + "document", + "draft", + "drafts", + "email", + "envelope", + "file", + "folder", + "holding", + "inbox", + "incomplete", + "letters", + "list", + "mail", + "memo", + "message", + "note", + "paper", + "pending", + "read", + "saved", + "stack", + "stationery", + "storage", + "text", + "unfiled", + "unfinished", + "unsent", + "writing" + ], + "popularity": 14787 + }, + "DRAG_HANDLE": { + "tags": [ + "action", + "app", + "application ui", + "bars", + "components", + "control", + "design", + "drag", + "element", + "grip", + "handle", + "handle.", + "indicator", + "interactive", + "interface", + "item", + "layout", + "lines", + "list", + "list item", + "menu", + "move", + "parallel", + "rearrange", + "reorder", + "reordering", + "screen", + "site", + "sort", + "sortable", + "three lines", + "ui", + "ux", + "vertical", + "web", + "website", + "widget", + "window" + ], + "popularity": 28105 + }, + "DRAG_INDICATOR": { + "tags": [ + "action", + "app", + "application", + "circles", + "column", + "components", + "control", + "design", + "dots", + "drag", + "drop", + "element", + "gesture", + "grab", + "grip", + "handle", + "icon", + "indicator", + "indicators", + "interaction", + "interface", + "item", + "layout", + "list", + "marker", + "menu", + "mobile", + "monitor", + "move", + "organize", + "phone", + "points", + "position", + "rearrange", + "reorder", + "screen", + "selector", + "shape", + "shift", + "site", + "sort", + "tablet", + "touch", + "ui", + "ux", + "vertical", + "web", + "website", + "window" + ], + "popularity": 44756 + }, + "DRAW": { + "tags": [ + "art", + "artist", + "compose", + "crayon", + "create", + "creative", + "curve", + "design", + "doodle", + "dot", + "draft", + "draw", + "edit", + "editing", + "form", + "freehand", + "graphic", + "hand drawn", + "illustration", + "ink", + "input", + "line", + "marker", + "modify", + "outline", + "pen", + "pencil", + "point", + "scribble", + "shape", + "sketch", + "tool", + "write", + "writing" + ], + "popularity": 14161 + }, + "DRIVE_ETA": { + "tags": [ + "auto", + "automobile", + "automotive", + "car", + "car symbol", + "cars", + "destination", + "direction", + "directions", + "drive", + "drive time", + "driving", + "estimate", + "estimated time", + "eta", + "journey", + "maps", + "mobility", + "navigate", + "navigation", + "passenger vehicle", + "public", + "road", + "route", + "sedan", + "time", + "transport", + "transport symbol", + "transportation", + "travel", + "travel time", + "trip", + "vehicle", + "vehicle icon" + ], + "popularity": 15649 + }, + "DRIVE_FILE_MOVE": { + "tags": [ + "action", + "arrange", + "arrow", + "button", + "cloud", + "copy", + "data", + "deliver", + "direction", + "doc", + "document", + "drive", + "drive storage", + "file", + "file management", + "folder", + "forward", + "graphic", + "icon", + "manage", + "move", + "navigation", + "organization", + "relocate", + "right", + "send", + "sheet", + "slide", + "storage", + "symbol", + "transfer", + "transport", + "ui element" + ], + "popularity": 8772 + }, + "DRIVE_FILE_MOVE_RTL": { + "tags": [ + "action", + "arrange", + "arrow", + "arrows", + "button", + "cloud", + "copy", + "data", + "deliver", + "direction", + "doc", + "document", + "drive", + "drive storage", + "file", + "file management", + "folder", + "folders", + "forward", + "graphic", + "icon", + "left", + "manage", + "move", + "navigation", + "organization", + "relocate", + "right", + "rtl", + "send", + "sheet", + "side", + "slide", + "storage", + "symbol", + "transfer", + "transport", + "ui element" + ], + "popularity": 2604 + }, + "DRIVE_FILE_RENAME_OUTLINE": { + "tags": [ + "archive", + "business", + "change", + "compose", + "create", + "data", + "document", + "draft", + "drive", + "e", + "edit", + "editing", + "file", + "folder", + "form", + "input", + "letter", + "marker", + "modify", + "office", + "outline", + "paper", + "pen", + "pencil", + "rename", + "save", + "sheet", + "square", + "text", + "update", + "write", + "writing" + ], + "popularity": 27275 + }, + "DRIVE_FOLDER_UPLOAD": { + "tags": [ + "add", + "archive", + "arrow", + "backup", + "cloud", + "computer", + "create", + "data", + "destination", + "digital", + "directory", + "doc", + "document", + "drive", + "export", + "file", + "folder", + "import", + "internet", + "move", + "network", + "new", + "online", + "save", + "send", + "share", + "sheet", + "slide", + "storage", + "technology", + "transfer", + "up", + "upload" + ], + "popularity": 8019 + }, + "DRY": { + "tags": [ + "air", + "air dry", + "appliance", + "bathroom", + "button", + "clothes", + "control", + "cycle", + "dry", + "dryer", + "drying", + "fingers", + "gesture", + "hand", + "hang dry", + "heat", + "household", + "indicator", + "laundry", + "laundry machine", + "mode", + "no heat", + "option", + "panel", + "setting", + "settings", + "spin", + "status", + "symbol", + "tumble", + "washing", + "washing machine", + "wc" + ], + "popularity": 1685 + }, + "DRY_CLEANING": { + "tags": [ + "apparel", + "bubble", + "button", + "care", + "chore", + "circle", + "circular", + "cleaning", + "clothes", + "dry", + "dry cleaning", + "dryer", + "fabric", + "garment", + "hanger", + "hotel", + "household", + "icon", + "ironing", + "laundry", + "machine", + "places", + "pressing", + "refresh", + "service", + "sign", + "steam", + "symbol", + "task", + "textile", + "toggle", + "towel", + "washing" + ], + "popularity": 4134 + }, + "DUO": { + "tags": [ + "account", + "avatar", + "call", + "chat", + "collaboration", + "communication", + "conference", + "device", + "double", + "duo", + "friends", + "group", + "network", + "pair", + "partnership", + "people", + "person", + "profile", + "relationship", + "social", + "teamwork", + "twin", + "two", + "user", + "users", + "video" + ], + "popularity": 3785 + }, + "DVR": { + "tags": [ + "android", + "archives", + "audio", + "box", + "broadcast", + "chrome", + "circle", + "computer", + "desktop", + "device", + "digital", + "display", + "dots", + "dvr", + "electronic", + "entertainment", + "hardware", + "home entertainment", + "ios", + "library", + "list", + "live tv", + "mac", + "media", + "monitor", + "movie", + "os", + "outline", + "playback", + "player", + "program", + "record", + "recorder", + "recording", + "rectangle", + "schedule", + "screen", + "series", + "shape", + "show", + "television", + "tv", + "vcr", + "video", + "web", + "window" + ], + "popularity": 12658 + }, + "DYNAMIC_FEED": { + "tags": [ + "abstract", + "activity", + "articles", + "blocks", + "blog", + "changing", + "chronological", + "content", + "current", + "data", + "dynamic", + "feed", + "flowing", + "information", + "lines", + "list", + "live", + "news", + "posts", + "publication", + "recent", + "rectangle", + "square", + "stories", + "stream", + "summaries", + "timeline", + "updates" + ], + "popularity": 9839 + }, + "DYNAMIC_FORM": { + "tags": [ + "adaptable", + "application", + "bolt", + "changing", + "choices", + "code", + "configurations", + "content", + "data", + "different", + "document", + "dynamic", + "dynamic form", + "electric", + "entry", + "fast", + "fields", + "file", + "flexible", + "form", + "information", + "input", + "lightning", + "list", + "lists", + "multiple", + "options", + "paper", + "properties", + "questionnaire", + "report", + "selection", + "settings", + "survey", + "text", + "thunderbolt", + "variable" + ], + "popularity": 7588 + }, + "E_MOBILEDATA": { + "tags": [ + "alphabet", + "bars", + "cell", + "cell service", + "cellular", + "cellular data", + "cellular network", + "connection", + "connectivity", + "data", + "data connectivity", + "data signal", + "e", + "e network", + "edge network", + "font", + "internet", + "internet signal", + "letters", + "mobile", + "mobile connectivity", + "mobile data", + "mobiledata", + "network", + "reception", + "service", + "signal", + "strength", + "telecom", + "telecommunication", + "telecommunications", + "text", + "type", + "wireless", + "wireless network" + ], + "popularity": 828 + }, + "EARBUDS": { + "tags": [ + "accessory", + "audio", + "audio device", + "audio input", + "cable", + "communication", + "connected", + "device", + "ear", + "earbuds", + "earbuds icon", + "earphone", + "earphones", + "earphones icon", + "entertainment", + "headphone", + "headphones", + "headset", + "listen", + "listening", + "listening device", + "media", + "microphone", + "music", + "personal audio", + "personal listening", + "playback", + "portable", + "sound", + "sound output", + "technology", + "wire", + "wired audio" + ], + "popularity": 2196 + }, + "EARBUDS_BATTERY": { + "tags": [ + "accessory", + "audio", + "battery", + "battery charge", + "battery level", + "battery status", + "bluetooth", + "charge", + "charging", + "device", + "earbud case", + "earbuds", + "earphone", + "earpiece", + "headphone", + "headphones", + "headset", + "icon", + "indicator", + "interface", + "level", + "listen", + "listening", + "music", + "power", + "sound", + "status", + "symbol", + "tech", + "technology", + "ui", + "wireless" + ], + "popularity": 1374 + }, + "EAST": { + "tags": [ + "angle", + "arrow", + "compass", + "direction", + "directional", + "east", + "element", + "forward", + "go", + "indicator", + "journey", + "line", + "maps", + "move", + "navigation", + "next", + "path", + "point", + "pointer", + "position", + "right", + "signage", + "symbol", + "travel", + "triangle" + ], + "popularity": 64832 + }, + "EDGESENSOR_HIGH": { + "tags": [ + "android", + "bar", + "bars", + "cell", + "cell signal", + "connection", + "data", + "device", + "edge", + "graphic", + "hardware", + "high", + "indicator", + "ios", + "level", + "measurement", + "mobile", + "move", + "network", + "os", + "phone", + "pie chart", + "power", + "reception", + "sensitivity", + "sensor", + "signal", + "status", + "strength", + "tablet", + "technology", + "telecommunications", + "triangle", + "vertical bars", + "vibrate", + "wi-fi" + ], + "popularity": 1547 + }, + "EDGESENSOR_LOW": { + "tags": [ + "alert", + "android", + "antenna", + "bars", + "cell", + "cellular", + "connection", + "connectivity", + "device", + "edge", + "hardware", + "high", + "indicator", + "ios", + "lines", + "low", + "mobile", + "move", + "network", + "os", + "phone", + "poor", + "reception", + "rectangle", + "rounded corners", + "sensitivity", + "sensor", + "signal", + "status", + "strength", + "tablet", + "vibrate", + "warning", + "weak" + ], + "popularity": 1224 + }, + "EDIT": { + "tags": [ + "action", + "alter", + "author", + "change", + "compose", + "control", + "create", + "document", + "edit", + "editing", + "form", + "glyph", + "input", + "mode", + "mode_edit", + "mode_edit_outline", + "modify", + "new", + "outline", + "pen", + "pencil", + "revise", + "shape", + "stroke", + "text", + "tool", + "update", + "write", + "writing" + ], + "popularity": 313958 + }, + "EDIT_ATTRIBUTES": { + "tags": [ + "adjust", + "approve", + "attributes", + "attribution", + "change", + "check", + "complete", + "configure", + "controls", + "customize", + "done", + "edit", + "edit attributes", + "fine tune", + "glyph", + "graphic", + "icon", + "manage", + "mark", + "modify", + "ok", + "options", + "outline", + "parameters", + "properties", + "select", + "settings", + "symbol", + "tick", + "tool", + "tune", + "validate", + "vector", + "verified", + "yes" + ], + "popularity": 4048 + }, + "EDIT_CALENDAR": { + "tags": [ + "agenda", + "annotate", + "appointment", + "booking", + "calendar", + "change", + "compose", + "create", + "date", + "day", + "deadline", + "draft", + "edit", + "editing", + "element", + "event", + "icon", + "interface", + "manage", + "modify", + "month", + "organizer", + "pen", + "pencil", + "planner", + "reminder", + "reschedule", + "schedule", + "symbol", + "timestamp", + "update", + "write", + "writing", + "year" + ], + "popularity": 31335 + }, + "EDIT_LOCATION": { + "tags": [ + "address", + "alter", + "change", + "configure", + "correct", + "customize", + "destination", + "direction", + "edit", + "geography", + "geotag", + "gps", + "location", + "manage", + "map", + "maps", + "marker", + "modify", + "navigation", + "pen", + "pencil", + "pin", + "pinpoint", + "place", + "pointer", + "position", + "set", + "spot", + "stop", + "teardrop", + "travel", + "update", + "write" + ], + "popularity": 4349 + }, + "EDIT_LOCATION_ALT": { + "tags": [ + "address", + "adjust", + "alt", + "alter", + "change", + "coordinates", + "customize", + "destination", + "direction", + "edit", + "edit location", + "geo", + "geographic", + "gps", + "location", + "map", + "marker", + "modify", + "navigation", + "pen", + "pencil", + "pin", + "place", + "poi", + "point of interest", + "position", + "reposition", + "set location", + "target", + "update", + "waypoint", + "write" + ], + "popularity": 3990 + }, + "EDIT_NOTE": { + "tags": [ + "changes", + "compose", + "compose note", + "corrections", + "create", + "create document", + "create note", + "document", + "draft", + "edit", + "edit document", + "edit file", + "edit text", + "editing", + "editor", + "file", + "input", + "lines", + "memo", + "modify", + "new", + "new document", + "note", + "notepad", + "paper", + "pen", + "pencil", + "revision", + "text", + "write", + "writing", + "writing tool" + ], + "popularity": 60863 + }, + "EDIT_NOTIFICATIONS": { + "tags": [ + "active", + "adjust", + "alarm", + "alert", + "bell", + "bell with pencil", + "change", + "chime", + "communication", + "compose", + "configure", + "create", + "customize", + "draft", + "drawing", + "edit", + "edit alert", + "editing", + "geometry", + "input", + "line", + "message", + "modify", + "modify notification", + "new", + "notification", + "notification settings", + "notifications", + "notify", + "options", + "pen", + "pencil", + "preferences", + "reminder", + "ring", + "settings", + "shape", + "sound", + "sounds", + "write", + "writing" + ], + "popularity": 4592 + }, + "EDIT_OFF": { + "tags": [ + "blocked", + "can't edit", + "compose", + "create", + "diagonal line", + "disabled", + "disabled edit", + "disallowed", + "draft", + "edit", + "edit blocked", + "edit off", + "editing", + "editing disabled", + "enabled", + "forbidden", + "icon", + "input", + "line", + "lock edit", + "new", + "no edit", + "no pen", + "no pencil", + "not available", + "off", + "offline", + "on", + "pen", + "pen off", + "pencil", + "pencil off", + "restricted", + "restricted edit", + "slash", + "slashes", + "strike through", + "ui icon", + "unavailable", + "write", + "writing" + ], + "popularity": 8816 + }, + "EDIT_ROAD": { + "tags": [ + "adjust", + "annotate", + "change", + "curve", + "destination", + "direction", + "draw", + "edit", + "gps", + "highway", + "journey", + "lane", + "location", + "map", + "maps", + "mark", + "modify", + "move", + "navigation", + "path", + "pen", + "pencil", + "road", + "route", + "street", + "tool", + "traffic", + "transport", + "travel", + "trip", + "ui", + "update", + "winding", + "write" + ], + "popularity": 3998 + }, + "EGG": { + "tags": [ + "animal", + "boiled", + "breakfast", + "broken", + "brunch", + "cooking", + "cracked", + "delicate", + "delicious", + "diet", + "egg", + "farm", + "food", + "fragile", + "fresh", + "fried", + "healthy", + "ingredient", + "kitchen", + "meal", + "nature", + "nutrition", + "organic", + "oval", + "ovum", + "poultry", + "protein", + "raw", + "scrambled", + "shell", + "source" + ], + "popularity": 2822 + }, + "EGG_ALT": { + "tags": [ + "agriculture", + "bake", + "break", + "breakfast", + "brunch", + "carton", + "cook", + "cooking", + "crack", + "cuisine", + "easter", + "egg", + "farm", + "food", + "fresh", + "holiday", + "ingredient", + "kitchen", + "livestock", + "menu", + "natural", + "object", + "organic", + "oval", + "poultry", + "protein", + "raw", + "shape", + "shell", + "symbol", + "white" + ], + "popularity": 1549 + }, + "EJECT": { + "tags": [ + "action", + "arrow", + "audio", + "bar", + "button", + "command", + "control", + "device", + "disc", + "disk", + "drive", + "dvd", + "eject", + "function", + "hardware", + "line", + "media", + "multimedia", + "pause", + "physical media", + "play", + "player", + "removal", + "remove", + "stop", + "symbol", + "triangle", + "ui control", + "upward", + "upward pointing", + "usb", + "video" + ], + "popularity": 4183 + }, + "ELDERLY": { + "tags": [ + "account", + "account icon", + "account representation", + "age", + "avatar", + "body", + "cane", + "community", + "demographic", + "elderly", + "figure", + "head and shoulders", + "human", + "identity", + "individual", + "member", + "old", + "old person", + "older", + "people", + "person", + "portrait", + "profile", + "profile icon", + "profile picture", + "profile representation", + "profile view", + "representation", + "senior", + "silhouette", + "user", + "user icon", + "user representation" + ], + "popularity": 6090 + }, + "ELDERLY_WOMAN": { + "tags": [ + "aged", + "avatar", + "body", + "cane", + "circle", + "elderly", + "female", + "figure", + "filled", + "gender", + "girl", + "head", + "human", + "icon", + "lady", + "old", + "outline", + "people", + "person", + "portrait", + "profile", + "round", + "senior", + "shape", + "shoulders", + "silhouette", + "social", + "solid", + "symbol", + "user", + "woman", + "women" + ], + "popularity": 2202 + }, + "ELECTRIC_BIKE": { + "tags": [ + "battery", + "battery bicycle", + "battery bike", + "bicycle", + "bike", + "bolt", + "commute", + "cycling", + "e-bike", + "ebike", + "eco-friendly", + "electric", + "electric bicycle", + "electric bike", + "electric scooter", + "electric vehicle", + "electricity", + "leisure", + "maps", + "mobility", + "motor", + "outdoor", + "pedal assist", + "power", + "powered bike", + "recreation", + "ride", + "scooter", + "speed", + "sports", + "sustainable", + "thunderbolt", + "transportation", + "travel", + "two wheels", + "urban", + "vehicle", + "vespa" + ], + "popularity": 2788 + }, + "ELECTRIC_BOLT": { + "tags": [ + "alert", + "battery", + "bolt", + "charging", + "current", + "danger", + "dynamic", + "electric", + "electric bolt", + "electric current", + "electrical", + "electricity", + "energy", + "fast", + "flash", + "high voltage", + "instant", + "intense", + "lightning", + "nest", + "performance", + "power", + "quick", + "rapid", + "speed", + "storm", + "sudden", + "thunderbolt", + "urgent", + "voltage", + "warning", + "weather", + "zap" + ], + "popularity": 7456 + }, + "ELECTRIC_CAR": { + "tags": [ + "automobile", + "battery", + "bolt", + "car", + "cars", + "charge", + "charging", + "commute", + "destination", + "drive", + "eco-friendly", + "electric", + "electric vehicle", + "electricity", + "energy", + "energy saving", + "green", + "journey", + "maps", + "mobility", + "plug", + "power", + "refuel", + "road", + "route", + "station", + "sustainable", + "thunderbolt", + "transport", + "transportation", + "travel", + "vehicle", + "zero emission" + ], + "popularity": 4892 + }, + "ELECTRIC_METER": { + "tags": [ + "analog", + "bill", + "billing", + "bolt", + "building", + "charge", + "circle", + "consumption", + "cost", + "data", + "dial", + "electric", + "electric meter", + "electricity", + "energy", + "energy usage", + "fast", + "gauge", + "home", + "house", + "indicator", + "information", + "instant", + "lightning", + "measure", + "measurement", + "meter", + "needle", + "nest", + "pointer", + "power", + "power consumption", + "square", + "statistics", + "thunderbolt", + "usage", + "utilities", + "utility", + "voltage", + "volts" + ], + "popularity": 2303 + }, + "ELECTRIC_MOPED": { + "tags": [ + "automobile", + "battery", + "bike", + "bolt", + "car", + "cars", + "charging", + "city", + "courier", + "delivery", + "e-scooter", + "eco-friendly", + "electric", + "electric moped", + "electric scooter", + "handlebars", + "maps", + "mobility", + "moped", + "motor", + "outline", + "personal transport", + "power", + "rental", + "ride", + "scooter", + "seat", + "share", + "silhouette", + "sustainable", + "symbol", + "thunderbolt", + "transportation", + "travel", + "two wheels", + "urban", + "vehicle", + "vespa", + "wheels" + ], + "popularity": 1678 + }, + "ELECTRIC_RICKSHAW": { + "tags": [ + "asia", + "auto rickshaw", + "automobile", + "bangkok", + "bolt", + "car", + "cars", + "driver", + "e rickshaw", + "electric", + "electric rickshaw", + "electric vehicle", + "india", + "lines", + "maps", + "mobility", + "outline", + "passenger", + "passenger vehicle", + "public transport", + "rickshaw", + "ride", + "silhouette", + "southeast asia", + "sustainable transport", + "taxi", + "thailand", + "three wheel vehicle", + "thunderbolt", + "transport", + "transportation", + "travel", + "truck", + "tuk tuk", + "urban transport", + "vehicle", + "wheels" + ], + "popularity": 2003 + }, + "ELECTRIC_SCOOTER": { + "tags": [ + "battery", + "bike", + "bolt", + "city", + "commute", + "commuter", + "deck", + "direction", + "directions", + "e-scooter", + "electric", + "electric scooter", + "footboard", + "handle bars", + "kick scooter", + "last mile", + "maps", + "micro-mobility", + "mobility", + "motor", + "movement", + "personal transport", + "rental", + "ride", + "scooter", + "sharing", + "standing scooter", + "thunderbolt", + "transport", + "transportation", + "travel", + "two wheels", + "urban mobility", + "vehicle", + "vespa", + "wheels" + ], + "popularity": 2615 + }, + "ELECTRICAL_SERVICES": { + "tags": [ + "bolt", + "bright", + "charge", + "circuit", + "cord", + "current", + "electric", + "electrical", + "electrical services", + "electricity", + "energy", + "energy savings", + "fast", + "fix", + "high voltage", + "home services", + "infrastructure", + "installation", + "jolt", + "light", + "lightning", + "maintenance", + "plug", + "power", + "power lines", + "repair", + "service", + "services", + "spark", + "surge", + "technician", + "utility", + "voltage", + "wire", + "wiring", + "zap" + ], + "popularity": 10818 + }, + "ELEVATOR": { + "tags": [ + "abstract", + "access", + "architecture", + "arrows", + "body", + "building", + "button", + "construction", + "control", + "destination", + "direction", + "down", + "elevator", + "floors", + "human", + "indicator", + "indoor", + "interface", + "levels", + "lift", + "machinery", + "movement", + "navigation", + "people", + "person", + "pointer", + "simplified", + "symbol", + "technology", + "transport", + "travel", + "triangles", + "up", + "vertical" + ], + "popularity": 3819 + }, + "EMAIL": { + "tags": [ + "communication", + "communication icon", + "contact", + "contact icon", + "correspondence", + "diagonal lines", + "digital", + "electronic mail", + "email", + "empty", + "envelop", + "envelope", + "fold", + "icon", + "inbox", + "inbox icon", + "internet", + "letter", + "letters", + "mail", + "message", + "message icon", + "new message", + "online", + "outline", + "paper", + "receive", + "rectangle", + "send", + "symbol", + "thin line", + "unread" + ], + "popularity": 277420 + }, + "EMERGENCY": { + "tags": [ + "alarm", + "alert", + "assistance", + "asterisk", + "attention", + "bell", + "clinic", + "critical", + "cross", + "crucial", + "danger", + "distress", + "emergency", + "first aid", + "hazard", + "health", + "healthcare", + "heartbeat", + "help", + "hospital", + "important", + "maps", + "medical", + "notification", + "notify", + "plus", + "pulse", + "safety", + "security", + "signal", + "siren", + "symbol", + "urgent", + "warning" + ], + "popularity": 10151 + }, + "EMERGENCY_RECORDING": { + "tags": [ + "action", + "alert", + "app", + "application", + "attention", + "button", + "camera", + "capture", + "caution", + "control", + "danger", + "device", + "emergency", + "film", + "filming", + "hardware", + "icon", + "image", + "important", + "interface element", + "lens", + "media", + "monitoring", + "motion", + "multimedia", + "notification", + "optical", + "photo", + "photography", + "picture", + "record", + "recording", + "security", + "surveillance", + "technology", + "ui element", + "urgent", + "video", + "videography", + "visual", + "warning" + ], + "popularity": 782 + }, + "EMERGENCY_SHARE": { + "tags": [ + "alert", + "assist", + "attention", + "broadcast", + "call for help", + "caution", + "communicate", + "crisis", + "critical", + "danger", + "disaster", + "distress", + "emergency", + "emergency communication", + "help", + "immediate", + "important", + "incident", + "inform", + "notification", + "panic", + "public safety", + "rapid", + "report", + "rescue", + "response", + "safety", + "send", + "share", + "sos", + "transmit", + "urgent", + "warning" + ], + "popularity": 1309 + }, + "EMOJI_EMOTIONS": { + "tags": [ + "+", + "add", + "character", + "chat", + "cheerful", + "circle", + "communication", + "emoji", + "emoticon", + "emotion", + "emotions", + "expression", + "expressions", + "face", + "feeling", + "feelings", + "glad", + "grin", + "happiness", + "happy", + "icon", + "icons", + "insert", + "joy", + "like", + "message", + "mood", + "new", + "outline", + "person", + "pleased", + "plus", + "reaction", + "round", + "select", + "smile", + "smiley", + "smiling", + "social", + "survey", + "symbol", + "tag", + "text" + ], + "popularity": 33870 + }, + "EMOJI_EVENTS": { + "tags": [ + "accomplishment", + "achievement", + "achievement award", + "award", + "award icon", + "celebration", + "chalice", + "challenge", + "champion", + "championship", + "championship trophy", + "competition", + "contest", + "cup", + "event", + "excellence", + "first", + "first place", + "gold cup", + "honor", + "prize", + "recognition", + "reward", + "sport", + "sports", + "sports award", + "success", + "tournament", + "trophy", + "victory", + "victory icon", + "win", + "winner", + "winner's cup" + ], + "popularity": 81935 + }, + "EMOJI_FOOD_BEVERAGE": { + "tags": [ + "beverage", + "break", + "cafe", + "caffeine", + "ceramic", + "coffee", + "cup", + "curve", + "dining", + "drink", + "emoji", + "food", + "handle", + "hot drink", + "kitchen", + "liquid", + "morning", + "mug", + "plate", + "refreshments", + "relax", + "restaurant", + "saucer", + "set", + "steam", + "steam lines", + "tea" + ], + "popularity": 6695 + }, + "EMOJI_NATURE": { + "tags": [ + "animal", + "bee", + "botany", + "branch", + "bug", + "daisy", + "earth", + "ecology", + "ecosystem", + "emoji", + "environment", + "environmental", + "flora", + "floral", + "flower", + "foliage", + "forestry", + "garden", + "gardening", + "green", + "growth", + "insect", + "ladybug", + "leaf", + "leaf symbol", + "leaves", + "natural", + "nature", + "nature conservation", + "organic", + "outdoor", + "park", + "petals", + "plant", + "spring", + "sprout", + "stem", + "summer", + "twig" + ], + "popularity": 9537 + }, + "EMOJI_OBJECTS": { + "tags": [ + "avatar", + "bulb", + "cartoon", + "character", + "chat", + "cheerful", + "circle", + "communication", + "creative", + "emoji", + "emoticon", + "expression", + "face", + "feeling", + "happy", + "idea", + "joy", + "light", + "message", + "objects", + "positive", + "reaction", + "round", + "smile", + "smiley", + "solution", + "thinking" + ], + "popularity": 26374 + }, + "EMOJI_PEOPLE": { + "tags": [ + "accounts", + "arm", + "assembly", + "audience", + "avatars", + "body", + "community", + "contacts", + "crowd", + "directory", + "emoji", + "employees", + "figures", + "friends", + "gathering", + "greeting", + "group", + "human", + "individuals", + "members", + "membership", + "multitude", + "network", + "outlines", + "people", + "person", + "profile", + "profiles", + "representation", + "roster", + "silhouettes", + "social", + "staff", + "team", + "users", + "waving" + ], + "popularity": 19218 + }, + "EMOJI_SYMBOLS": { + "tags": [ + "add emoji", + "ampersand", + "character", + "chat", + "communication", + "emoji", + "emoji picker", + "emoticon", + "emotions", + "expression", + "face", + "feeling", + "fun", + "happy", + "hieroglyph", + "icon set", + "keyboard", + "messaging", + "music", + "note", + "percent", + "pick emoji", + "reaction", + "select emoji", + "sentiment", + "sign", + "smile", + "smiley face", + "social media", + "sticker", + "symbols", + "text" + ], + "popularity": 6525 + }, + "EMOJI_TRANSPORTATION": { + "tags": [ + "architecture", + "arrow", + "automobile", + "building", + "car", + "carriage", + "cars", + "commute", + "direction", + "emoji", + "engine", + "estate", + "forward", + "journey", + "locomotive", + "maps", + "passengers", + "place", + "public", + "public transport", + "public transport icon", + "rail", + "railway", + "railway icon", + "railway symbol", + "real", + "residence", + "residential", + "shelter", + "train", + "train icon", + "train symbol", + "transport icon", + "transport symbol", + "transportation", + "travel", + "travel icon", + "travel symbol", + "vehicle", + "wagon" + ], + "popularity": 6506 + }, + "ENERGY_SAVINGS_LEAF": { + "tags": [ + "battery saver", + "button", + "configuration", + "conservation", + "control", + "eco", + "eco-friendly", + "ecology", + "efficiency", + "energy", + "environment", + "green", + "icon", + "indicator", + "leaf", + "leaves", + "low power", + "nature", + "nest", + "options", + "plant", + "power", + "renewable", + "resource management", + "saving", + "savings", + "savings mode", + "settings", + "status", + "sustainable", + "symbol", + "toggle", + "usage" + ], + "popularity": 4697 + }, + "ENGINEERING": { + "tags": [ + "adjustment", + "automation", + "body", + "building", + "cog", + "cogs", + "cogwheel", + "configuration", + "construction", + "control", + "customize", + "development", + "engineering", + "fix", + "fixing", + "function", + "gear", + "gears", + "hat", + "helmet", + "human", + "industrial", + "industry", + "machinery", + "maintenance", + "management", + "mechanics", + "operation", + "options", + "people", + "person", + "process", + "repair", + "setting", + "settings", + "setup", + "system", + "technical", + "technology", + "tools", + "worker" + ], + "popularity": 53645 + }, + "ENHANCED_ENCRYPTION": { + "tags": [ + "+", + "access", + "add", + "authorized", + "breaking encryption", + "cipher", + "closed", + "code", + "confidential", + "data", + "decoding", + "decryption", + "digital", + "encryption", + "enhanced", + "key", + "lock", + "locked", + "new", + "open lock", + "open padlock", + "padlock", + "password", + "plus", + "privacy", + "private", + "protection", + "restricted", + "safety", + "scrambling", + "secure", + "security", + "sensitive", + "symbol", + "technology", + "unlock", + "unlocked", + "unscrambling" + ], + "popularity": 6533 + }, + "EQUALIZER": { + "tags": [ + "adjust", + "adjustment", + "analytics", + "audio", + "audio control", + "bars", + "chart", + "control", + "customize", + "data", + "digital", + "equalizer", + "filter", + "fine tune", + "frequency", + "graph", + "levels", + "lines", + "measure", + "metrics", + "mix", + "mixing", + "multimedia", + "music", + "noise", + "parameters", + "playback", + "preferences", + "settings", + "settings icon", + "sound", + "sound adjustment", + "spectrum", + "static", + "statistics", + "tone", + "tracking", + "vertical", + "visualizer", + "volume" + ], + "popularity": 20061 + }, + "ERROR": { + "tags": [ + "!", + "alert", + "attention", + "bug", + "caution", + "circle", + "critical", + "danger", + "error", + "exception", + "exclamation", + "failure", + "important", + "information", + "invalid", + "issue", + "mark", + "message", + "mistake", + "notification", + "outline", + "problem", + "round", + "security", + "status", + "stop", + "symbol", + "system", + "trouble", + "validation", + "warning", + "wrong" + ], + "popularity": 111119 + }, + "ERROR_OUTLINE": { + "tags": [ + "!", + "alert", + "attention", + "bug", + "caution", + "circle", + "critical", + "danger", + "error", + "exception", + "exclamation", + "failure", + "important", + "information", + "invalid", + "issue", + "mark", + "message", + "mistake", + "notification", + "outline", + "problem", + "round", + "security", + "status", + "stop", + "symbol", + "system", + "trouble", + "validation", + "warning", + "wrong" + ], + "popularity": 87362 + }, + "ESCALATOR": { + "tags": [ + "access", + "accessibility", + "airport", + "arrow", + "ascend", + "building", + "convenience", + "descend", + "directions", + "disabled access", + "down", + "escalator", + "facility", + "floor", + "levels", + "mall", + "movement", + "moving walkway", + "navigation", + "public transport", + "sign", + "staircase", + "stairs", + "station", + "steps", + "transport", + "transportation", + "travel", + "up", + "wayfinding" + ], + "popularity": 1723 + }, + "ESCALATOR_WARNING": { + "tags": [ + "alert", + "attention", + "body", + "broken", + "building", + "caution", + "child", + "danger", + "downward movement", + "escalator", + "exclamation mark", + "facility", + "filled", + "forbidden", + "hazard", + "human", + "kid", + "maintenance", + "mechanical stairs", + "moving stairs", + "no entry", + "notification", + "out of order", + "outlined", + "parent", + "people", + "person", + "prohibited", + "public transport", + "restricted", + "safety", + "sign", + "symbol", + "triangle", + "upward movement", + "warning" + ], + "popularity": 6859 + }, + "EURO": { + "tags": [ + "banking", + "bill", + "card", + "cash", + "coin", + "commerce", + "cost", + "credit", + "currency", + "currency symbol", + "dollars", + "economics", + "euro", + "europe", + "european", + "european currency", + "euros", + "exchange", + "finance", + "financial symbol", + "glyph", + "horizontal lines", + "international currency", + "line", + "monetary", + "money", + "money symbol", + "online", + "pay", + "payment", + "price", + "shape", + "shopping", + "stroke", + "symbol", + "trade", + "value", + "wealth" + ], + "popularity": 19995 + }, + "EURO_SYMBOL": { + "tags": [ + "banking", + "bill", + "business", + "buy", + "card", + "cash", + "coin", + "commerce", + "cost", + "credit", + "currency", + "dollars", + "economy", + "euro", + "european", + "exchange", + "finance", + "financial", + "international", + "monetary", + "money", + "online", + "pay", + "payment", + "price", + "sell", + "symbol", + "transaction", + "value", + "wealth" + ], + "popularity": 21683 + }, + "EV_STATION": { + "tags": [ + "automobile", + "battery", + "bolt", + "car", + "cars", + "charger", + "charging", + "charging port", + "charging station", + "electric", + "electric car", + "electric vehicle", + "electric vehicle charging station", + "electricity", + "energy", + "energy source", + "ev", + "ev charger", + "fuel", + "gas", + "green energy", + "home", + "maps", + "outlet", + "petrol", + "places", + "plug", + "power", + "power station", + "pump", + "refueling", + "renewable", + "socket", + "station", + "sustainable", + "thunderbolt", + "transport", + "transportation", + "vehicle" + ], + "popularity": 5190 + }, + "EVENT": { + "tags": [ + "add", + "add event", + "add invitation", + "add to calendar", + "agenda", + "appointment", + "booking", + "calendar", + "daily", + "date", + "day", + "event", + "insert invitation", + "invitation", + "invite", + "mark", + "meeting", + "month", + "monthly", + "new event", + "new invitation", + "organizing", + "planning", + "plus", + "range", + "remember", + "reminder", + "reservation", + "schedule", + "schedule event", + "square", + "time", + "today", + "week", + "weekly" + ], + "popularity": 143591 + }, + "EVENT_AVAILABLE": { + "tags": [ + "agenda", + "appointment", + "approve", + "availability", + "availability icon", + "available", + "booked", + "booking", + "calendar", + "calendar icon", + "check", + "check icon", + "checkmark", + "complete", + "confirmed", + "confirmed appointment", + "confirmed event", + "date", + "date available", + "date confirmed", + "date icon", + "done", + "event", + "event icon", + "event planning", + "mark", + "ok", + "plan", + "reminder", + "schedule", + "scheduled date", + "scheduled event", + "select", + "tick", + "time", + "validate", + "verified", + "yes" + ], + "popularity": 42447 + }, + "EVENT_BUSY": { + "tags": [ + "appointment", + "blocked", + "booked", + "busy", + "calendar", + "cancel", + "clear", + "close", + "cross", + "date", + "event", + "exit", + "fill", + "full", + "glyph", + "holiday", + "lines", + "mark", + "meeting", + "no", + "out of office", + "outlined", + "remove", + "schedule", + "solid", + "square", + "stop", + "stroke", + "time", + "time off", + "unavailable", + "vacation", + "x", + "x mark" + ], + "popularity": 14219 + }, + "EVENT_NOTE": { + "tags": [ + "activity", + "agenda", + "appointment", + "booking", + "calendar", + "date", + "diary", + "document", + "due date", + "entry", + "event", + "important", + "journal", + "list", + "meeting", + "memo", + "note", + "organize", + "paper", + "plan", + "planning", + "record", + "reminder", + "reservations", + "schedule", + "task", + "tasks", + "text", + "time", + "timelog", + "timestamp", + "to do", + "writing" + ], + "popularity": 25685 + }, + "EVENT_REPEAT": { + "tags": [ + "agenda", + "always", + "appointment", + "around", + "calendar", + "constant", + "continuous", + "cycle", + "daily", + "date", + "day", + "event", + "event repeat", + "frequency", + "infinite", + "inprogress", + "load", + "loading refresh", + "loop", + "meeting", + "month", + "monthly", + "perpetual", + "planner", + "recurrence", + "recurring", + "redo", + "renew", + "repeat", + "revisit", + "rotate", + "schedule", + "schedule management", + "task", + "time", + "turn", + "weekly", + "yearly" + ], + "popularity": 6232 + }, + "EVENT_SEAT": { + "tags": [ + "allocation", + "arrangement", + "assign", + "assigned", + "available", + "booking", + "chair", + "choice", + "cinema", + "concert", + "empty", + "event", + "furniture", + "location", + "occupied", + "place", + "plan", + "position", + "reservation", + "row", + "seat", + "seating", + "section", + "selection", + "sit", + "sports", + "spot", + "stadium", + "taken", + "theater", + "ticket", + "venue" + ], + "popularity": 8042 + }, + "EXIT_TO_APP": { + "tags": [ + "abandon", + "access", + "account", + "app", + "application", + "arrow", + "block", + "box", + "close", + "components", + "depart", + "design", + "door", + "exit", + "export", + "forward", + "gate", + "interface", + "layout", + "leave", + "line", + "log off", + "logout", + "mobile", + "monitor", + "move", + "navigate", + "navigation", + "out", + "output", + "outside", + "phone", + "portal", + "quit", + "rectangle", + "right arrow", + "screen", + "session", + "sign out", + "site", + "square", + "tablet", + "to", + "ui", + "user", + "ux", + "web", + "website", + "window" + ], + "popularity": 39310 + }, + "EXPAND": { + "tags": [ + "arrow", + "arrows", + "aspect ratio", + "bigger", + "compress", + "content", + "corner", + "diagonal", + "enlarge", + "expand", + "four arrows", + "four directions", + "frame", + "full screen", + "fullscreen", + "grow", + "increase", + "maximize", + "move", + "multimedia", + "open", + "outward", + "outward arrows", + "push", + "scale", + "screen", + "stretch", + "together", + "view", + "view area", + "window", + "zoom" + ], + "popularity": 14479 + }, + "EXPAND_CIRCLE_DOWN": { + "tags": [ + "arrow", + "arrows", + "button", + "chevron", + "circle", + "circle button", + "close", + "collapse", + "collapse down", + "control", + "details", + "direction", + "down", + "down arrow", + "down arrow button", + "dropdown", + "dropdown indicator", + "expand", + "expand down", + "expandable", + "hide", + "indicator", + "information", + "list", + "maximize", + "menu", + "minimize", + "more", + "more options", + "navigation", + "reveal", + "show" + ], + "popularity": 23335 + }, + "EXPAND_LESS": { + "tags": [ + "accordion", + "angle up", + "arrow", + "arrow up", + "arrows", + "caret up", + "chevron", + "chevron up", + "close", + "collapse", + "collapse panel", + "content hide", + "contract", + "direction", + "direction up", + "expand", + "expand less", + "expandable", + "fold", + "hide", + "indicator up", + "less", + "list", + "menu collapse", + "minimize", + "minimize panel", + "narrow", + "navigation up", + "pointer up", + "reduce", + "reveal less", + "scroll up", + "section close", + "shrink", + "sort ascending", + "toggle up", + "up" + ], + "popularity": 110892 + }, + "EXPAND_MORE": { + "tags": [ + "accordion", + "arrow", + "arrows", + "caret", + "caret-down", + "chevron", + "collapse", + "control", + "detail", + "direction", + "disclose", + "down", + "dropdown", + "expand", + "expandable", + "expander", + "filter", + "indicator", + "information", + "less", + "list", + "menu", + "more", + "navigation", + "open", + "pointer", + "reveal", + "selection", + "show", + "sort", + "toggle", + "unfold", + "v-shape" + ], + "popularity": 356521 + }, + "EXPLICIT": { + "tags": [ + "access", + "adult", + "advisory", + "alphabet", + "block", + "caution", + "character", + "clear", + "content", + "control", + "definite", + "direct", + "distinct", + "e", + "explicit", + "filter", + "flag", + "font", + "graphic", + "hide", + "inappropriate", + "label", + "language", + "letters", + "mature", + "media", + "movies", + "music", + "parental", + "plain", + "restricted", + "reveal", + "sensitive", + "sexual", + "specific", + "symbol", + "text", + "type", + "uncensored", + "unhide", + "violence", + "warning" + ], + "popularity": 2168 + }, + "EXPLORE": { + "tags": [ + "adventure", + "browse", + "compass", + "curiosity", + "destination", + "direction", + "discover", + "discovery", + "east", + "explore", + "find", + "globe", + "guide", + "investigate", + "journey", + "location", + "map", + "maps", + "marker", + "navigate", + "navigation", + "needle", + "new", + "north", + "path", + "pin", + "roam", + "search", + "seek", + "sightseeing", + "south", + "travel", + "uncharted", + "wander", + "west", + "world" + ], + "popularity": 51064 + }, + "EXPLORE_OFF": { + "tags": [ + "adventure off", + "compass", + "compass blocked", + "compass off", + "destination", + "direction", + "directions off", + "disable exploration", + "disabled", + "discover blocked", + "discover off", + "east", + "enabled", + "explore", + "explore blocked", + "explore off", + "find blocked", + "find off", + "geo off", + "globe off", + "gps off", + "guidance blocked", + "guidance disabled", + "journey off", + "location", + "location disabled", + "map off", + "maps", + "navigation blocked", + "navigation disabled", + "needle", + "north", + "off", + "on", + "orientation off", + "pinpoint off", + "route blocked", + "route off", + "satellite off", + "search off", + "slash", + "south", + "tag off", + "travel", + "travel off", + "west", + "world off" + ], + "popularity": 2425 + }, + "EXPOSURE": { + "tags": [ + "add", + "adjustment", + "bar", + "brightness", + "camera", + "contrast", + "controls", + "edit", + "editing", + "effect", + "exposure", + "graphic", + "image", + "indicator", + "iso", + "level", + "light", + "lines", + "minus", + "photo", + "photography", + "picture", + "plus", + "scale", + "settings", + "slider", + "subtract", + "toggle", + "visual" + ], + "popularity": 2905 + }, + "EXPOSURE_NEG_1": { + "tags": [ + "1", + "adjust", + "brightness", + "brightness adjustment", + "camera control", + "contrast", + "controls", + "dark", + "darker", + "decrease", + "digit", + "dim", + "edit", + "editing", + "effect", + "exposure", + "exposure level", + "filter", + "image", + "image adjustment", + "level", + "light", + "light adjustment", + "minus", + "minus one", + "neg", + "negative", + "numbers", + "photo", + "photo editing", + "photo effect", + "photography", + "photography editing", + "settings", + "subtract", + "symbol", + "value" + ], + "popularity": 1512 + }, + "EXPOSURE_NEG_2": { + "tags": [ + "2", + "adjust", + "brightness", + "camera", + "contrast", + "control", + "correction", + "dark", + "decrement", + "digit", + "edit", + "editing", + "effect", + "exposure", + "image", + "indicator", + "level", + "light", + "media", + "meter", + "minus", + "multimedia", + "neg", + "negative", + "number", + "numbers", + "photo", + "photographic", + "photography", + "picture", + "processing", + "setting", + "settings", + "slider", + "subtract", + "symbol", + "two" + ], + "popularity": 1020 + }, + "EXPOSURE_PLUS_1": { + "tags": [ + "1", + "add", + "adjustment", + "arithmetic", + "brightness", + "button", + "camera setting", + "contrast", + "count", + "counter", + "digit", + "edit", + "editing", + "effect", + "exposure", + "exposure plus one", + "image", + "increase", + "increment", + "increment value", + "math", + "number", + "numbers", + "numerical", + "numerical increment", + "numerical value", + "one", + "photo", + "photography", + "plus", + "plus one", + "plus sign", + "setting", + "settings", + "sign", + "symbol", + "ui control", + "value" + ], + "popularity": 3032 + }, + "EXPOSURE_PLUS_2": { + "tags": [ + "2", + "add", + "adjust", + "adjustment", + "brightness", + "contrast", + "darkroom", + "digit", + "digital", + "edit", + "editing", + "effect", + "enhancement", + "exposure", + "filter", + "graphic", + "image", + "image editing", + "increase", + "levels", + "math", + "modify", + "number", + "number 2", + "numbers", + "photo", + "photo editor", + "photography", + "picture", + "plus", + "plus 2", + "positive", + "settings", + "symbol", + "two" + ], + "popularity": 1658 + }, + "EXPOSURE_ZERO": { + "tags": [ + "0", + "adjust", + "balance", + "brightness", + "camera", + "centered", + "contrast", + "control", + "default", + "digit", + "digital", + "edit", + "editing", + "editor", + "effect", + "exposure", + "image", + "level", + "light", + "midpoint", + "multimedia", + "neutral", + "numbers", + "photo", + "photography", + "point", + "reset", + "setting", + "settings", + "slider", + "symbol", + "value", + "visual", + "zero" + ], + "popularity": 2366 + }, + "EXTENSION": { + "tags": [ + "addon", + "app", + "browser-extension", + "compatibility", + "component", + "connect", + "connection", + "extended", + "extension", + "feature", + "fit", + "game", + "integration", + "interlocking", + "jigsaw", + "logic", + "modular", + "module", + "piece", + "plugin", + "plugin add", + "problem-solving", + "puzzle", + "shape", + "software", + "solve", + "system", + "tool", + "utility" + ], + "popularity": 30057 + }, + "EXTENSION_OFF": { + "tags": [ + "addon", + "block", + "browser", + "cancel", + "component", + "deactivate", + "diagonal", + "disable", + "disabled", + "disconnected", + "enabled", + "extended", + "extension", + "forbidden", + "inactive", + "integration", + "jigsaw", + "missing", + "module", + "off", + "on", + "piece", + "plugin", + "puzzle", + "remove", + "restrict", + "shape", + "slash", + "stop", + "tools" + ], + "popularity": 2142 + }, + "FACE": { + "tags": [ + "access", + "account", + "authentication", + "authorized", + "biometric", + "biometric scan", + "emoji", + "eyes", + "face", + "faceid", + "head", + "human", + "identification", + "identity", + "lock", + "log", + "login", + "logout", + "passcode", + "people", + "person", + "personal", + "portrait", + "private", + "profile", + "protected", + "recognition", + "safe", + "scan", + "secure", + "security", + "social", + "thumbnail", + "unlock", + "user", + "verify" + ], + "popularity": 161296 + }, + "FACE_2": { + "tags": [ + "account", + "amiable", + "avatar", + "character", + "cheerful", + "contentment", + "delightful", + "emoji", + "emoticon", + "emotion", + "expression", + "eyes", + "face", + "feeling", + "grin", + "happy", + "human", + "identity", + "joy", + "lock", + "log", + "login", + "logout", + "mood", + "people", + "person", + "pleasant", + "pleased", + "positivity", + "profile", + "recognition", + "satisfaction", + "security", + "smiling", + "social", + "thumbnail", + "unlock", + "user" + ], + "popularity": 2132 + }, + "FACE_3": { + "tags": [ + "account", + "avatar", + "avatar 3", + "avatar icon", + "emoji", + "eyes", + "face", + "features", + "figure", + "head", + "human", + "lock", + "log", + "login", + "logout", + "male", + "man", + "mouth", + "nose", + "people", + "person", + "person 3", + "person icon", + "portrait", + "profile", + "profile 3", + "profile icon", + "recognition", + "security", + "social", + "thumbnail", + "unlock", + "user", + "user 3", + "user icon", + "young" + ], + "popularity": 2887 + }, + "FACE_4": { + "tags": [ + "account", + "avatar", + "bland", + "character", + "circle", + "emoji", + "emotion", + "expression", + "eyes", + "face", + "features", + "generic", + "head", + "human", + "identity", + "lock", + "log", + "login", + "logout", + "mouth", + "neutral", + "nose", + "outline", + "people", + "person", + "plain", + "portrait", + "profile", + "recognition", + "rounded", + "security", + "simple", + "smiley", + "social", + "thumbnail", + "unlock", + "user" + ], + "popularity": 2077 + }, + "FACE_5": { + "tags": [ + "account", + "avatar", + "avatar icon", + "character", + "communication", + "emoji", + "emotion", + "expression", + "eyes", + "face", + "feelings", + "happy", + "happy face", + "head", + "human", + "identity", + "individual", + "joy", + "lock", + "log", + "login", + "logout", + "people", + "person", + "person icon", + "portrait", + "profile", + "profile picture", + "recognition", + "security", + "smile icon", + "smiley", + "smiling", + "social", + "thumbnail", + "unlock", + "user", + "user icon" + ], + "popularity": 1501 + }, + "FACE_6": { + "tags": [ + "account", + "avatar", + "cheerful", + "contented", + "delighted", + "emoji", + "emotion", + "expression", + "eyes", + "face", + "grin", + "happy", + "head", + "human", + "joy", + "lock", + "log", + "login", + "logout", + "mouth", + "people", + "person", + "pleased", + "profile", + "recognition", + "satisfied", + "security", + "smiling", + "social", + "thumbnail", + "unlock", + "user" + ], + "popularity": 2918 + }, + "FACE_RETOUCHING_NATURAL": { + "tags": [ + "adjust", + "ai", + "artificial", + "automatic", + "automation", + "avatar", + "beauty", + "camera", + "clean", + "clear", + "custom", + "edit", + "editing", + "effect", + "emoji", + "emotion", + "enhancement", + "face", + "faces", + "filter", + "genai", + "glow", + "head", + "image", + "improve", + "intelligence", + "magic", + "natural", + "perfect", + "photo", + "photography", + "picture", + "portrait", + "profile", + "remove imperfections", + "retouch", + "retouching", + "settings", + "skin", + "smart", + "smooth", + "spark", + "sparkle", + "star", + "studio", + "tag", + "technology", + "video" + ], + "popularity": 7606 + }, + "FACE_RETOUCHING_OFF": { + "tags": [ + "avatar", + "beauty", + "blemish", + "block", + "cancel", + "circle", + "disable", + "disabled", + "edit", + "editing", + "effect", + "emoji", + "emotion", + "enabled", + "enhance", + "eye", + "face", + "faces", + "features", + "filter", + "head", + "human", + "image", + "imperfect", + "mouth", + "natural", + "off", + "on", + "person", + "photo", + "photography", + "portrait", + "profile", + "remove", + "retouch", + "retouching", + "settings", + "skin", + "slash", + "tag", + "user" + ], + "popularity": 1477 + }, + "FACT_CHECK": { + "tags": [ + "accuracy", + "accurate", + "approval", + "approve", + "audit", + "authentic", + "authenticity", + "certification", + "certify", + "check", + "complete", + "confirm", + "confirmation", + "correct", + "correctness", + "data", + "document", + "done", + "evidence", + "fact", + "fact check", + "information", + "list", + "mark", + "ok", + "quality", + "reliability", + "reliable", + "review", + "select", + "tick", + "true", + "truth", + "validate", + "validation", + "verification", + "verified", + "verify", + "yes" + ], + "popularity": 86378 + }, + "FACTORY": { + "tags": [ + "architecture", + "assembly", + "automation", + "building", + "business", + "chimney", + "commerce", + "construction", + "development", + "economy", + "energy", + "fabrication", + "facility", + "factory", + "industrial", + "industry", + "infrastructure", + "manufacturing", + "plant", + "power", + "processing", + "production", + "smokestack", + "structure", + "warehouse" + ], + "popularity": 12892 + }, + "FAMILY_RESTROOM": { + "tags": [ + "accessibility", + "amenities", + "baby", + "bathroom", + "changing station", + "child", + "children", + "directional", + "facilities", + "facility", + "family", + "family bathroom", + "family restroom", + "family toilet", + "father", + "gender", + "gender neutral bathroom", + "gender neutral restroom", + "gender neutral toilet", + "human", + "kids", + "lavatory", + "men", + "mother", + "navigation", + "parents", + "people", + "person", + "public area", + "public bathroom", + "public restroom", + "public toilet", + "restroom", + "services", + "signage", + "toilet", + "wc", + "women" + ], + "popularity": 14897 + }, + "FAST_FORWARD": { + "tags": [ + "accelerate", + "action", + "advance", + "arrow", + "audio", + "audio visual", + "button", + "content", + "control", + "direction", + "double arrow", + "entertainment", + "fast", + "fast forward", + "forward", + "media", + "media control", + "move forward", + "music", + "next", + "play", + "playback", + "player", + "progress", + "right arrow", + "skip", + "speed", + "streaming", + "symbol", + "time", + "timeline", + "tv", + "ui element", + "video" + ], + "popularity": 18918 + }, + "FAST_REWIND": { + "tags": [ + "accelerate", + "audio", + "back", + "backward", + "control", + "double arrows", + "fast", + "go back", + "instant", + "jump", + "jump back", + "left arrows", + "media", + "move back", + "multimedia", + "music", + "navigation", + "play", + "playback", + "player", + "previous", + "quickly", + "reverse", + "rewind", + "skip", + "speed", + "time", + "transport", + "tv", + "video" + ], + "popularity": 11271 + }, + "FASTFOOD": { + "tags": [ + "american food", + "bun", + "burger", + "burger icon", + "cheeseburger", + "circle", + "circle with rectangle", + "cuisine", + "delivery", + "dinner", + "drink", + "eat", + "fast food", + "fast food icon", + "fastfood", + "food", + "food and drink", + "food and drink icon", + "food icon", + "hamburger", + "lunch", + "maps", + "meal", + "order food", + "patty", + "places", + "restaurant", + "restaurant icon", + "round", + "sandwich", + "sesame seeds", + "snack", + "takeaway" + ], + "popularity": 15571 + }, + "FAVORITE": { + "tags": [ + "affection", + "appreciate", + "appreciation", + "bookmark", + "border", + "button", + "collection", + "data", + "empty", + "engagement", + "favorite", + "feedback", + "full", + "heart", + "icon", + "interest", + "item", + "like", + "love", + "media", + "object", + "outline", + "rating", + "remember", + "save", + "shape", + "social", + "solid", + "status", + "symbol", + "toggle", + "wish list" + ], + "popularity": 284309 + }, + "FAVORITE_BORDER": { + "tags": [ + "affection", + "appreciation", + "bookmark", + "border", + "button", + "collection", + "data", + "empty", + "engagement", + "favorite", + "feedback", + "full", + "heart", + "icon", + "interest", + "item", + "like", + "love", + "media", + "object", + "outline", + "rating", + "remember", + "save", + "shape", + "social", + "solid", + "status", + "symbol", + "toggle", + "wish list" + ], + "popularity": 229039 + }, + "FAX": { + "tags": [ + "apparatus", + "appliance", + "business", + "communication", + "data", + "device", + "document", + "electronic", + "equipment", + "fax", + "file", + "hardware", + "line", + "machine", + "message", + "obsolete", + "office", + "office supply", + "paper", + "phone", + "print", + "receive", + "retro", + "scan", + "send", + "technology", + "telecommunications", + "telephone line", + "transfer", + "transmission", + "vintage" + ], + "popularity": 6663 + }, + "FEATURED_PLAY_LIST": { + "tags": [ + "album", + "arrangement", + "audio", + "bullet points", + "collection", + "content", + "document", + "episodes", + "featured", + "file", + "highlighted", + "items", + "lines", + "list", + "media", + "movies", + "music", + "order", + "organized", + "play", + "playlist", + "queue", + "recommended", + "rectangle", + "selection", + "sequence", + "series", + "shows", + "square", + "tracks", + "video", + "videos" + ], + "popularity": 4954 + }, + "FEATURED_VIDEO": { + "tags": [ + "advertised", + "advertisement", + "cinema", + "circle", + "clip", + "content", + "entertainment", + "featured", + "file", + "film", + "footage", + "highlight", + "highlighted", + "important", + "media", + "movie", + "multimedia", + "play", + "player", + "premium", + "recommended", + "recording", + "ring", + "round", + "screen", + "shape", + "spotlight", + "star", + "stream", + "ui icon", + "video", + "watch" + ], + "popularity": 2858 + }, + "FEED": { + "tags": [ + "abstract", + "article", + "atom", + "blog", + "broadcasting", + "circle", + "communication", + "content", + "curves", + "data", + "distribution", + "dots", + "feed", + "headline", + "information", + "information flow", + "internet", + "lines", + "media", + "network", + "news", + "newspaper", + "paper", + "public", + "publishing", + "rss", + "signal", + "social", + "square", + "stream", + "subscription", + "symbol", + "syndicated", + "timeline", + "updates", + "waves", + "web" + ], + "popularity": 41371 + }, + "FEEDBACK": { + "tags": [ + "!", + "alert", + "announcement", + "attention", + "broadcast", + "caution", + "chat", + "chat bubble", + "comment", + "communicate", + "communication", + "conversation", + "danger", + "delivery failed", + "element", + "error", + "exclamation", + "fail", + "failed", + "feedback", + "icon", + "important", + "mark", + "megaphone", + "message", + "news", + "notification", + "public address", + "send failed", + "service", + "sms", + "sound", + "speaker", + "speech", + "symbol", + "text message", + "volume", + "warning" + ], + "popularity": 35883 + }, + "FEMALE": { + "tags": [ + "account", + "addition", + "avatar", + "basic", + "biological", + "biological sex", + "character", + "circle", + "cross", + "female", + "figure", + "gender", + "generic", + "girl", + "health", + "human", + "identity", + "individual", + "lady", + "medical", + "medicine", + "outline", + "person", + "plus", + "profile", + "representation", + "silhouette", + "simple", + "social", + "symbol", + "user", + "woman", + "women" + ], + "popularity": 14689 + }, + "FENCE": { + "tags": [ + "backyard", + "barrier", + "border", + "boundaries", + "boundary", + "boundary line", + "construction", + "defense", + "demarcation", + "door", + "enclosure", + "entrance", + "fence", + "flowers", + "garden", + "gate", + "grass", + "home", + "house", + "landscape", + "nature", + "nest", + "outdoor", + "outline", + "outside", + "perimeter", + "picket fence", + "private", + "property", + "protection", + "railing", + "residential", + "security", + "separation", + "structure", + "wooden", + "yard" + ], + "popularity": 2593 + }, + "FESTIVAL": { + "tags": [ + "art", + "calendar", + "celebration", + "circus", + "community", + "concert", + "culture", + "dance", + "date", + "entertainment", + "event", + "festival", + "fun", + "gathering", + "happy", + "holiday", + "invitation", + "joy", + "local", + "maps", + "meeting", + "music", + "party", + "performance", + "places", + "public", + "schedule", + "show", + "social", + "special occasion", + "tent", + "theatre", + "ticket", + "tour", + "travel" + ], + "popularity": 4842 + }, + "FIBER_DVR": { + "tags": [ + "alphabet", + "box", + "broadcast", + "buttons", + "character", + "communication", + "controls", + "data", + "device", + "digital", + "dvr", + "electronics", + "entertainment", + "fiber", + "fiber dvr", + "font", + "interface", + "letters", + "lines", + "media", + "multimedia", + "network", + "panel", + "playback", + "record", + "recorder", + "recording", + "rectangular", + "square", + "storage", + "streaming", + "symbol", + "system", + "technology", + "television", + "text", + "tv", + "type", + "video" + ], + "popularity": 1045 + }, + "FIBER_MANUAL_RECORD": { + "tags": [ + "active", + "alert", + "audio", + "broadcast", + "button", + "circle", + "connection", + "current", + "dot", + "fiber", + "filled circle", + "indicator", + "live", + "manual", + "marker", + "media", + "notification", + "online", + "play", + "point", + "presence", + "record", + "recording", + "session", + "signal", + "solid circle", + "status", + "streaming", + "video", + "watch" + ], + "popularity": 33661 + }, + "FIBER_NEW": { + "tags": [ + "alphabet", + "broadband", + "cable", + "character", + "circle", + "communication", + "connection", + "cutting edge", + "data", + "development", + "digital", + "dot", + "fast", + "fiber", + "fiber new", + "font", + "futuristic", + "glass", + "high speed", + "innovation", + "internet", + "letters", + "media", + "modern", + "network", + "new", + "optical", + "progress", + "signal", + "speed", + "symbol", + "technology", + "text", + "transmission", + "type" + ], + "popularity": 8629 + }, + "FIBER_PIN": { + "tags": [ + "alphabet", + "broadband", + "cable", + "character", + "communication", + "communication link", + "connection", + "connectivity", + "connector", + "data", + "data transmission", + "digital", + "fiber", + "fiber optic", + "fiber pin", + "font", + "internet", + "internet connection", + "letters", + "network", + "network connection", + "optic cable", + "pin", + "plug", + "port", + "signal", + "signal transmission", + "socket", + "symbol", + "technology", + "text", + "transmission", + "type", + "wire" + ], + "popularity": 1187 + }, + "FIBER_SMART_RECORD": { + "tags": [ + "action", + "audio", + "audio recording", + "automatic", + "automation", + "button", + "capture", + "capture audio", + "capture video", + "circle", + "data", + "disc", + "dot", + "fiber", + "future", + "intelligent", + "media", + "media control", + "multimedia", + "play", + "record", + "recording", + "save", + "save audio", + "save video", + "smart", + "smart record", + "storage", + "streaming", + "technology", + "video", + "video recording", + "watch" + ], + "popularity": 2008 + }, + "FILE_COPY": { + "tags": [ + "archive", + "backup", + "clone", + "content", + "copy", + "create copy", + "cut", + "data", + "doc", + "document", + "duplicate", + "entry", + "file", + "form", + "information", + "make a copy", + "memo", + "multiple", + "note", + "page", + "paperwork", + "past", + "paste", + "print", + "record", + "record book", + "report", + "save a copy", + "sheet", + "stack", + "text", + "transcript", + "version" + ], + "popularity": 31207 + }, + "FILE_DOWNLOAD": { + "tags": [ + "acquire", + "action", + "app", + "application", + "archive", + "arrow", + "arrows", + "bar", + "button", + "cloud", + "computer", + "control", + "data", + "document", + "down", + "download", + "downloads", + "drive", + "export", + "file", + "get", + "incoming", + "install", + "internet", + "line", + "move", + "network", + "obtain", + "pointed", + "receive", + "save", + "storage", + "symbol", + "transfer", + "underscore", + "upload" + ], + "popularity": 183419 + }, + "FILE_DOWNLOAD_DONE": { + "tags": [ + "arrow", + "arrow and check", + "arrows", + "check", + "checkmark", + "complete", + "completed download", + "completed file download", + "confirmation", + "document", + "document and check", + "done", + "down", + "down arrow", + "down arrow and check", + "download", + "download complete", + "download done", + "download finished", + "download successful", + "downloads", + "drive", + "file", + "file download complete", + "file download done", + "file download finished", + "file download successful", + "finished", + "finished download", + "finished file download", + "install", + "installed", + "paper", + "paper and check", + "success", + "successful download", + "successful file download", + "tick", + "upload" + ], + "popularity": 7733 + }, + "FILE_DOWNLOAD_OFF": { + "tags": [ + "arrow", + "blocked", + "cancelled", + "cannot download", + "disabled", + "document access", + "document management", + "down", + "download", + "download blocked", + "download disabled", + "download error", + "download off", + "download problem", + "download restricted", + "download unavailable", + "drive", + "enabled", + "error", + "export", + "failed", + "file", + "file access", + "file download blocked", + "file download disabled", + "file download off", + "file download restricted", + "file download unavailable", + "file error", + "file management", + "file transfer", + "install", + "not downloadable", + "off", + "on", + "problem", + "restricted", + "save", + "slash", + "unavailable", + "upload" + ], + "popularity": 3257 + }, + "FILE_OPEN": { + "tags": [ + "access", + "access file", + "administration", + "application", + "arrow", + "browse", + "business", + "computer", + "data", + "directory", + "doc", + "document", + "drive", + "explore", + "file", + "file open", + "folder", + "folder open", + "information", + "interface", + "left", + "manage", + "office", + "open", + "open document", + "open file", + "page", + "paper", + "record", + "retrieve", + "storage", + "technology", + "view", + "view file" + ], + "popularity": 9351 + }, + "FILE_PRESENT": { + "tags": [ + "business", + "clip", + "collaboration", + "communication", + "conference", + "content", + "data", + "display", + "doc", + "document", + "drive", + "education", + "file", + "folder", + "folders", + "information", + "meeting", + "monitor", + "note", + "office", + "paper", + "present", + "presentation", + "project", + "projector", + "reminder", + "report", + "reveal", + "screen", + "screen sharing", + "share", + "sheet", + "show", + "slide", + "slideshow", + "speaker", + "storage", + "view", + "webinar", + "writing" + ], + "popularity": 16552 + }, + "FILE_UPLOAD": { + "tags": [ + "add", + "arrow", + "arrows", + "attach", + "backup", + "cloud", + "data", + "direction", + "document", + "download", + "drive", + "export", + "file", + "import", + "input", + "internet", + "memory", + "move", + "network", + "open", + "pointer", + "publish", + "save", + "select", + "send", + "server", + "share", + "store", + "submit", + "transfer", + "up", + "upload" + ], + "popularity": 95047 + }, + "FILTER": { + "tags": [ + "adjustments", + "categorization", + "categorize", + "choices", + "collection", + "collections", + "control", + "criteria", + "data", + "edit", + "editing", + "effect", + "filter", + "funnel", + "image", + "landscape", + "list", + "manage", + "management", + "mountain", + "mountains", + "narrow", + "narrowing", + "options", + "organization", + "organize", + "photo", + "photography", + "picture", + "preferences", + "refine", + "refinement", + "rules", + "select", + "selection", + "settings", + "sort", + "sorting", + "view" + ], + "popularity": 4208 + }, + "FILTER_1": { + "tags": [ + "1", + "adjust", + "amount", + "choice", + "control", + "count", + "criteria", + "customization", + "data", + "digit", + "edit", + "editing", + "effect", + "filter", + "filtering", + "funnel", + "image", + "images", + "limit", + "list", + "multiple", + "narrow", + "number", + "numbers", + "one", + "options", + "organize", + "photography", + "picture", + "pictures", + "preferences", + "quantity", + "refined", + "restriction", + "results", + "select", + "settings", + "sort", + "sorting", + "specific", + "stack", + "symbol", + "view" + ], + "popularity": 5200 + }, + "FILTER_2": { + "tags": [ + "2", + "array", + "categorize", + "count", + "customize", + "data", + "digit", + "display", + "edit", + "editing", + "effect", + "filter", + "filter 2", + "filter by 2", + "funnel", + "image", + "images", + "level 2", + "limit", + "list", + "multiple", + "narrow", + "number", + "numbers", + "numeral", + "options", + "parameters", + "photography", + "picture", + "pictures", + "preferences", + "quantity", + "refine", + "results", + "second", + "selection", + "settings", + "sort", + "specifications", + "stack", + "symbol", + "value", + "view" + ], + "popularity": 2979 + }, + "FILTER_3": { + "tags": [ + "3", + "adjust", + "adjustment", + "bars", + "control", + "controls", + "count", + "counting", + "customize", + "data", + "digit", + "edit", + "editing", + "effect", + "filter", + "filters", + "funnel", + "image", + "images", + "line", + "lines", + "list", + "multiple", + "number", + "numbers", + "numeral", + "options", + "photography", + "picture", + "pictures", + "preferences", + "refine", + "refinement", + "select", + "selection", + "settings", + "sort", + "sorting", + "stack", + "symbol", + "three", + "triangle" + ], + "popularity": 2342 + }, + "FILTER_4": { + "tags": [ + "4", + "adjust", + "choose", + "control", + "count", + "criteria", + "data", + "digit", + "digit 4", + "edit", + "editing", + "effect", + "filter", + "four", + "funnel", + "image", + "images", + "level", + "limit", + "list", + "manage", + "multiple", + "narrow", + "number 4", + "numbers", + "options", + "organize", + "photography", + "picture", + "pictures", + "process", + "quantity", + "rank", + "refine", + "restriction.", + "select", + "settings", + "sieve", + "sort", + "stack", + "symbol", + "value" + ], + "popularity": 1712 + }, + "FILTER_5": { + "tags": [ + "5", + "adjust", + "configure", + "constraints", + "count", + "criteria", + "data", + "digit", + "digit five", + "edit", + "editing", + "effect", + "filter", + "filtering data", + "five", + "five items", + "funnel", + "image", + "images", + "items", + "limit", + "multiple", + "number", + "number five", + "number of items", + "numbers", + "options", + "organize", + "photography", + "picture", + "pictures", + "preferences", + "quantity", + "refine", + "restrictions", + "results", + "selection", + "settings", + "sort", + "stack", + "symbol" + ], + "popularity": 1547 + }, + "FILTER_6": { + "tags": [ + "6", + "apply filter", + "count", + "count filter", + "data filter", + "data refinement", + "digit", + "edit", + "editing", + "effect", + "filter", + "filter by number", + "filter count", + "filter results", + "image", + "images", + "item count", + "limit", + "list filter", + "max items", + "multiple", + "number", + "number 6", + "number six", + "numbered filter", + "numbers", + "numeric filter", + "photography", + "picture", + "pictures", + "quantity", + "quantity filter", + "refine", + "refine results", + "settings", + "six", + "six items", + "sort", + "stack", + "symbol" + ], + "popularity": 1273 + }, + "FILTER_7": { + "tags": [ + "7", + "adjust", + "analysis", + "category", + "choose", + "count", + "customize", + "data", + "digit", + "digit 7", + "edit", + "editing", + "effect", + "filter", + "funnel", + "image", + "images", + "limit", + "list", + "manage", + "multiple", + "number", + "number 7", + "numbers", + "options", + "organize", + "photography", + "picture", + "pictures", + "preferences", + "refine", + "restrict", + "results", + "search", + "selection", + "settings", + "seven", + "sieve", + "sorting", + "stack", + "symbol", + "type" + ], + "popularity": 1708 + }, + "FILTER_8": { + "tags": [ + "8", + "adjust", + "categorize", + "constrain", + "control", + "criteria", + "criterion", + "customize", + "data", + "digit", + "digit 8", + "edit", + "editing", + "effect", + "eight", + "filter", + "filtration", + "funnel", + "image", + "images", + "limit", + "modify", + "multiple", + "narrow", + "number 8", + "number.", + "numbers", + "options", + "organize", + "parameters", + "photography", + "picture", + "pictures", + "preferences", + "refine", + "selection", + "settings", + "sifter", + "sort", + "specifications", + "stack", + "symbol" + ], + "popularity": 1344 + }, + "FILTER_9": { + "tags": [ + "9", + "adjust", + "categories", + "control", + "counter", + "criteria", + "data", + "digit", + "edit", + "editing", + "effect", + "filter", + "funnel", + "image", + "images", + "list", + "manage", + "modify", + "multiple", + "narrow", + "nine", + "nine items", + "number", + "numbers", + "options", + "organize", + "parameters", + "photography", + "picture", + "pictures", + "preferences", + "reduce", + "refine", + "select", + "settings", + "sort", + "stack", + "symbol", + "tool" + ], + "popularity": 1339 + }, + "FILTER_9_PLUS": { + "tags": [ + "+", + "9", + "9 plus", + "9+", + "amount", + "criteria", + "data", + "digit", + "edit", + "editing", + "effect", + "filter", + "filtering", + "funnel", + "image", + "images", + "limit", + "limit results", + "multiple", + "nine", + "nine plus", + "number", + "numbers", + "options", + "photography", + "picture", + "pictures", + "plus", + "preferences", + "quantity", + "refine", + "refine results", + "search", + "search filter", + "search options", + "select", + "select criteria", + "selection limit", + "settings", + "sort", + "sort data", + "stack", + "symbol", + "threshold" + ], + "popularity": 1678 + }, + "FILTER_ALT": { + "tags": [ + "adjust", + "arrange", + "choose", + "control", + "customize", + "data", + "edit", + "filter", + "find", + "funnel", + "icon", + "information", + "inverted triangle", + "line", + "list", + "narrow", + "options", + "organize", + "preferences", + "refine", + "refinement", + "search", + "select", + "settings", + "sift", + "sort", + "sorting", + "three lines", + "tool", + "triangle" + ], + "popularity": 147960 + }, + "FILTER_ALT_OFF": { + "tags": [ + "alt", + "clear criteria", + "clear filter", + "clear selection", + "data filter", + "data options", + "disable filter", + "disabled", + "edit", + "filter", + "filter alt off", + "filter disabled", + "filter off", + "filter removed", + "filter state", + "filtering off", + "filtering state off", + "funnel", + "funnel disabled", + "funnel off", + "list filter", + "list options", + "menu filter", + "no filter", + "off", + "offline", + "options", + "options filter", + "refine", + "remove criteria", + "remove filter", + "remove selection", + "reset filter", + "reset selection", + "selection filter", + "sift", + "slash", + "sort off", + "sorting disabled", + "turn off filter", + "undo filter" + ], + "popularity": 10390 + }, + "FILTER_B_AND_W": { + "tags": [ + "and", + "apply", + "b", + "b&w", + "black", + "black and white", + "camera", + "classic", + "color correction", + "contrast", + "darkroom", + "digital", + "edit", + "editing", + "effect", + "filter", + "grayscale", + "image", + "image adjustment", + "images", + "light", + "monochrome", + "negative", + "photo effects", + "photography", + "picture", + "picture settings", + "pictures", + "saturation", + "settings", + "shadow", + "style", + "toggle", + "tone", + "vintage", + "visual", + "w", + "white" + ], + "popularity": 1871 + }, + "FILTER_CENTER_FOCUS": { + "tags": [ + "adjust", + "aiming", + "alignment", + "box", + "calibration", + "camera", + "camera settings", + "center", + "center focus", + "corners", + "crosshair", + "crosshairs", + "dot", + "edit", + "filter", + "filter settings", + "focus", + "framing", + "guides", + "image", + "lens", + "lines", + "optical", + "perspective", + "photo", + "photo editor", + "photo filter", + "photography", + "photography tools", + "picture", + "refine", + "settings", + "square", + "targeting", + "viewfinder" + ], + "popularity": 6562 + }, + "FILTER_DRAMA": { + "tags": [ + "atmosphere", + "cinematic", + "cloud", + "dark", + "drama", + "edit", + "editing", + "effect", + "film", + "filter", + "graphic", + "icon", + "image", + "mood", + "movie", + "ominous", + "photo", + "photography", + "picture", + "processing", + "scene", + "setting", + "sky", + "sky camera", + "special effects", + "stormy", + "symbol", + "tone", + "video", + "visual", + "weather" + ], + "popularity": 7956 + }, + "FILTER_FRAMES": { + "tags": [ + "albums", + "arrangement", + "boarders", + "border", + "camera", + "center", + "depth", + "display", + "edit", + "editing", + "editor", + "effect", + "filter", + "filters", + "focus", + "frame", + "frames", + "frames.", + "gallery", + "image", + "images", + "layering", + "layout", + "multimedia", + "multiple", + "options", + "order", + "organize", + "overlap", + "perspective", + "photo", + "photography", + "picture", + "pictures", + "rectangles", + "screen", + "sequence", + "sort", + "stacked", + "view", + "visual", + "windows" + ], + "popularity": 2052 + }, + "FILTER_HDR": { + "tags": [ + "button", + "camera", + "control", + "earth", + "edit", + "editing", + "effect", + "effects", + "environment", + "filter", + "generic", + "geography", + "graphics", + "hdr", + "hills", + "icon", + "image", + "image adjustment", + "image filter", + "landscape", + "mountain", + "mountains", + "nature", + "outdoors", + "peak", + "photo", + "photo effects", + "photography", + "picture", + "scenery", + "shape", + "simple", + "summit", + "symbol", + "terrain", + "ui", + "ux", + "view", + "vista" + ], + "popularity": 2455 + }, + "FILTER_LIST": { + "tags": [ + "arrange", + "bar", + "bar graph", + "bars", + "categorize", + "control", + "criteria", + "filter", + "filtering", + "horizontal", + "lines", + "list", + "manage", + "menu", + "narrow", + "options", + "options menu", + "organize", + "preferences", + "preferences menu", + "refine", + "settings", + "settings menu", + "sort", + "sorting", + "stacked", + "three bars", + "three lines" + ], + "popularity": 75383 + }, + "FILTER_LIST_OFF": { + "tags": [ + "alt", + "bars", + "choices", + "clear", + "control", + "data", + "disable", + "disabled", + "disabled filter", + "display", + "edit", + "exclusion", + "filter", + "filtering", + "inactive", + "information", + "lines", + "list", + "management", + "menu", + "not filtering", + "off", + "offline", + "options", + "organize", + "preferences", + "refine", + "remove", + "rows", + "selection", + "settings", + "sift", + "slash", + "sorting", + "toggle", + "unfilter", + "view" + ], + "popularity": 4218 + }, + "FILTER_NONE": { + "tags": [ + "basic", + "blank", + "clean", + "clear", + "default", + "empty", + "filter", + "multiple", + "no change", + "no effect", + "no filter", + "none", + "normal", + "null", + "original", + "pristine", + "pure", + "remove filter", + "reset", + "revert", + "square", + "stack", + "standard", + "transparent", + "unapplied", + "unedited", + "unenhanced", + "unfiltered", + "unfiltered data", + "unfiltered image", + "unfiltered results", + "without", + "zero" + ], + "popularity": 6781 + }, + "FILTER_TILT_SHIFT": { + "tags": [ + "adjustment", + "aperture", + "blur", + "camera", + "center", + "circle", + "circular", + "control", + "dash", + "dashed", + "depth of field", + "dot", + "edit", + "editing", + "effect", + "filter", + "filter settings", + "focus", + "image", + "images", + "lens", + "lens focus", + "miniature", + "optic", + "perspective", + "photo", + "photography", + "photography tool", + "picture", + "pictures", + "point", + "precision", + "settings", + "shift", + "target", + "tilt", + "tilt shift", + "zoom" + ], + "popularity": 2875 + }, + "FILTER_VINTAGE": { + "tags": [ + "abstract", + "adjust", + "bloom", + "blossom", + "camera", + "decorative", + "edit", + "editing", + "effect", + "filter", + "flower", + "graphic", + "image", + "images", + "lotus", + "nature", + "ornate", + "photo", + "photography", + "picture", + "pictures", + "plant", + "swirl", + "vintage" + ], + "popularity": 8305 + }, + "FIND_IN_PAGE": { + "tags": [ + "content search", + "data", + "doc", + "document", + "document icon", + "document search", + "drive", + "file", + "file icon", + "file search", + "find", + "find icon", + "find in page", + "folder", + "folders", + "glass", + "in", + "information retrieval", + "locate", + "locate text", + "look", + "look up", + "loupe", + "magnifier", + "magnify", + "magnifying", + "magnifying glass", + "magnifying glass on document", + "open document", + "page", + "page search", + "paper", + "paper search", + "rectangle", + "scan", + "search", + "search icon", + "search tool", + "see", + "sheet", + "sheet of paper", + "slide", + "text icon", + "text search", + "view document", + "writing" + ], + "popularity": 24743 + }, + "FIND_REPLACE": { + "tags": [ + "action", + "application", + "around", + "arrows", + "button", + "command", + "content", + "control", + "data", + "discover", + "document", + "edit", + "file", + "find", + "glass", + "inprogress", + "interface element", + "load", + "loading refresh", + "locate", + "look", + "loupe", + "magnifier", + "magnify", + "magnifying", + "magnifying glass", + "modify", + "program", + "query", + "renew", + "replace", + "rotate", + "search", + "see", + "software", + "string", + "text", + "tool", + "utility", + "zoom" + ], + "popularity": 6530 + }, + "FINGERPRINT": { + "tags": [ + "access", + "authentication", + "authorized", + "biometric", + "circles", + "confirm", + "curves", + "data", + "digit", + "digital", + "finger", + "fingerprint", + "human", + "id", + "identification", + "identity", + "lines", + "log in", + "oval", + "personal", + "print", + "privacy", + "reader", + "scan", + "security", + "sign in", + "swirls", + "technology", + "thumbprint", + "touch id", + "unique", + "unlock", + "verification", + "verify" + ], + "popularity": 142000 + }, + "FIRE_EXTINGUISHER": { + "tags": [ + "alarm", + "alert", + "control", + "cylinder", + "danger", + "device", + "element", + "emergency", + "equipment", + "extinguish", + "extinguisher", + "fire", + "fire extinguisher", + "flame", + "graphic", + "handle", + "hazard", + "hose", + "icon", + "lever", + "minimal", + "nozzle", + "prevention", + "protection", + "rescue", + "safety", + "security", + "simple", + "symbol", + "tool", + "ui", + "warning", + "water" + ], + "popularity": 3268 + }, + "FIRE_HYDRANT_ALT": { + "tags": [], + "popularity": 522 + }, + "FIRE_TRUCK": { + "tags": [ + "accident", + "aid", + "alarm", + "alert", + "automotive", + "danger", + "emergency", + "emergency services", + "emergency vehicle", + "fire and rescue", + "fire department", + "fire engine", + "fire truck", + "firefighting", + "help", + "hose", + "ladder", + "rescue", + "response", + "safety", + "security", + "service", + "siren", + "transport", + "transport icon", + "transportation", + "truck", + "vehicle", + "vehicle icon", + "warning" + ], + "popularity": 1395 + }, + "FIREPLACE": { + "tags": [ + "barbecue", + "burning", + "camping", + "chimney", + "comfort", + "cooking", + "cozy", + "ember", + "energy", + "fire", + "fireplace", + "flame", + "fuel", + "glow", + "grill", + "hearth", + "heat", + "heating", + "home", + "house", + "ignition", + "indoor", + "living", + "living room", + "logs", + "nature", + "outdoor", + "pit", + "place", + "room", + "spark", + "survival", + "warm", + "warmth", + "winter" + ], + "popularity": 5527 + }, + "FIRST_PAGE": { + "tags": [ + "arrow", + "back", + "beginning", + "book", + "caret", + "chevron", + "control", + "data", + "document", + "file", + "first", + "jump", + "jump back", + "left", + "list", + "media", + "media control", + "move", + "navigation", + "page", + "play", + "playback", + "presentation", + "previous", + "reverse", + "rewind", + "skip back", + "slide", + "start", + "step", + "transport" + ], + "popularity": 17392 + }, + "FIT_SCREEN": { + "tags": [ + "adjust", + "arrows", + "aspect ratio", + "boundary", + "box", + "corners", + "diagonal arrows", + "display", + "enlarge", + "expand", + "fit", + "fit to screen", + "format", + "frame", + "full screen", + "fullscreen", + "grow", + "layout", + "maximize", + "media", + "monitor", + "rectangle", + "reduce", + "scale", + "screen", + "size", + "stretch", + "video player", + "view", + "window", + "zoom" + ], + "popularity": 8831 + }, + "FITBIT": { + "tags": [ + "abstract", + "activity", + "app", + "application", + "athlete", + "athletic", + "brand", + "brand identity", + "company", + "corporate", + "device", + "digital", + "exercise", + "fitbit", + "fitness", + "glyph", + "health", + "heart", + "hobby", + "logo", + "logotype", + "modern", + "monitoring", + "pulse", + "smart device", + "sport", + "symbol", + "technology", + "tracking", + "trademark", + "wearable" + ], + "popularity": 3539 + }, + "FITNESS_CENTER": { + "tags": [ + "active", + "athlete", + "athletics", + "barbell", + "bodybuilding", + "center", + "dumbbell", + "exercise", + "fitness", + "fitness center", + "fitness club", + "gym", + "gym class", + "gym equipment", + "health", + "health club", + "hobby", + "lifting", + "muscle", + "personal training", + "physical activity", + "places", + "sport", + "strength", + "training", + "training equipment", + "weightlifting", + "weights", + "workout", + "workout center" + ], + "popularity": 29188 + }, + "FLAG": { + "tags": [ + "achievement", + "banner", + "bookmark", + "border", + "country", + "destination", + "emoji", + "empty", + "flag", + "flags", + "goal", + "highlight", + "indicator", + "label", + "landmark", + "location", + "mark", + "marker", + "milepost", + "milestone", + "nation", + "national", + "notice", + "outline", + "pennant", + "pin", + "place", + "pole", + "report", + "save", + "signal", + "social", + "standard", + "start", + "territory", + "unfilled", + "world" + ], + "popularity": 47452 + }, + "FLAG_CIRCLE": { + "tags": [ + "circle", + "country", + "destination", + "direction", + "emblem", + "filled", + "finish line", + "flag", + "geography", + "goal", + "international", + "location", + "mark", + "marker", + "nation", + "national", + "navigation", + "outline", + "patriotism", + "pinpoint", + "place", + "pointer", + "position", + "race", + "region", + "report", + "round", + "spot", + "start", + "symbol", + "territory" + ], + "popularity": 5170 + }, + "FLAKY": { + "tags": [ + "actions", + "app menu", + "approve", + "check", + "close", + "close menu", + "collapse", + "collapsed menu", + "complete", + "contrast", + "done", + "drawer", + "exit", + "expand", + "expanded menu", + "flaky", + "hamburger", + "hide menu", + "horizontal lines", + "lines", + "list", + "mark", + "menu", + "mobile menu", + "more", + "more options", + "navigation", + "no", + "ok", + "open menu", + "options", + "primary menu", + "select", + "show menu", + "side navigation", + "sidebar", + "stacked lines", + "stop", + "three lines", + "tick", + "toggle", + "verified", + "website navigation", + "x", + "yes" + ], + "popularity": 8638 + }, + "FLARE": { + "tags": [ + "blast", + "bright", + "burst", + "burst of light", + "camera", + "edit", + "editing", + "effect", + "flare", + "flash", + "gleam", + "glint", + "glow", + "highlight", + "illumination", + "image", + "images", + "lens flare", + "light", + "optical", + "optical effect", + "photography", + "picture", + "pictures", + "ray of light", + "shimmer", + "shine", + "sparkle", + "special effect", + "star", + "sun", + "visual effect" + ], + "popularity": 6912 + }, + "FLASH_AUTO": { + "tags": [ + "a", + "auto", + "auto mode", + "automatic", + "bolt", + "bright", + "burst", + "camera", + "capture", + "choosing", + "control", + "electric", + "electricity", + "energy", + "fast", + "flash", + "highlight", + "image", + "instant", + "light", + "lightning", + "mode", + "off", + "on", + "option", + "photo", + "photography", + "picture", + "power", + "selection", + "setting", + "symbol", + "thunderbolt", + "toggle", + "video", + "zap" + ], + "popularity": 2601 + }, + "FLASH_OFF": { + "tags": [ + "bolt", + "camera control", + "camera flash", + "camera option", + "camera setting", + "dark", + "deactivate", + "disable flash", + "disable light", + "disabled", + "electric", + "enabled", + "energy", + "fast", + "flash", + "flash disabled", + "flash off", + "flash setting", + "instant", + "light off", + "lighting", + "lighting off", + "lightning", + "low light", + "mode off", + "no flash", + "not lit", + "off", + "on", + "photo setting", + "photography", + "photography icon", + "photography tool", + "setting disabled", + "slash", + "thunderbolt", + "turn off", + "visual setting" + ], + "popularity": 6031 + }, + "FLASH_ON": { + "tags": [ + "activate", + "alert", + "bolt", + "bright", + "camera", + "camera flash", + "danger", + "disabled", + "electric", + "electricity", + "enabled", + "energy", + "fast", + "flash", + "glow", + "illuminate", + "indication", + "instant", + "light", + "lighting", + "lightning", + "notification", + "off", + "on", + "photo", + "photo flash", + "photography", + "power", + "shine", + "slash", + "status", + "thunder", + "thunderbolt", + "toggle", + "turn on", + "warning" + ], + "popularity": 19823 + }, + "FLASHLIGHT_OFF": { + "tags": [ + "beam off", + "brightness.", + "button", + "control", + "dark", + "deactivate", + "device", + "disabled", + "electric", + "enabled", + "flash", + "flashlight", + "flashlight off", + "icon", + "illumination", + "inactive", + "lamp off", + "light", + "light off", + "night", + "off", + "off state", + "on", + "outline", + "portable light", + "power off", + "shape", + "slash", + "symbol", + "toggle off", + "tool", + "torch off", + "turn off", + "ui element", + "utility", + "visibility" + ], + "popularity": 2323 + }, + "FLASHLIGHT_ON": { + "tags": [ + "activated", + "beam", + "bright", + "button", + "camping", + "circle", + "cone of light", + "conical", + "disabled", + "discovery", + "emergency", + "enabled", + "flash", + "flashlight", + "guidance", + "handheld", + "handle", + "illuminated", + "illumination", + "light", + "navigation", + "off", + "on", + "outdoor", + "portable", + "ray", + "round", + "shine", + "slash", + "spotlight", + "torch", + "visibility" + ], + "popularity": 5588 + }, + "FLATWARE": { + "tags": [ + "cafe", + "cafeteria", + "catering", + "cooking", + "cutlery", + "diner", + "dining", + "dinner", + "dishware", + "eat", + "eating", + "flatware", + "food", + "fork", + "glyph", + "kitchen", + "knife", + "local", + "meal", + "menu", + "outline", + "pictogram", + "restaurant", + "serving", + "silverware", + "simple", + "spoon", + "table setting", + "tools", + "utensils" + ], + "popularity": 5159 + }, + "FLIGHT": { + "tags": [ + "ai", + "air", + "air travel", + "aircraft", + "airplane", + "airplanes", + "airport", + "arrival", + "arrow", + "artificial intelligence", + "automation", + "clover", + "departure", + "direction", + "flight", + "flight mode", + "flights", + "fly", + "flying", + "flying mode", + "forward", + "genai", + "icon", + "intelligence", + "jet", + "magic", + "mode", + "move", + "navigation", + "on", + "plane", + "planes", + "point", + "settings", + "signal", + "silhouette", + "sky", + "spark", + "sparkle", + "speed", + "star", + "symbol", + "transport", + "transportation", + "travel", + "trip", + "vehicle" + ], + "popularity": 29544 + }, + "FLIGHT_CLASS": { + "tags": [ + "aerial", + "air", + "air travel", + "aircraft", + "airline", + "airplane", + "airplanes", + "airport", + "aisle", + "aviation", + "booking", + "business", + "business class", + "cabin", + "class", + "comfort", + "economy", + "first class", + "flight", + "flights", + "fly", + "flying", + "journey", + "passenger", + "passenger experience", + "plane", + "planes", + "reservation", + "seat", + "seating", + "service", + "signal", + "transport", + "transportation", + "travel", + "trip", + "vacation", + "window seat" + ], + "popularity": 1284 + }, + "FLIGHT_LAND": { + "tags": [ + "air", + "aircraft", + "airplane", + "airplanes", + "airport", + "arrival", + "arrivals", + "arriving", + "aviation", + "departing", + "departure", + "descent", + "downward", + "flight", + "flight arrival", + "flight landing", + "flights", + "fly", + "flying", + "land", + "land flight", + "land plane", + "landing", + "plane", + "planes", + "signal", + "transportation", + "travel", + "travel arrival", + "travel landing", + "trip" + ], + "popularity": 9774 + }, + "FLIGHT_TAKEOFF": { + "tags": [ + "air", + "air transport", + "air travel", + "aircraft", + "airplane", + "airplanes", + "airport", + "arrival", + "arriving", + "arrow", + "ascending", + "aviation", + "departing", + "departure", + "diagonal", + "flight", + "flights", + "fly", + "flying", + "journey", + "landing", + "mobility", + "moving", + "moving forward", + "plane", + "planes", + "signal", + "takeoff", + "takeoff runway", + "transport", + "transportation", + "travel", + "trip", + "up", + "voyage", + "wing" + ], + "popularity": 34371 + }, + "FLIP": { + "tags": [ + "actions", + "adjust", + "arrow", + "change", + "change direction", + "commands", + "dash", + "dashed", + "direction", + "edit", + "editing", + "flip", + "horizontal flip", + "image", + "mirror", + "modify", + "opposing arrows", + "options", + "orientation", + "pivot", + "reflect", + "reverse", + "rotate", + "scan scanning", + "settings", + "spin", + "swap", + "switch", + "tools", + "transform", + "turn", + "two arrows", + "update", + "vertical flip" + ], + "popularity": 5508 + }, + "FLIP_CAMERA_ANDROID": { + "tags": [ + "android", + "arrows", + "back camera", + "camera", + "camera direction", + "camera icon", + "camera perspective", + "camera switch", + "center", + "change camera", + "circle", + "circular arrows", + "device", + "direction", + "edit", + "editing", + "flip", + "flip camera", + "front camera", + "image", + "mobile", + "orientation", + "photo", + "photography", + "rear camera", + "reverse camera", + "rotate", + "self camera", + "selfie", + "square", + "switch camera", + "turn", + "two arrows", + "video", + "video recording" + ], + "popularity": 5602 + }, + "FLIP_CAMERA_IOS": { + "tags": [ + "android", + "arrows", + "camera", + "camera toggle", + "capture", + "change", + "circle", + "control", + "device", + "direction", + "disable_ios", + "edit", + "editing", + "flip", + "flip camera", + "front camera", + "image", + "ios", + "media", + "mobile", + "orientation", + "photo", + "photography", + "picture", + "rear camera", + "record", + "rotate", + "rotate camera", + "selfie camera", + "smartphone", + "swap", + "switch camera", + "turn", + "video", + "video call", + "video chat" + ], + "popularity": 5016 + }, + "FLIP_TO_BACK": { + "tags": [ + "arrange", + "arrangement", + "back", + "bring forward", + "bring to front", + "dash", + "dashed", + "depth", + "element", + "flip", + "format", + "front", + "group", + "layering", + "layers", + "layout", + "move", + "move back", + "move backward", + "move forward", + "move front", + "objects", + "order", + "organize", + "overlap", + "overlay", + "position", + "reorder", + "send backward", + "send to back", + "sort", + "stack", + "to", + "z-index" + ], + "popularity": 2981 + }, + "FLIP_TO_FRONT": { + "tags": [ + "arrange", + "arrangement", + "ascend", + "back", + "bring forward", + "bring to top", + "card", + "dash", + "dashed", + "depth", + "elevate", + "flip", + "flip over", + "flip to front", + "format", + "front", + "layer", + "layout", + "move", + "move forward", + "order", + "overlap", + "overlay", + "perspective", + "positioning", + "rearrange", + "reorder", + "reorganize", + "send to front", + "sort", + "stack", + "to", + "two cards", + "z-index" + ], + "popularity": 4326 + }, + "FLOOD": { + "tags": [ + "abstract waves", + "alert", + "climate", + "climate change", + "crisis", + "danger", + "deluge", + "disaster", + "drowning", + "emergency", + "environmental", + "extreme weather", + "flood", + "flooding", + "flowing water", + "hazard", + "heavy rain", + "high water", + "inundation", + "liquid", + "natural", + "natural disaster", + "rain", + "rising water", + "storm", + "warning", + "water", + "wave", + "waves", + "wavy lines", + "weather" + ], + "popularity": 1400 + }, + "FLUORESCENT": { + "tags": [ + "adjustments", + "bright", + "brightness", + "camera", + "effects", + "electric", + "electricity", + "energy", + "filter", + "fluorescent", + "gleam", + "glow", + "illumination", + "image", + "incandescent", + "iridescent", + "lamp", + "light", + "light bulb", + "lightbulb", + "lighting", + "photo", + "photography", + "picture", + "power", + "settings", + "shimmer", + "sparkle", + "tungsten", + "wb", + "white balance" + ], + "popularity": 616 + }, + "FLUTTER_DASH": { + "tags": [ + "abstract", + "animal", + "app", + "app development", + "application", + "bird", + "brand", + "cartoon", + "character", + "coding", + "cross-platform", + "dash", + "development", + "fast", + "flutter", + "framework", + "futuristic", + "google", + "logo", + "mascot", + "mobile", + "open source", + "program", + "programming", + "software", + "speed", + "stylized", + "technology", + "winged" + ], + "popularity": 23600 + }, + "FMD_BAD": { + "tags": [ + "!", + "address", + "alert", + "attention", + "bad", + "blocked", + "caution", + "cross", + "danger", + "denied", + "destination", + "direction", + "disabled", + "error", + "exclamation", + "fail", + "fmd", + "geo", + "geotag", + "gps", + "important", + "incorrect", + "invalid", + "location", + "map", + "maps", + "mark", + "marker", + "navigation", + "notification", + "pin", + "pinpoint", + "place", + "position", + "problem", + "stop", + "symbol", + "unavailable", + "warning", + "wrong", + "x" + ], + "popularity": 5653 + }, + "FMD_GOOD": { + "tags": [ + "address", + "area", + "current location", + "destination", + "direction", + "drop", + "find", + "fmd", + "geography", + "geotag", + "good", + "gps", + "landmark", + "locate", + "location", + "map", + "maps", + "marker", + "navigation", + "nearby", + "pin", + "place", + "point of interest", + "pointer", + "position", + "proximity", + "region", + "route", + "site", + "spot", + "stop", + "teardrop", + "travel", + "venue" + ], + "popularity": 16313 + }, + "FOLDER": { + "tags": [ + "administration", + "archive", + "browse", + "business", + "category", + "collection", + "computer", + "container", + "data", + "directory", + "doc", + "document", + "drive", + "explore", + "file", + "file system", + "folder", + "folders", + "group", + "hierarchy", + "manage", + "office", + "open", + "organize", + "portfolio", + "project", + "record", + "save", + "sheet", + "slide", + "storage", + "structure", + "system", + "tab", + "work" + ], + "popularity": 75074 + }, + "FOLDER_COPY": { + "tags": [ + "archive", + "backup", + "clone", + "collection", + "content", + "copy", + "create copy", + "cut", + "data", + "directory", + "doc", + "document", + "documents", + "drive", + "duplicate", + "file", + "files", + "folder", + "folders", + "generate copy", + "information", + "make a copy", + "management", + "multiple", + "papers", + "paste", + "replicate", + "repository", + "save", + "save as", + "save copy", + "sheet", + "slide", + "storage" + ], + "popularity": 5239 + }, + "FOLDER_DELETE": { + "tags": [ + "administration", + "archive", + "bin", + "business", + "can", + "clear", + "computer", + "data", + "data management", + "delete", + "doc", + "document", + "documents", + "drive", + "file", + "file management", + "folder", + "folder management", + "folders", + "garbage", + "management", + "office", + "organization", + "organized", + "recycle bin", + "remove", + "repository.", + "sheet", + "slide", + "storage", + "system", + "trash", + "waste" + ], + "popularity": 2817 + }, + "FOLDER_OFF": { + "tags": [ + "access denied", + "block", + "blocked", + "close folder", + "data", + "data folder off", + "delete folder", + "denied", + "directory off", + "disabled", + "doc", + "document", + "document folder off", + "drive", + "enabled", + "file", + "file folder off", + "folder", + "folder access denied", + "folder blocked", + "folder disable", + "folder disabled", + "folder off", + "folder restricted", + "folder unavailable", + "folders", + "no access", + "no folder", + "not allowed", + "off", + "on", + "online", + "private folder off", + "remove folder", + "restricted", + "restricted access", + "secret folder off", + "sheet", + "slash", + "slide", + "storage", + "storage folder off", + "unavailable" + ], + "popularity": 1795 + }, + "FOLDER_OPEN": { + "tags": [ + "access", + "archive", + "browse", + "collection", + "computer", + "container", + "content", + "data", + "directory", + "doc", + "document", + "drive", + "expand", + "explore", + "file", + "file management", + "folder", + "folders", + "hierarchy", + "information", + "locate", + "navigation", + "open", + "organization", + "organize", + "project", + "retrieve", + "reveal", + "save", + "sheet", + "slide", + "storage", + "system", + "tab", + "view" + ], + "popularity": 33876 + }, + "FOLDER_SHARED": { + "tags": [ + "access", + "account", + "backup", + "cloud", + "collaboration", + "computer", + "content", + "data", + "digital", + "directory", + "distribute", + "doc", + "document", + "drive", + "face", + "file", + "folder", + "group", + "human", + "management", + "network", + "organize", + "people", + "person", + "profile", + "save", + "send", + "share", + "shared", + "sheet", + "slide", + "storage", + "store", + "sync", + "synchronise", + "team", + "teamwork", + "user" + ], + "popularity": 13136 + }, + "FOLDER_SPECIAL": { + "tags": [ + "archive", + "bookmark", + "data", + "directory", + "doc", + "document", + "documents", + "drive", + "favorite", + "favorite folder", + "file", + "files", + "folder", + "highlight", + "important", + "important folder", + "marked", + "marked folder", + "organize", + "save", + "saved", + "saved folder", + "shape", + "sheet", + "slide", + "special", + "special folder", + "star", + "starred", + "starred folder", + "storage" + ], + "popularity": 6644 + }, + "FOLDER_ZIP": { + "tags": [ + "archive", + "archive file", + "compress", + "compressed file", + "computer", + "data", + "data organization", + "digital", + "directory", + "doc", + "document", + "document icon", + "document management", + "drive", + "electronic", + "file", + "file folder", + "file icon", + "file management", + "file zip", + "folder", + "folder archive", + "folder compress", + "folder icon", + "folder zip", + "folders", + "open", + "organize", + "paper", + "sheet", + "slide", + "storage", + "storage icon", + "storage management", + "zip", + "zip icon" + ], + "popularity": 5201 + }, + "FOLLOW_THE_SIGNS": { + "tags": [ + "arrow", + "body", + "crossroads", + "destination", + "direction", + "directional", + "follow", + "forward", + "guidance", + "guide", + "highway", + "human", + "indication", + "junction", + "left", + "line", + "location", + "navigate", + "next", + "path", + "people", + "person", + "point", + "pointer", + "right", + "road", + "road sign", + "route", + "signal", + "signpost", + "signs", + "social", + "street", + "street sign", + "the", + "travel", + "turn", + "turn indicator", + "up" + ], + "popularity": 5723 + }, + "FONT_DOWNLOAD": { + "tags": [ + "a", + "acquire", + "action", + "alphabet", + "arrow", + "button", + "character", + "classification", + "document", + "down arrow", + "download", + "file", + "font", + "get", + "icon", + "install", + "letter", + "letters", + "obtain", + "pointer", + "retrieve", + "square", + "symbol", + "text", + "type", + "typeface", + "typography", + "ui", + "writing" + ], + "popularity": 6771 + }, + "FONT_DOWNLOAD_OFF": { + "tags": [ + "access denied", + "alphabet", + "blocked", + "cancel download", + "character", + "denied", + "disabled", + "disabled font download", + "download", + "download font", + "download text", + "download typography", + "enabled", + "font", + "font download blocked", + "font download off", + "font download unavailable", + "forbidden", + "glyph", + "glyph download off", + "letter", + "letter download off", + "letters", + "no access.", + "no download", + "not allowed", + "off", + "on", + "restricted", + "slash", + "square", + "stop download", + "symbol", + "text", + "text download off", + "type", + "typography", + "typography download disabled", + "unavailable" + ], + "popularity": 1686 + }, + "FOOD_BANK": { + "tags": [ + "access", + "aid", + "architecture", + "assistance", + "bank", + "building", + "center", + "charity", + "community", + "distribution", + "donation", + "eat", + "estate", + "food", + "food bank", + "fork", + "giving", + "help", + "house", + "hunger", + "institution", + "knife", + "meal", + "non-profit", + "organization", + "place", + "provisions", + "real", + "residence", + "residential", + "resource", + "service", + "shelter", + "social", + "storage", + "structure", + "supplies", + "support", + "utensils", + "warehouse", + "welfare" + ], + "popularity": 5663 + }, + "FOREST": { + "tags": [ + "abstract", + "adventure", + "destination", + "discovery", + "earth", + "eco", + "environment", + "exploration", + "flora", + "forest", + "green", + "growth", + "jungle", + "landscape", + "life", + "location", + "map", + "marker", + "natural", + "nature", + "navigation", + "outdoor", + "park", + "pin", + "plant", + "plantation", + "plants", + "preserve", + "travel", + "trees", + "wilderness", + "woodland", + "woods" + ], + "popularity": 7480 + }, + "FORK_LEFT": { + "tags": [ + "alternative", + "arrow", + "arrows", + "branch left", + "branching path", + "choice", + "decision", + "deviation", + "direction", + "directional", + "directions", + "diverge", + "divide", + "fork", + "fork left", + "junction", + "left", + "left turn", + "map", + "maps", + "navigation", + "options", + "path", + "pathway", + "road", + "road sign", + "route", + "sidetrack", + "sign", + "split left", + "traffic", + "travel", + "turn", + "veer" + ], + "popularity": 1124 + }, + "FORK_RIGHT": { + "tags": [ + "arrow", + "arrow right", + "arrows", + "branch right", + "curve right", + "direction", + "direction right", + "directions", + "diverge right", + "divide right", + "drive right", + "fork", + "fork right", + "journey right", + "junction right", + "maps", + "merge right", + "movement right", + "navigate right", + "navigation", + "path", + "path right", + "right", + "right bend", + "right side", + "right turn", + "rightward", + "route", + "route right", + "side right", + "sign", + "split right", + "traffic", + "travel", + "travel right", + "turn right" + ], + "popularity": 1887 + }, + "FORMAT_ALIGN_CENTER": { + "tags": [ + "align", + "align horizontal", + "align middle", + "alignment", + "center", + "centered", + "centered alignment", + "centered text", + "doc", + "document", + "document editing", + "edit", + "editing", + "editor", + "equal lines", + "format", + "formatting", + "horizontal", + "justify", + "middle", + "paragraph", + "paragraph alignment", + "sheet", + "spreadsheet", + "symmetric lines", + "text", + "text format", + "type", + "word processing", + "writing" + ], + "popularity": 6952 + }, + "FORMAT_ALIGN_JUSTIFY": { + "tags": [ + "adjust", + "align", + "alignment", + "arrange", + "blocks of text", + "content", + "density", + "doc", + "document", + "document format", + "edit", + "editing", + "editor", + "extra", + "format", + "formatting options", + "four lines", + "full align", + "justify", + "layout", + "left align", + "line breaks", + "lines", + "paragraph", + "paragraphs", + "right align", + "sheet", + "small", + "spreadsheet", + "text", + "text alignment", + "text editor", + "text style", + "three lines", + "type", + "typing", + "word", + "writing", + "writing tool" + ], + "popularity": 5398 + }, + "FORMAT_ALIGN_LEFT": { + "tags": [ + "align", + "align document", + "align left", + "alignment", + "doc", + "document alignment", + "document editor", + "edit", + "editing", + "editor", + "format", + "format text", + "formatting", + "justify left", + "left", + "left align", + "left justified", + "lines", + "lines of text", + "organize text", + "paragraph alignment", + "sheet", + "spreadsheet", + "text", + "text alignment", + "text block", + "text editor", + "text formatting", + "three lines", + "type", + "uneven lines", + "word processing", + "writing", + "writing editor" + ], + "popularity": 10639 + }, + "FORMAT_ALIGN_RIGHT": { + "tags": [ + "adjust text", + "align", + "align right", + "alignment", + "doc", + "document editor", + "edit", + "editing", + "editor", + "format", + "justified right", + "justify right", + "lines", + "multi-line", + "paragraph", + "paragraph align", + "right", + "right align", + "right aligned", + "right justified", + "sheet", + "spreadsheet", + "text", + "text alignment", + "text editor", + "text format", + "text justify", + "text layout", + "type", + "typography", + "word processor", + "writing" + ], + "popularity": 6043 + }, + "FORMAT_BOLD": { + "tags": [ + "alphabet", + "b", + "bold", + "character", + "content", + "doc", + "document", + "edit", + "editing", + "editor", + "font", + "format", + "heavy", + "input", + "interface", + "letter", + "letters", + "paragraph", + "rich text", + "sheet", + "spreadsheet", + "style", + "styles", + "symbol", + "symbols", + "text", + "thick", + "type", + "typography", + "weight", + "word", + "writing" + ], + "popularity": 14969 + }, + "FORMAT_CLEAR": { + "tags": [ + "alphabet", + "brush", + "character", + "clean", + "clear", + "delete", + "disabled", + "doc", + "document", + "document cleaning", + "document editor", + "document tools", + "edit", + "editing", + "editor", + "editor tools", + "enabled", + "erase", + "font", + "format", + "formatting", + "letters", + "line", + "off", + "on", + "paint brush", + "paragraph", + "remove", + "reset", + "sheet", + "slash", + "spreadsheet", + "style", + "style cleaner", + "style removal", + "symbol", + "t", + "text", + "text cleaning", + "text formatting", + "text tools", + "type", + "typography", + "writing" + ], + "popularity": 2549 + }, + "FORMAT_COLOR_FILL": { + "tags": [ + "alter", + "apply", + "area", + "art", + "background", + "background color", + "bucket", + "change", + "color", + "design", + "doc", + "drawing", + "drop", + "edit", + "editing", + "editor", + "fill", + "fill color", + "font", + "format", + "graphics", + "liquid", + "modify", + "paint", + "paint bucket", + "palette", + "pouring", + "select", + "shape", + "sheet", + "spill", + "spreadsheet", + "style", + "text", + "tool", + "type", + "writing" + ], + "popularity": 10351 + }, + "FORMAT_COLOR_RESET": { + "tags": [ + "and", + "angled line", + "art", + "choose color", + "circle", + "clear", + "clear color", + "color", + "color picker", + "color swatch", + "default color", + "disabled", + "doc", + "document", + "drawing", + "drop", + "droplet", + "dropper", + "edit", + "editing", + "editor", + "enabled", + "eyedropper", + "fill", + "format", + "graphic design", + "initial color", + "liquid", + "off", + "on", + "original color", + "paint", + "photo editing", + "pipette", + "remove color", + "reset", + "reset color", + "sample", + "select color", + "sheet", + "slash", + "spreadsheet", + "style", + "text", + "type", + "water", + "writing" + ], + "popularity": 3569 + }, + "FORMAT_COLOR_TEXT": { + "tags": [ + "ab", + "abc", + "brush", + "change color", + "color", + "doc", + "document", + "document editor", + "edit", + "editing", + "editor", + "fill", + "font", + "font style", + "format", + "formatting", + "letter", + "letter t", + "paint", + "palette", + "rich text", + "select color", + "sheet", + "spreadsheet", + "style", + "t symbol", + "text", + "text color", + "text style", + "type", + "typography", + "word processing", + "writing" + ], + "popularity": 6109 + }, + "FORMAT_INDENT_DECREASE": { + "tags": [ + "align", + "alignment", + "alignment control", + "decrease", + "decrease indent", + "decrease indentation", + "doc", + "document control", + "document editor", + "document formatting", + "edit", + "editing", + "editing tools", + "editor", + "format", + "format text", + "formatting options", + "indent", + "indent decrease", + "indentation", + "layout control", + "left alignment", + "lines", + "paragraph", + "paragraph style", + "sheet", + "spreadsheet", + "style", + "text", + "text alignment", + "text block", + "text control", + "text editor", + "text format", + "text formatting", + "text layout", + "text lines", + "type", + "typography", + "word processor", + "writing", + "writing assistant", + "writing tools" + ], + "popularity": 2696 + }, + "FORMAT_INDENT_INCREASE": { + "tags": [ + "align", + "alignment", + "block quote", + "content creation", + "doc", + "document formatting", + "document layout", + "edit", + "editing", + "editor", + "format", + "formatting control", + "increase", + "increase indent", + "indent", + "indent right", + "indentation", + "layout", + "lines of text", + "move right", + "nested text", + "paragraph", + "paragraph formatting", + "paragraph layout", + "paragraph styling", + "sheet", + "spacing", + "spreadsheet", + "text", + "text adjustment", + "text alignment", + "text block", + "text control", + "text display", + "text editing", + "text formatting", + "text indent", + "text styling", + "type", + "visual hierarchy", + "word processing", + "writing" + ], + "popularity": 3842 + }, + "FORMAT_ITALIC": { + "tags": [ + "a", + "abc", + "adjust", + "alphabet", + "angle", + "angled", + "b", + "bold", + "c", + "character", + "doc", + "document", + "edit", + "editing", + "editor", + "emphasize", + "font", + "format", + "formatting", + "italic", + "leaning", + "letter", + "letters", + "sheet", + "slant", + "slant right", + "spreadsheet", + "strikethrough", + "style", + "symbol", + "text", + "type", + "typeface", + "typography", + "underline", + "words", + "writing" + ], + "popularity": 10348 + }, + "FORMAT_LINE_SPACING": { + "tags": [ + "adjust spacing", + "align", + "alignment", + "arrows", + "decrease spacing", + "doc", + "document", + "document editing", + "down arrow", + "edit", + "editing", + "editor", + "format", + "formatting", + "increase spacing", + "layout", + "line", + "line spacing", + "lines", + "paragraph spacing", + "sheet", + "spacing", + "spreadsheet", + "text", + "text block", + "text spacing", + "type", + "typography", + "typography control", + "up arrow", + "vertical spacing", + "word processing", + "writing" + ], + "popularity": 2525 + }, + "FORMAT_LIST_BULLETED": { + "tags": [ + "align", + "alignment", + "arrangement", + "bullet list", + "bulleted", + "bullets", + "content", + "display", + "doc", + "document", + "edit", + "editing", + "editor", + "enumeration", + "format", + "formatting", + "itemize", + "items", + "layout", + "list", + "notes", + "order", + "organize", + "outline", + "points", + "rich text", + "selection", + "sequence", + "sheet", + "spreadsheet", + "structure", + "text", + "type", + "unordered", + "word processing", + "writing" + ], + "popularity": 56504 + }, + "FORMAT_LIST_NUMBERED": { + "tags": [ + "align", + "alignment", + "arrangement", + "bullet points", + "digit", + "doc", + "document", + "edit", + "editing", + "editor", + "enumeration", + "format", + "format options", + "formatting", + "indent", + "items", + "layout", + "lines", + "list", + "notes", + "numbered", + "numbered list", + "numbering", + "numbering style", + "numbers", + "order", + "ordered items", + "ordered list", + "organizing", + "outline", + "paragraph", + "points", + "sequence", + "sequence order", + "sheet", + "spreadsheet", + "structure", + "symbol", + "text", + "type", + "writing" + ], + "popularity": 23383 + }, + "FORMAT_LIST_NUMBERED_RTL": { + "tags": [ + "align", + "alignment", + "arabic", + "bulleted list", + "content", + "digit", + "digits", + "doc", + "document", + "edit", + "editing", + "editor", + "form", + "format", + "formatting", + "hebrew", + "language", + "lines", + "list", + "list number", + "notes", + "number", + "numbered", + "numbered list", + "numbering", + "numbers", + "order", + "organization", + "right to left", + "rtl", + "sequence", + "sheet", + "spreadsheet", + "structure", + "symbol", + "text", + "text editing", + "three lines", + "type", + "writing" + ], + "popularity": 5762 + }, + "FORMAT_OVERLINE": { + "tags": [ + "alphabet", + "button", + "character", + "character formatting", + "control", + "doc", + "document", + "edit", + "editing", + "editor", + "font", + "format", + "formatting", + "graphic design", + "horizontal lines", + "letters", + "line", + "lines", + "menu", + "option", + "overline", + "sheet", + "spreadsheet", + "strikethrough", + "style", + "symbol", + "text", + "three lines", + "type", + "typography", + "ui", + "under", + "underline", + "ux", + "word processing", + "writing" + ], + "popularity": 739 + }, + "FORMAT_PAINT": { + "tags": [ + "adjust", + "adjustment", + "art", + "artist", + "brush", + "bucket", + "color", + "coloring", + "creative", + "creativity", + "decorate", + "decoration", + "design", + "doc", + "drawing", + "edit", + "editing", + "editor", + "fill", + "fill color", + "format", + "formatting", + "hue", + "paint", + "paint bucket", + "painting", + "palette", + "roller", + "shade", + "sheet", + "spreadsheet", + "style", + "text", + "tint", + "tools", + "type", + "writing" + ], + "popularity": 6590 + }, + "FORMAT_QUOTE": { + "tags": [ + "block quote", + "citation", + "citation format", + "closing quote", + "comment", + "content", + "dialogue", + "doc", + "document", + "double quotes", + "edit", + "editing", + "editor", + "editorial", + "format", + "format quote", + "opening quote", + "paragraph", + "punctuation", + "quotation", + "quotation mark", + "quote", + "quote marks", + "quote symbol", + "reference", + "sheet", + "speech", + "spreadsheet", + "text", + "text formatting", + "type", + "typography", + "writing" + ], + "popularity": 25533 + }, + "FORMAT_SHAPES": { + "tags": [ + "align", + "alphabet", + "arrange", + "character", + "circle", + "color", + "customize", + "design", + "doc", + "edit", + "editing", + "editor", + "element", + "fill", + "font", + "form", + "format", + "format shapes", + "geometric", + "geometry", + "graphic", + "insert", + "layout", + "letters", + "modify", + "organize", + "paint", + "pattern", + "polygon", + "settings", + "shape", + "shapes", + "sheet", + "spreadsheet", + "square", + "structure", + "style", + "symbol", + "text", + "tools", + "triangle", + "type", + "ui", + "ux", + "vector", + "visual", + "writing" + ], + "popularity": 4493 + }, + "FORMAT_SIZE": { + "tags": [ + "a a", + "alphabet", + "alphabet size", + "big a little a", + "character", + "character size", + "color", + "content", + "doc", + "document", + "document format", + "document scale", + "edit", + "editing", + "editor", + "enlarge", + "fill", + "font", + "font size", + "format", + "formatting options", + "letter size", + "letters", + "paint", + "paragraph", + "resize", + "scale", + "sheet", + "shrink", + "size", + "size control", + "spreadsheet", + "style", + "symbol", + "text", + "text formatting", + "text scale", + "text size", + "text styling", + "type", + "typography", + "uppercase lowercase", + "word processing", + "writing", + "zoom" + ], + "popularity": 8419 + }, + "FORMAT_STRIKETHROUGH": { + "tags": [ + "alphabet", + "cancel", + "character", + "cross out", + "crossed", + "crossed out", + "delete", + "doc", + "document", + "edit", + "edit text", + "editing", + "editor", + "font", + "format", + "format text", + "formatting option", + "horizontal line", + "letters", + "line", + "line through text", + "marking", + "remove", + "sheet", + "spreadsheet", + "strikethrough", + "strikethru", + "style", + "symbol", + "text", + "text decoration", + "through", + "type", + "typography", + "visual formatting", + "word processing", + "writing" + ], + "popularity": 2114 + }, + "FORMAT_TEXTDIRECTION_L_TO_R": { + "tags": [ + "align", + "alignment", + "bidirectional text", + "direction", + "doc", + "document", + "document editing", + "edit", + "editing", + "editor", + "format", + "formatting tools", + "language", + "layout", + "left to right", + "ltr", + "paragraph", + "paragraph direction", + "right to left", + "rtl", + "sheet", + "spreadsheet", + "text", + "text alignment", + "text control", + "text editor", + "text formatting", + "text layout", + "text options", + "textdirection", + "type", + "typography", + "word processing", + "writing", + "writing direction" + ], + "popularity": 934 + }, + "FORMAT_TEXTDIRECTION_R_TO_L": { + "tags": [ + "align", + "alignment", + "alignment direction", + "bidirectional", + "bidirectional text", + "content", + "direction", + "doc", + "document", + "edit", + "editing", + "editor", + "flow", + "format", + "formatting", + "horizontal", + "internationalization", + "justify", + "language", + "layout", + "left to right", + "localization", + "ltr", + "paragraph", + "reading", + "right to left", + "rtl", + "script", + "sheet", + "spreadsheet", + "text", + "text alignment", + "textdirection", + "type", + "typography", + "word processing", + "writing", + "writing mode" + ], + "popularity": 857 + }, + "FORMAT_UNDERLINED": { + "tags": [ + "alphabet", + "character", + "decoration", + "doc", + "document", + "edit", + "editing", + "editor", + "emphasis", + "font", + "format", + "horizontal line", + "letter u", + "letters", + "line", + "sheet", + "spreadsheet", + "style", + "styling", + "symbol", + "text", + "text editing", + "text formatting", + "type", + "u", + "under", + "underline", + "underlined", + "underscore", + "word processor", + "writing", + "writing tool" + ], + "popularity": 8135 + }, + "FORT": { + "tags": [ + "ancient", + "architecture", + "battlements", + "building", + "castle", + "defense", + "dwelling", + "fort", + "fortress", + "graphic", + "historical", + "house", + "icon", + "kingdom", + "landmark", + "mansion", + "medieval", + "military", + "monument", + "outline", + "palace", + "property", + "protection", + "real estate", + "royalty", + "security", + "shape", + "stronghold", + "structure", + "symbol", + "tower", + "walls" + ], + "popularity": 1334 + }, + "FORUM": { + "tags": [ + "answers", + "bubble", + "chat", + "comment", + "comments", + "communicate", + "communication", + "communication bubble", + "community", + "conversation", + "debate", + "dialogue", + "discussion", + "empty", + "feedback", + "forum", + "help", + "hub", + "message", + "online chat", + "outline", + "qa", + "question_answer", + "questions", + "rectangle", + "speaking", + "speech", + "speech balloon", + "speech bubble", + "support", + "tail", + "talk", + "talk bubble", + "talking", + "thinking", + "thought" + ], + "popularity": 34362 + }, + "FORWARD": { + "tags": [ + "arrow", + "communication", + "content sharing", + "forward", + "forward icon", + "google plus", + "google plus share", + "mail", + "message", + "playback", + "reshare", + "reshare icon", + "right", + "right arrow", + "send", + "send icon", + "send to", + "sent", + "share", + "share arrow", + "share content", + "share icon", + "share link", + "share post", + "share to", + "share with", + "shortcut", + "social icon", + "social media", + "social share" + ], + "popularity": 18192 + }, + "FORWARD_10": { + "tags": [ + "10", + "10 seconds", + "advance", + "arrow", + "audio", + "audio playback", + "content navigation", + "control", + "controls", + "digit", + "duration", + "fast", + "fast forward", + "forward", + "increment time", + "jump", + "media", + "media control", + "move ahead", + "music", + "numbers", + "play", + "playback", + "player", + "player control", + "quick skip", + "scrub forward", + "seconds", + "seek", + "skip", + "skip ahead", + "specific time", + "symbol", + "ten seconds", + "time", + "time jump", + "timeline", + "timestamp", + "video", + "video playback" + ], + "popularity": 6843 + }, + "FORWARD_30": { + "tags": [ + "30", + "30 seconds", + "advance", + "arc", + "arrow", + "audio", + "control", + "controls", + "curve", + "digit", + "fast", + "fast forward", + "forward", + "icon", + "interface element", + "jump", + "media", + "media control", + "multimedia", + "music", + "number", + "numbers", + "numeric", + "playback", + "player", + "progress", + "rewind forward", + "seconds", + "skip", + "symbol", + "thirty seconds", + "time", + "transport control", + "video" + ], + "popularity": 2698 + }, + "FORWARD_5": { + "tags": [ + "10", + "5", + "5 seconds", + "advance", + "arrow", + "audio", + "back", + "control", + "controls", + "digit", + "direction", + "duration", + "fast", + "fast forward", + "five seconds", + "forward", + "interval", + "jump", + "media control", + "music", + "navigation", + "next", + "numbers", + "playback", + "player", + "previous", + "progress", + "rewind", + "right arrow", + "seconds", + "skip", + "streaming", + "symbol", + "time", + "time skip", + "timeframe", + "timeline", + "triangle", + "video" + ], + "popularity": 2303 + }, + "FORWARD_TO_INBOX": { + "tags": [ + "arrow", + "arrow icon", + "arrows", + "communication", + "communication icon", + "correspondence", + "delivery", + "destination", + "direction", + "directions", + "document", + "email", + "envelop", + "envelope", + "envelope icon", + "forward", + "inbox", + "inbox icon", + "letter", + "letter icon", + "letters", + "mail", + "mail icon", + "message", + "message forwarding", + "message transfer", + "move", + "navigation", + "outgoing", + "paper", + "right", + "send", + "send mail", + "send message", + "to", + "transfer", + "transport" + ], + "popularity": 18604 + }, + "FOUNDATION": { + "tags": [ + "architectural element", + "architecture", + "base", + "base icon", + "basis", + "beginning", + "building", + "building block", + "column", + "construction", + "construction icon", + "core", + "development", + "essential", + "establishing", + "estate", + "foundation", + "fundamental", + "ground", + "home", + "house", + "pillar", + "progress", + "property", + "real", + "real estate", + "residential", + "root", + "solid", + "stable", + "start", + "structure", + "support" + ], + "popularity": 5972 + }, + "FREE_BREAKFAST": { + "tags": [ + "beverage", + "break", + "breakfast", + "cafe", + "caffeine", + "ceramic", + "coffee", + "cup", + "diner", + "dining", + "drink", + "eatery", + "food", + "free", + "handle", + "hot drink", + "kitchen", + "local", + "morning", + "mug", + "order", + "refreshment", + "relax", + "restaurant", + "service", + "shop", + "steam", + "store", + "tea", + "warm" + ], + "popularity": 6971 + }, + "FREE_CANCELLATION": { + "tags": [ + "abort", + "approve", + "back out", + "block", + "calendar", + "cancel", + "cancellation", + "check", + "clear", + "close", + "complete", + "cross", + "date", + "day", + "delete", + "denied", + "discard", + "done", + "error", + "event", + "exit", + "forbidden", + "free", + "invalid", + "mark", + "month", + "negative", + "no", + "ok", + "override", + "prohibition", + "refusal", + "reject", + "remove", + "restriction", + "revoke", + "schedule", + "select", + "stop", + "tick", + "unavailable", + "undo", + "validate", + "verified", + "void", + "wrong", + "x", + "x mark", + "yes" + ], + "popularity": 6304 + }, + "FRONT_HAND": { + "tags": [ + "accessibility", + "alert", + "anatomy", + "body part", + "communication", + "control", + "cursor", + "fingers", + "five", + "front", + "gesture", + "greeting", + "hand", + "hello", + "high five", + "human", + "interaction", + "limb", + "open hand", + "outstretched hand", + "palm", + "point", + "pointer", + "recognition", + "selection", + "stop", + "symbol", + "touch", + "warning", + "wave" + ], + "popularity": 10869 + }, + "FULLSCREEN": { + "tags": [ + "adjust", + "app", + "application", + "aspect ratio", + "big", + "cinema mode", + "components", + "display", + "enlarge", + "expand", + "extend", + "frame", + "full", + "full screen", + "fullscreen", + "immersive", + "interface", + "magnify", + "maximize", + "media", + "mode", + "monitor", + "picture", + "player", + "presentation", + "scale", + "screen", + "site", + "size", + "stretch", + "toggle", + "ui", + "ux", + "video", + "view", + "web", + "website", + "wide", + "window", + "zoom" + ], + "popularity": 36896 + }, + "FULLSCREEN_EXIT": { + "tags": [ + "adjust", + "app", + "application", + "arrows", + "cinema", + "close", + "collapse", + "components", + "contract", + "default view", + "display", + "escape", + "exit", + "exit full screen", + "exit fullscreen", + "full", + "full screen exit", + "fullscreen", + "fullscreen exit", + "go back", + "interface", + "media", + "minimize", + "mode", + "monitor", + "normal view", + "player", + "presentation", + "reduce", + "restore", + "return", + "revert", + "screen", + "shrink", + "site", + "size", + "theatre", + "ui", + "ux", + "video", + "view", + "web", + "website", + "window" + ], + "popularity": 16430 + }, + "FUNCTIONS": { + "tags": [ + "adjustments", + "administration", + "algorithms", + "automation", + "average", + "calculate", + "capabilities", + "cogwheels", + "configuration", + "controls", + "count", + "custom", + "customization", + "data", + "doc", + "edit", + "editing", + "editor", + "engineering", + "features", + "functions", + "gears", + "management", + "math", + "mechanisms", + "operations", + "options", + "parameters", + "preferences", + "processing", + "settings", + "setup", + "sheet", + "spreadsheet", + "style", + "sum", + "system", + "text", + "tools", + "type", + "writing" + ], + "popularity": 12007 + }, + "G_MOBILEDATA": { + "tags": [ + "alphabet", + "bars", + "cell service", + "cellular", + "character", + "communication", + "connection", + "connectivity", + "data", + "digital", + "dots", + "download", + "font", + "g", + "g_mobiledata", + "internet", + "letters", + "lines", + "mobile", + "mobile data", + "mobile internet", + "mobile network", + "network", + "network strength", + "reception", + "service", + "signal", + "speed", + "symbol", + "technology", + "telecommunications", + "text", + "tower", + "transfer", + "triangle", + "type", + "upload", + "wireless", + "wireless data" + ], + "popularity": 989 + }, + "G_TRANSLATE": { + "tags": [ + "a icon", + "alphabet", + "babel", + "communication", + "convert language", + "dictionary", + "different languages", + "emblem", + "foreign language", + "g", + "g icon", + "global", + "glossary", + "google", + "international", + "language", + "language barrier", + "language change", + "letter", + "linguistic", + "logo", + "mark", + "meaning", + "multiple languages", + "speaking", + "speech", + "switch language", + "talking", + "text", + "translate", + "translation", + "translator", + "two languages", + "understanding", + "words", + "world" + ], + "popularity": 14619 + }, + "GAMEPAD": { + "tags": [ + "accessory", + "action", + "activity", + "buttons", + "circles", + "console", + "control", + "controller", + "d-pad", + "device", + "digital", + "direction", + "electronic", + "entertainment", + "fun", + "game", + "gamepad", + "gaming", + "hardware", + "input", + "interface", + "joystick", + "leisure", + "menu", + "navigation", + "play", + "playstation", + "rectangle", + "selection", + "technology", + "video", + "video games" + ], + "popularity": 4587 + }, + "GAMES": { + "tags": [ + "accessory", + "action", + "activity", + "adjust", + "arrow", + "arrows", + "buttons", + "circles", + "control", + "controller", + "d-pad", + "device", + "digital", + "direction", + "electronic", + "entertainment", + "fun", + "gamepad", + "games", + "gaming", + "hardware", + "input", + "interface", + "joystick", + "left", + "leisure", + "menu", + "move", + "navigation", + "play", + "rectangle", + "right", + "selection", + "technology", + "video games" + ], + "popularity": 7440 + }, + "GARAGE": { + "tags": [ + "auto", + "automobile", + "automotive", + "building", + "car", + "cars", + "closed", + "direction", + "door", + "entrance", + "garage", + "home", + "house", + "maintenance", + "maps", + "mechanic", + "open", + "outline", + "park", + "parking", + "property", + "real estate", + "repair", + "residential", + "shop", + "silhouette", + "simple", + "storage", + "structure", + "tool", + "transportation", + "travel", + "vehicle", + "workshop" + ], + "popularity": 6280 + }, + "GAS_METER": { + "tags": [ + "analog indicator", + "analog meter", + "circular gauge", + "circular meter", + "consumption", + "dashboard", + "dashboard element", + "dial", + "droplet", + "energy", + "energy meter", + "fuel", + "fuel gauge", + "fuel level", + "gas", + "gas meter", + "gauge", + "indicator", + "level", + "level indicator", + "measure", + "measurement", + "measurement device", + "meter", + "nest", + "pointer", + "power", + "power meter", + "reading", + "scale", + "usage", + "usage indicator", + "utility", + "water" + ], + "popularity": 1912 + }, + "GAVEL": { + "tags": [ + "agreement", + "attorney", + "auction", + "authority", + "command", + "contract", + "court", + "courtroom", + "decision", + "document", + "formal", + "gavel", + "government", + "hammer", + "judge", + "judgment", + "judgment call", + "judiciary", + "justice", + "law", + "lawyer", + "legal", + "legal proceedings", + "legislation", + "mallet", + "official", + "order", + "police", + "rule", + "rules", + "terms", + "trial", + "verdict", + "wood", + "wood object" + ], + "popularity": 31413 + }, + "GENERATING_TOKENS": { + "tags": [ + "access", + "ai", + "algorithm", + "api", + "artificial", + "artificial intelligence", + "automatic", + "automation", + "brain", + "build", + "building", + "code", + "coding", + "cog", + "cogs", + "coin", + "computation", + "computing", + "create", + "creating", + "custom", + "data", + "genai", + "generate", + "generating", + "idea", + "ideas", + "intelligence", + "machine learning", + "magic", + "mind", + "ml", + "process", + "processing", + "program", + "programming", + "smart", + "spark", + "sparkle", + "star", + "thinking", + "thinking cap", + "thought", + "tokens" + ], + "popularity": 6440 + }, + "GESTURE": { + "tags": [ + "activate", + "arrow", + "click", + "control", + "cursor", + "diagonal", + "direction", + "doodle", + "down", + "drag", + "draw", + "drawing", + "engage", + "finger", + "flow", + "gesture", + "gestures", + "hand", + "interaction", + "left", + "line", + "manipulate", + "motion", + "movement", + "navigate", + "path", + "pointer", + "right", + "scribble", + "select", + "string", + "swipe", + "tap", + "thread", + "touch", + "trail", + "up" + ], + "popularity": 6162 + }, + "GET_APP": { + "tags": [ + "acquire", + "action", + "app", + "application", + "archive", + "arrow", + "arrows", + "bar", + "button", + "cloud", + "computer", + "control", + "data", + "document", + "down", + "download", + "downloads", + "export", + "file", + "get", + "incoming", + "install", + "internet", + "line", + "move", + "network", + "obtain", + "play", + "pointed", + "receive", + "save", + "storage", + "symbol", + "transfer", + "underscore", + "upload" + ], + "popularity": 28018 + }, + "GIF": { + "tags": [ + "abbreviation", + "alphabet", + "animated", + "animation", + "bitmap", + "box", + "character", + "clip", + "extension", + "file type", + "font", + "format", + "gif", + "graphic", + "graphics", + "image", + "interchange", + "label", + "letters", + "loop", + "motion", + "moving", + "multimedia", + "picture", + "rectangle", + "symbol", + "text", + "three letters", + "type", + "video" + ], + "popularity": 5348 + }, + "GIF_BOX": { + "tags": [ + "add", + "alphabet", + "animated", + "animation", + "bitmap", + "box", + "character", + "chat", + "communication", + "digital file", + "expression", + "f", + "file type", + "font", + "format", + "funny", + "g", + "gif", + "graphics", + "i", + "image", + "insert", + "interchange", + "letter", + "letters", + "media", + "message", + "moving image", + "multimedia", + "picture", + "reaction", + "social media", + "square", + "symbol", + "text", + "type", + "upload", + "video" + ], + "popularity": 4155 + }, + "GIRL": { + "tags": [ + "account", + "avatar", + "body", + "character", + "female", + "feminine", + "figure", + "gender", + "girl", + "graphic", + "head", + "human", + "icon", + "identity", + "individual", + "lady", + "member", + "outline", + "people", + "person", + "portrait", + "profile", + "shoulders", + "silhouette", + "social", + "symbol", + "user", + "woman", + "women", + "young" + ], + "popularity": 2892 + }, + "GITE": { + "tags": [ + "architecture", + "automation", + "branch", + "changes", + "code", + "collaboration", + "commit", + "deployment", + "developer", + "development", + "estate", + "fork", + "git", + "gite", + "history", + "home", + "hostel", + "hosting", + "house", + "integration", + "local", + "maps", + "merge", + "open source", + "pipeline", + "place", + "programming", + "project", + "pull request", + "real", + "remote", + "repository", + "repository manager", + "residence", + "residential", + "software", + "source code", + "stay", + "tracking", + "traveling", + "update", + "version control", + "workflow" + ], + "popularity": 5464 + }, + "GOLF_COURSE": { + "tags": [ + "activity", + "area", + "athlete", + "athletic", + "ball", + "club", + "course", + "entertainment", + "fairway", + "field", + "flag", + "game", + "golf", + "golf course", + "golfer", + "golfing", + "green", + "grounds", + "hobby", + "hole", + "landscape", + "leisure", + "location", + "map", + "navigation", + "outdoor", + "park", + "pin", + "places", + "putt", + "recreation", + "sport", + "sports", + "tee" + ], + "popularity": 5039 + }, + "GPP_BAD": { + "tags": [ + "access denied", + "alert", + "bad", + "blocked", + "cancel", + "certified", + "close", + "cross", + "danger", + "denied", + "error", + "exit", + "failed", + "failure", + "forbidden", + "gpp", + "invalid", + "no", + "no entry", + "not allowed", + "privacy", + "private", + "protect", + "protection", + "reject", + "remove", + "restricted", + "safety", + "security", + "shield", + "sim", + "stop", + "unauthorized", + "verified", + "warning", + "x" + ], + "popularity": 7792 + }, + "GPP_GOOD": { + "tags": [ + "badge", + "certified", + "check", + "complete", + "confirmation", + "data", + "endorsed", + "excellent", + "exemption", + "good", + "gpp", + "guard", + "ok", + "pass", + "positive", + "privacy", + "protected", + "protection", + "quality", + "safety", + "security", + "shield", + "sim", + "success", + "tick", + "trust", + "user", + "valid", + "validation", + "verification", + "verified" + ], + "popularity": 18434 + }, + "GPP_MAYBE": { + "tags": [ + "!", + "alert", + "attention", + "authenticate", + "authentication", + "caution", + "certified", + "check", + "danger", + "doubt", + "error", + "exclamation", + "gpp", + "help", + "important", + "inquiry", + "integrity", + "mark", + "maybe", + "not sure", + "notification", + "privacy", + "private", + "protect", + "protection", + "query", + "question mark", + "questionable", + "risk", + "safe", + "security", + "shield", + "sim", + "status", + "symbol", + "threat", + "uncertain", + "uncertain security", + "unknown", + "unsafe", + "unsure", + "validation", + "verified", + "verify", + "warning" + ], + "popularity": 9384 + }, + "GPS_FIXED": { + "tags": [ + "area", + "center location", + "circle", + "compass", + "coordinates", + "current location", + "destination", + "detection", + "direction", + "find location", + "fixed", + "fixed location", + "geographic", + "geolocate", + "gps", + "locate me", + "location", + "map", + "maps", + "marker", + "my location", + "navigation", + "pin", + "pinpoint", + "place", + "point", + "pointer", + "position", + "precise", + "spot", + "stop", + "target location", + "track location", + "tracking", + "user location", + "where am i" + ], + "popularity": 21348 + }, + "GPS_NOT_FIXED": { + "tags": [ + "acquire", + "acquiring", + "coordinates", + "current location", + "destination", + "direction", + "disabled", + "enabled", + "finding", + "gps", + "locate", + "location", + "map", + "maps", + "navigate", + "navigation", + "not fixed", + "off", + "on", + "online", + "pin", + "pinpoint", + "place", + "pointer", + "pointing", + "position", + "radar", + "scan", + "scanning", + "search", + "searching", + "searching signal", + "signal", + "slash", + "target", + "tracking" + ], + "popularity": 4244 + }, + "GPS_OFF": { + "tags": [ + "access denied", + "alert", + "blocked", + "circle", + "cross", + "deny", + "destination", + "diagonal line", + "direction", + "disabled", + "enabled", + "error", + "forbidden", + "geolocation", + "gps", + "gps off", + "location", + "location disabled", + "lost", + "map", + "maps", + "marker", + "navigation", + "no signal", + "not fixed", + "not found", + "off", + "offline", + "on", + "pinpoint", + "place", + "pointer", + "positioning", + "prohibition", + "restricted", + "satellite", + "slash", + "tracking", + "unavailable", + "warning" + ], + "popularity": 2233 + }, + "GRADE": { + "tags": [ + "add to favorite", + "bookmark", + "border", + "empty", + "empty star", + "favorite", + "five pointed star", + "five points", + "grade", + "hollow", + "hollow star", + "important", + "mark", + "news", + "not filled", + "outline", + "point", + "rating", + "rating symbol", + "shape", + "star", + "symbol", + "ui action", + "ui element", + "unselected" + ], + "popularity": 62308 + }, + "GRADIENT": { + "tags": [ + "appearance", + "art", + "background", + "blend", + "color", + "contrast", + "dark", + "design", + "edit", + "editing", + "effect", + "element", + "fade", + "fill", + "filter", + "gradient", + "graphic", + "image", + "images", + "intensity", + "light", + "option", + "photography", + "picture", + "pictures", + "property", + "setting", + "shade", + "style", + "tone", + "tool", + "transition", + "visual" + ], + "popularity": 3296 + }, + "GRADING": { + "tags": [ + "approved", + "assess", + "check", + "checklist", + "complete", + "document", + "done", + "evaluation", + "fail", + "form", + "grade", + "grading", + "list", + "mark", + "marking", + "paper", + "pass", + "quality control", + "rating", + "report", + "review", + "score", + "survey", + "tally", + "task list", + "test", + "tick", + "to do list", + "validation", + "verification" + ], + "popularity": 19050 + }, + "GRAIN": { + "tags": [ + "adjust", + "analog", + "art", + "detail", + "digital art", + "dots", + "edit", + "editing", + "effect", + "film", + "filter", + "grain", + "graphic", + "image", + "images", + "imperfection", + "media", + "multimedia", + "noise", + "overlay", + "photo effect", + "photography", + "picture", + "picture effect", + "pictures", + "pixels", + "quality", + "retro", + "speckles", + "square", + "static", + "texture", + "video effect", + "vintage", + "visual" + ], + "popularity": 5712 + }, + "GRAPHIC_EQ": { + "tags": [ + "audio", + "audio analysis", + "audio control", + "audio customization", + "audio effect", + "audio icon", + "audio mixer", + "audio settings", + "audio spectrum", + "audio tuning", + "audio visualization", + "bar graph", + "detect", + "detection", + "eq", + "equalization", + "equalizer", + "equalizer bars", + "frequency bands", + "graphic", + "graphic equalizer", + "media player", + "music", + "music icon", + "music player", + "music settings", + "noise", + "recording", + "sound", + "sound adjustment", + "sound analysis", + "sound customization", + "sound effect", + "sound icon", + "sound levels", + "sound mixer", + "sound tuning", + "sound waves", + "vertical bars", + "voice", + "volume control" + ], + "popularity": 13170 + }, + "GRASS": { + "tags": [ + "agriculture", + "backyard", + "blade", + "botanical", + "cultivate", + "earth", + "eco", + "environment", + "field", + "flora", + "fodder", + "foliage", + "garden", + "grass", + "green", + "ground", + "growth", + "home", + "landscape", + "lawn", + "leaves", + "meadow", + "natural", + "nature", + "organic", + "outdoor", + "park", + "pasture", + "plant", + "stem", + "turf", + "wild", + "yard" + ], + "popularity": 12014 + }, + "GRID_3X3": { + "tags": [ + "3", + "3x3 grid", + "album view", + "area", + "arrange", + "blocks", + "cells", + "dashboard", + "display", + "gallery view", + "grid", + "layout", + "line", + "matrix", + "menu", + "nine blocks", + "nine cells", + "nine squares", + "organize", + "presentation", + "section", + "segments", + "settings", + "space", + "squares", + "structure", + "table", + "thumbnail view", + "view" + ], + "popularity": 2110 + }, + "GRID_4X4": { + "tags": [ + "4", + "4x4", + "arrangement", + "block", + "by", + "cells", + "collection", + "columns", + "component", + "data", + "design", + "display", + "distribution", + "element", + "formatting", + "four by four", + "grid", + "grouping", + "layout", + "lines", + "matrix", + "order", + "organization", + "pattern", + "rows", + "section", + "segment", + "space", + "squares", + "structure", + "system", + "table", + "unit", + "view" + ], + "popularity": 3272 + }, + "GRID_GOLDENRATIO": { + "tags": [ + "aesthetic", + "alignment", + "arrangement", + "art", + "balance", + "composition", + "composition guide", + "design", + "fibonacci", + "frame", + "golden", + "golden ratio", + "goldenratio", + "grid", + "guide", + "harmony", + "layout", + "layout guide", + "lines", + "mathematical", + "overlay", + "photography", + "proportion", + "ratio", + "rectangle", + "rule of thirds", + "space", + "spiral", + "squares", + "structure", + "symmetry", + "visual" + ], + "popularity": 1223 + }, + "GRID_OFF": { + "tags": [ + "arrangement", + "blocked", + "collage", + "cross out", + "diagonal line", + "disable", + "disabled", + "display", + "enabled", + "format", + "grid", + "grid off", + "hide", + "image", + "inactive", + "layout", + "no grid", + "off", + "on", + "pattern", + "presentation", + "rectangles", + "remove grid", + "removed", + "slash", + "squares", + "structure", + "toggle", + "ungrid", + "view" + ], + "popularity": 1620 + }, + "GRID_ON": { + "tags": [ + "alignment", + "arrange", + "array", + "background", + "blocks", + "bounding box", + "cells", + "chart", + "collage", + "columns", + "data", + "diagram", + "disabled", + "display", + "enabled", + "format", + "geometry", + "graph", + "grid", + "image", + "layout", + "lines", + "matrix", + "off", + "on", + "organize", + "outline", + "pattern", + "plot", + "rows", + "segmentation", + "slash", + "spreadsheet", + "squares", + "structure", + "table", + "view" + ], + "popularity": 11220 + }, + "GRID_VIEW": { + "tags": [ + "app", + "application square", + "arrangement", + "block layout", + "blocks", + "boxes", + "components", + "content", + "dashboard", + "data display", + "design", + "display", + "elements", + "grid", + "grid layout", + "grid view", + "information display", + "interface", + "items", + "layout", + "matrix", + "multiple items", + "organization", + "organize", + "organized", + "pattern", + "screen", + "site", + "square grid", + "squares", + "structure", + "structured", + "system", + "tile view", + "tiles", + "ui", + "ux", + "view", + "visual display", + "web", + "website", + "window" + ], + "popularity": 65692 + }, + "GROUP": { + "tags": [ + "accounts", + "administration", + "audience", + "basic", + "committee", + "community", + "contacts", + "crowd", + "directory", + "employees", + "face", + "family", + "figures", + "friends", + "group", + "heads", + "humans", + "list", + "management", + "members", + "network", + "outline", + "people", + "persons", + "profile", + "profiles", + "roster", + "shape", + "silhouettes", + "simple", + "social", + "staff", + "team", + "users" + ], + "popularity": 64562 + }, + "GROUP_ADD": { + "tags": [ + "accounts", + "add", + "add friend", + "add member", + "add user", + "avatar", + "circle", + "collaborate", + "collective", + "committee", + "contact", + "face", + "family", + "friend", + "friends", + "group", + "human", + "humans", + "inclusion", + "increase", + "invite", + "join", + "member", + "membership", + "more", + "network", + "new", + "people", + "person", + "persons", + "plus", + "profile", + "profiles", + "roster", + "silhouette", + "social", + "team", + "user profile", + "users" + ], + "popularity": 43842 + }, + "GROUP_OFF": { + "tags": [ + "association off", + "body", + "cancel group", + "club", + "cluster off", + "collaboration", + "collection off", + "community off", + "connection off", + "crew off", + "crowd", + "delete group", + "disabled", + "disband", + "gathering", + "gathering off", + "group", + "group disabled", + "group off", + "human", + "meeting", + "members off", + "network off", + "off", + "people", + "people disabled", + "people off", + "person", + "remove group", + "separate", + "social", + "society off", + "split", + "squad off", + "team disabled", + "team off", + "teams", + "ungroup", + "unit off", + "users disabled", + "users off" + ], + "popularity": 3180 + }, + "GROUP_REMOVE": { + "tags": [ + "account remove", + "accounts", + "action", + "application", + "button", + "collaboration", + "committee", + "community", + "control", + "delete member", + "delete person", + "delete user", + "face", + "family", + "friends", + "group", + "group remove", + "humans", + "membership", + "menu", + "minus", + "negative", + "network", + "people", + "people icon", + "person icon", + "persons", + "profile remove", + "profiles", + "remove", + "remove member", + "remove person", + "remove user", + "silhouette", + "social", + "subtract", + "team", + "ungroup", + "ungrouping", + "user profile", + "users" + ], + "popularity": 3832 + }, + "GROUP_WORK": { + "tags": [ + "alliance", + "assembly", + "association", + "avatars", + "business", + "circular", + "collaboration", + "collective", + "community", + "congregation", + "crowd", + "employees", + "figures", + "gathering", + "group", + "huddle", + "members", + "network", + "organization", + "oval", + "partnership", + "people", + "profiles", + "round", + "silhouettes", + "social", + "staff", + "team", + "teamwork", + "together", + "users", + "work" + ], + "popularity": 21273 + }, + "GROUPS": { + "tags": [ + "audience", + "avatars", + "body", + "club", + "collaboration", + "collective", + "community", + "connected", + "crowd", + "figures", + "gathering", + "graphic", + "groups", + "human", + "icon", + "joined", + "many", + "meeting", + "members", + "multiple", + "network", + "outline", + "participants", + "people", + "person", + "profiles", + "shape", + "silhouettes", + "social", + "solid", + "symbol", + "team", + "teams", + "together", + "ui", + "users" + ], + "popularity": 177258 + }, + "GROUPS_2": { + "tags": [ + "assembly", + "avatars", + "body", + "circle", + "club", + "collaboration", + "community", + "community icon", + "connection", + "crowd", + "crowd icon", + "demographic", + "figures", + "gathering", + "group icon", + "groups", + "hair", + "human", + "interaction", + "meeting", + "members", + "members icon", + "membership", + "network", + "network icon", + "people", + "people icon", + "person", + "profiles", + "profiles icon", + "silhouettes", + "social", + "social icon", + "team", + "team icon", + "teams", + "user icon", + "users" + ], + "popularity": 5409 + }, + "GROUPS_3": { + "tags": [ + "abstract", + "account", + "assembly", + "audience", + "avatars", + "body", + "circle", + "club", + "collaboration", + "collective", + "community", + "crowd", + "figures", + "gathering", + "group", + "groups", + "head", + "human", + "individuals", + "many people", + "meeting", + "members", + "multiple people", + "network", + "people", + "person", + "profile", + "profiles", + "shoulders", + "silhouettes", + "social", + "team", + "teams", + "three people", + "three users", + "user", + "users" + ], + "popularity": 3399 + }, + "H_MOBILEDATA": { + "tags": [ + "4g", + "alphabet", + "alphanumeric", + "cellular", + "cellular connection", + "cellular data", + "character", + "communication", + "connection", + "connectivity", + "data", + "data network", + "font", + "h", + "h symbol", + "h+", + "high speed data", + "internet", + "internet connection", + "letter h", + "letters", + "mobile", + "mobile internet", + "mobile network", + "mobile signal", + "network", + "phone", + "service", + "signal", + "symbol", + "telephone", + "text", + "type", + "typography", + "wireless", + "wireless data" + ], + "popularity": 877 + }, + "H_PLUS_MOBILEDATA": { + "tags": [ + "+", + "3g", + "4g", + "access", + "alphabet", + "broadband", + "cellular", + "cellular data", + "character", + "connection", + "connectivity", + "data", + "font", + "h", + "h plus", + "h+", + "high speed", + "hplus", + "indicator", + "internet", + "internet access", + "letters", + "mobile", + "mobile data", + "mobile internet", + "mobile network", + "modem", + "network", + "plus", + "service", + "signal", + "speed", + "status", + "symbol", + "technology", + "telecommunications", + "text", + "type", + "wifi", + "wireless" + ], + "popularity": 768 + }, + "HAIL": { + "tags": [ + "alert", + "bad weather", + "body", + "circles", + "climate", + "cold", + "dots", + "environment", + "forecast", + "frozen", + "hail", + "human", + "ice", + "meteorology", + "natural disaster", + "nature", + "people", + "person", + "pick", + "precipitation", + "public", + "rain", + "severe weather", + "sky", + "sleet", + "snow", + "stop", + "storm", + "taxi", + "transportation", + "warning", + "weather", + "weather forecast", + "winter" + ], + "popularity": 7396 + }, + "HANDSHAKE": { + "tags": [ + "accord", + "agreement", + "alliance", + "business", + "collaboration", + "connection", + "contract", + "cooperation", + "deal", + "glyph", + "greeting", + "hand", + "hands", + "handshake", + "joining hands", + "line icon", + "meeting", + "negotiation", + "outline", + "partnership", + "pictogram", + "relationship", + "shake", + "solidarity", + "support", + "trust", + "two hands", + "unity", + "welcome" + ], + "popularity": 24590 + }, + "HANDYMAN": { + "tags": [ + "adjust", + "build", + "builder", + "cog", + "configuration", + "construction", + "craftsman", + "customize", + "engineering", + "equipment", + "fix", + "gear", + "hammer", + "handyman", + "job", + "maintenance", + "mechanic", + "options", + "preferences", + "professional", + "repair", + "screw", + "screwdriver", + "service", + "settings", + "spanner", + "toolbox", + "tools", + "utility", + "work", + "workshop", + "wrench" + ], + "popularity": 27612 + }, + "HARDWARE": { + "tags": [ + "adjust", + "administration", + "break", + "circle", + "cog", + "configuration", + "construction", + "control", + "customize", + "engine", + "engineering", + "gear", + "hammer", + "hardware", + "industrial", + "machinery", + "management", + "mechanical", + "mechanism", + "nail", + "options", + "parameters", + "personalize", + "preferences", + "repair", + "rotate", + "settings", + "setup", + "sharp", + "system", + "technical", + "technology", + "tool", + "tools", + "turn", + "wheel" + ], + "popularity": 5395 + }, + "HD": { + "tags": [ + "alphabet", + "character", + "clarity", + "codec", + "content", + "crisp", + "definition", + "detail", + "digital", + "display", + "film", + "font", + "hd", + "high", + "high definition", + "indicator", + "information", + "label", + "letter d", + "letter h", + "letters", + "mark", + "media", + "movie", + "movies", + "multimedia", + "pixels", + "playback", + "quality", + "resolution", + "screen", + "sharp", + "streaming", + "symbol", + "text", + "tv", + "type", + "video" + ], + "popularity": 3346 + }, + "HDR_AUTO": { + "tags": [ + "a", + "adjustment", + "alphabet", + "auto", + "automatic", + "button", + "camera", + "character", + "circle", + "control", + "dynamic", + "enhancement", + "feature", + "font", + "hdr", + "high", + "high dynamic range", + "image", + "letters", + "mode", + "option", + "photo", + "photography", + "picture", + "quality", + "range", + "setting", + "switch", + "symbol", + "text", + "toggle", + "type" + ], + "popularity": 3073 + }, + "HDR_AUTO_SELECT": { + "tags": [ + "+", + "a", + "adjustment", + "alphabet", + "auto", + "automatic", + "button", + "camera", + "character", + "circle", + "contrast", + "detail", + "dynamic", + "enhancement", + "exposure", + "font", + "glyph", + "graphic", + "hdr", + "high", + "high dynamic range", + "icon", + "image quality", + "letters", + "multimedia", + "option", + "photo", + "photo editing", + "photography", + "range", + "select", + "setting", + "switch", + "symbol", + "technology", + "text", + "toggle", + "type", + "ui element", + "video editing", + "videography" + ], + "popularity": 690 + }, + "HDR_ENHANCED_SELECT": { + "tags": [ + "add", + "adjustment", + "alphabet", + "brightness", + "camera", + "character", + "color", + "contrast", + "dynamic", + "effect", + "enhance", + "enhanced", + "enhancement", + "film", + "filter", + "font", + "frame", + "graphic", + "hdr", + "high", + "high dynamic range", + "image", + "letters", + "media", + "mode", + "movie", + "option", + "photo", + "photography", + "picture", + "plus", + "quality", + "range", + "select", + "selection", + "setting", + "square", + "symbol", + "text", + "type", + "video", + "vivid" + ], + "popularity": 747 + }, + "HDR_OFF": { + "tags": [ + "alphabet", + "button", + "camera settings", + "cancel", + "character", + "control", + "diagonal line", + "disabled", + "dynamic", + "enabled", + "enhance", + "font", + "hdr", + "hdr disabled", + "hdr off", + "high", + "high dynamic range", + "high dynamic range disabled", + "high dynamic range off", + "image adjustment", + "image settings", + "letters", + "letters h d r", + "letters hdr", + "off", + "on", + "option", + "photo editing", + "photography", + "range", + "select", + "slash", + "strike through", + "symbol", + "text", + "text cancel", + "text disabled", + "text off", + "three letters", + "type", + "video settings", + "visual settings" + ], + "popularity": 658 + }, + "HDR_OFF_SELECT": { + "tags": [ + "alphabet", + "border", + "camera", + "cancel", + "character", + "circle", + "control", + "disabled", + "dynamic", + "effect", + "enabled", + "enhancement", + "filter", + "font", + "hdr", + "hdr off", + "high", + "high dynamic range off", + "image", + "inactive", + "letters", + "mode", + "no hdr", + "off", + "on", + "option", + "outline", + "photo", + "photography", + "picture", + "range", + "rectangle", + "select", + "selection", + "setting", + "slash", + "square", + "symbol", + "text", + "three characters", + "three letters", + "toggle", + "type" + ], + "popularity": 647 + }, + "HDR_ON": { + "tags": [ + "activate", + "add", + "alphabet", + "button", + "camera", + "capture", + "character", + "control", + "dynamic", + "enable", + "enhance", + "enhancement", + "feature", + "font", + "hdr", + "high", + "high dynamic range", + "image", + "letters", + "movie", + "on", + "option", + "photography", + "picture", + "plus", + "quality", + "range", + "record", + "select", + "setting", + "switch", + "symbol", + "text", + "toggle", + "type", + "video" + ], + "popularity": 1184 + }, + "HDR_ON_SELECT": { + "tags": [ + "+", + "alphabet", + "bright", + "button", + "camera", + "character", + "cinema", + "circle", + "contrast", + "control", + "dark", + "dynamic", + "enhanced", + "feature", + "film", + "font", + "graphic", + "hdr", + "high", + "high dynamic range", + "image", + "letters", + "mode", + "on", + "option", + "photo", + "photography", + "picture", + "processing", + "quality", + "range", + "select", + "setting", + "switch", + "symbol", + "text", + "tone mapping", + "type", + "video", + "video editing" + ], + "popularity": 725 + }, + "HDR_PLUS": { + "tags": [ + "+", + "activate", + "add", + "alphabet", + "button", + "camera", + "character", + "circle", + "control", + "dynamic", + "editor", + "effect", + "enable", + "enhance", + "enhancement", + "filter", + "font", + "geometric", + "hdr", + "hdr mode", + "hdr plus", + "hdr plus on", + "high", + "high dynamic range", + "image processing", + "imaging", + "letters", + "media", + "on", + "photo", + "photography", + "photography mode", + "picture", + "plus", + "quality", + "range", + "select", + "settings", + "switch", + "symbol", + "text", + "toggle", + "type", + "video", + "visual effect" + ], + "popularity": 862 + }, + "HDR_STRONG": { + "tags": [ + "adjust", + "adjust image", + "brightness", + "camera", + "camera settings", + "circles", + "contrast", + "dots", + "dynamic", + "enhance", + "enhanced", + "enhanced image", + "exposure", + "exposure settings", + "hdr", + "hdr strong", + "high", + "high dynamic range", + "image", + "image editing", + "improve", + "options", + "photo", + "photo editing", + "photo quality", + "photography", + "picture", + "picture settings", + "quality", + "range", + "settings", + "strong", + "visual", + "visual effect", + "visual settings" + ], + "popularity": 2695 + }, + "HDR_WEAK": { + "tags": [ + "camera", + "circle", + "circles", + "contrast", + "control", + "correction", + "dark", + "disabled", + "dots", + "dynamic", + "effect", + "empty", + "enhance", + "enhancement", + "exposure", + "filter", + "hdr", + "high", + "high dynamic range", + "hollow", + "image", + "inactive", + "light", + "low", + "off", + "option", + "outline", + "photo", + "photography", + "range", + "ring", + "setting", + "ui", + "weak" + ], + "popularity": 2195 + }, + "HEADPHONES": { + "tags": [ + "accessory", + "audio", + "audio device", + "audio equipment", + "call", + "communication", + "device", + "ear", + "ear cups", + "earphone", + "electronics", + "entertainment", + "equipment", + "gaming", + "headband", + "headphones", + "headphones icon", + "headset", + "headset icon", + "listen", + "listening", + "listening device", + "multimedia", + "music", + "over ear", + "sound", + "sound device", + "stereo", + "support", + "technology", + "virtual reality" + ], + "popularity": 17615 + }, + "HEADPHONES_BATTERY": { + "tags": [ + "accessory", + "audio", + "battery", + "bluetooth", + "charge", + "charging", + "connection", + "device", + "ear", + "earphone", + "electronic", + "energy", + "headphones", + "headset", + "icon", + "indicator", + "level", + "listen", + "listening", + "music", + "pairing", + "power", + "sound", + "status", + "symbol.", + "technology", + "ui", + "wireless" + ], + "popularity": 1518 + }, + "HEADSET": { + "tags": [ + "accessory", + "audio", + "audio device", + "audio equipment", + "call", + "communication", + "device", + "ear", + "ear cups", + "earphone", + "electronics", + "entertainment", + "equipment", + "gaming", + "headband", + "headphones", + "headphones icon", + "headset", + "headset icon", + "listen", + "listening", + "listening device", + "multimedia", + "music", + "over ear", + "sound", + "sound device", + "stereo", + "support", + "technology", + "virtual reality" + ], + "popularity": 8028 + }, + "HEADSET_MIC": { + "tags": [ + "accessory", + "audio", + "audio device", + "band", + "boom mic", + "call", + "chat", + "communication", + "device", + "double earpiece", + "ear", + "earphone", + "earpieces", + "entertainment", + "gadget", + "headphones", + "headset", + "listen", + "listen and talk", + "mic", + "microphone", + "music", + "podcast", + "record", + "sound", + "speak", + "speak and listen", + "talk", + "technology", + "telecommunication", + "voice" + ], + "popularity": 16928 + }, + "HEADSET_OFF": { + "tags": [ + "accessory", + "audio", + "audio off", + "broken", + "call", + "chat", + "communication", + "device", + "diagonal line", + "disabled", + "disconnected", + "ear", + "earphone", + "enabled", + "headphones", + "headphones muted", + "headphones off", + "headset", + "headset muted", + "listen", + "listening", + "meeting", + "mic", + "music", + "mute", + "muted", + "muted audio", + "off", + "on", + "quiet", + "silence", + "slash", + "sound", + "sound off", + "talk", + "unavailable", + "video call", + "voice", + "volume" + ], + "popularity": 2012 + }, + "HEALING": { + "tags": [ + "aid", + "band-aid", + "bandage", + "clinic", + "cross", + "cure", + "doctor", + "edit", + "editing", + "emergency", + "first aid", + "fix", + "gauze", + "healing", + "health", + "health care", + "health kit", + "healthcare", + "hospital", + "image", + "injury", + "medical", + "medical supplies", + "medicine", + "nurse", + "patient", + "pharmacy", + "plaster", + "recovery", + "remedy", + "treatment", + "wellness", + "wound" + ], + "popularity": 7853 + }, + "HEALTH_AND_SAFETY": { + "tags": [ + "+", + "add", + "aid", + "and", + "care", + "certified", + "cross", + "cross symbol", + "defense", + "guard", + "health", + "health shield", + "health symbol", + "healthcare", + "home", + "immune", + "medical", + "medical shield", + "medical symbol", + "medicare", + "nest", + "plus", + "preventative", + "privacy", + "private", + "protect", + "protected", + "protection", + "reliable", + "safe", + "safeguard", + "safety", + "safety shield", + "safety symbol", + "secure", + "security", + "shield", + "shield symbol", + "symbol", + "trust", + "verified", + "wellness" + ], + "popularity": 36436 + }, + "HEARING": { + "tags": [ + "abstract", + "accessibility", + "accessible", + "acoustic", + "aids", + "assistance", + "audio", + "body", + "communication", + "concept", + "disability", + "ear", + "frequency", + "handicap", + "health", + "hearing", + "hearing aids", + "help", + "human", + "impaired", + "language", + "listen", + "listen in", + "medical", + "mono", + "noise", + "outline", + "sensory", + "shape", + "sound", + "symbol", + "understanding", + "volume", + "waves" + ], + "popularity": 9013 + }, + "HEARING_DISABLED": { + "tags": [ + "access", + "accessibility", + "accessible", + "aid", + "assist", + "assistance", + "audio", + "circle", + "communication", + "deaf", + "diagonal line", + "disability", + "disabled", + "ear", + "enabled", + "handicap", + "hard of hearing", + "health", + "hearing", + "hearing disabled", + "hearing impairment", + "help", + "impaired", + "line", + "listen", + "medical", + "mute", + "off", + "on", + "profile", + "prohibited", + "silent", + "slash", + "sound", + "special needs", + "status", + "symbol", + "user", + "volume" + ], + "popularity": 2327 + }, + "HEART_BROKEN": { + "tags": [ + "bad review", + "break", + "broken", + "broken heart", + "core", + "crush", + "delete", + "dislike", + "emotion", + "favorite", + "favourite", + "health", + "heart", + "like", + "love", + "not liked", + "not loved", + "nucleus", + "outline", + "rejected", + "relationship", + "remove", + "romance", + "sadness", + "shape", + "split", + "symbol", + "unfavorite", + "unfavorite button", + "unfavourite", + "unlike", + "unlike button", + "unloved", + "valentine" + ], + "popularity": 6629 + }, + "HEAT_PUMP": { + "tags": [ + "air conditioner", + "air conditioning", + "air flow", + "appliance", + "building", + "climate control", + "commercial", + "cool", + "cooling", + "cooling system", + "eco-friendly", + "efficiency", + "energy", + "furnance", + "green energy", + "heat", + "heat pump", + "heating", + "heating system", + "home", + "house", + "hvac", + "indoor climate", + "industrial", + "nest", + "pump", + "residential", + "system", + "technology", + "temperature", + "temperature control", + "thermostat", + "usage", + "ventilation", + "ventilation system" + ], + "popularity": 2237 + }, + "HEIGHT": { + "tags": [ + "arrow", + "calibration", + "color", + "dimension", + "dimension tool", + "doc", + "double ended arrow", + "down", + "edit", + "editing", + "editor", + "extend", + "fill", + "format", + "height", + "length", + "length measurement", + "line segment", + "lines", + "marking", + "measure", + "measurement tool", + "paint", + "ruler", + "scale", + "scale indicator", + "sheet", + "size", + "size indicator", + "size tool", + "spreadsheet", + "straight line", + "style", + "tall", + "text", + "ticks", + "type", + "up", + "vertical", + "vertical dimension", + "vertical measurement", + "writing" + ], + "popularity": 7987 + }, + "HELP": { + "tags": [ + "?", + "about", + "answer", + "assistance", + "button", + "circle", + "circular", + "documentation", + "element", + "faq", + "guide", + "guide me", + "help", + "icon", + "info", + "information", + "instructions", + "knowledge", + "line", + "link", + "manual", + "outline", + "punctuation", + "query", + "question", + "question mark", + "recent", + "restore", + "shape", + "stroke", + "support", + "symbol", + "tutorial", + "ui", + "user manual", + "what is" + ], + "popularity": 119484 + }, + "HELP_CENTER": { + "tags": [ + "?", + "advice", + "aid", + "ask", + "assistance", + "center", + "circle", + "customer service", + "documentation", + "dot", + "faq", + "guide", + "help", + "help center", + "info", + "information", + "information symbol", + "knowledge base", + "learn", + "manual", + "punctuation", + "query", + "query symbol", + "question", + "question mark", + "recent", + "resource", + "restore", + "service", + "shape", + "suggestion", + "support", + "symbol", + "tutorial" + ], + "popularity": 27308 + }, + "HELP_OUTLINE": { + "tags": [ + "?", + "about", + "answer", + "assistance", + "button", + "circle", + "circular", + "documentation", + "element", + "faq", + "guide", + "guide me", + "help", + "icon", + "info", + "information", + "instructions", + "knowledge", + "line", + "link", + "manual", + "outline", + "punctuation", + "query", + "question", + "question mark", + "recent", + "restore", + "shape", + "stroke", + "support", + "symbol", + "tutorial", + "ui", + "user manual", + "what is" + ], + "popularity": 170316 + }, + "HEVC": { + "tags": [ + "abbreviation", + "acronym", + "alphabet", + "character", + "codec", + "coding", + "compression", + "digital", + "efficiency", + "encoding", + "file type", + "film", + "font", + "format", + "h.265", + "hevc", + "high", + "high efficiency video coding", + "identification", + "label", + "letters", + "media", + "movie", + "multimedia", + "playback", + "short", + "standard", + "streaming", + "symbol", + "tag", + "technology", + "text", + "title", + "type", + "typography", + "video" + ], + "popularity": 743 + }, + "HEXAGON": { + "tags": [ + "adjust", + "configuration", + "defense", + "filled", + "futuristic", + "gears", + "geometry", + "hexagon", + "modern", + "outline", + "polygon", + "protection", + "secure", + "security", + "settings", + "shape", + "shield", + "six sides", + "six-sided", + "solid", + "technology" + ], + "popularity": 3516 + }, + "HIDE_IMAGE": { + "tags": [ + "absence", + "artwork", + "blocked", + "broken", + "conceal", + "content", + "disabled", + "display", + "enabled", + "eye", + "gallery", + "graphic", + "hide", + "image", + "invisible", + "landscape", + "media", + "mountain", + "mountains", + "off", + "on", + "photo", + "photography", + "picture", + "placeholder", + "private", + "remove", + "restrict", + "secret", + "slash", + "toggle", + "unsee", + "unview", + "view", + "visibility", + "visual" + ], + "popularity": 3111 + }, + "HIDE_SOURCE": { + "tags": [ + "access", + "circle", + "concealment", + "confidential", + "control", + "disabled", + "enabled", + "eye", + "eyeball", + "hide", + "hiding", + "invisible", + "lock", + "monitoring", + "observation", + "off", + "offline", + "on", + "privacy", + "private", + "private mode", + "protected", + "protection", + "reveal", + "secret", + "secure", + "security", + "shape", + "show", + "slash", + "source", + "surveillance", + "unhide", + "unlock", + "unreveal", + "unviewable", + "view", + "visible" + ], + "popularity": 10181 + }, + "HIGH_QUALITY": { + "tags": [ + "achievement", + "alphabet", + "award", + "badge", + "best", + "button", + "certification", + "character", + "definition", + "display", + "excellent", + "exclusive", + "favorite", + "first", + "five star", + "font", + "gold", + "high", + "hq", + "icon", + "letters", + "luxury", + "movie", + "movies", + "preferred", + "premium", + "quality", + "quality mark", + "rank", + "ranking", + "rating", + "resolution", + "review", + "screen", + "seal of approval", + "stamp", + "star", + "symbol", + "text", + "top", + "tv", + "type", + "winner", + "winner's medal" + ], + "popularity": 5292 + }, + "HIGHLIGHT": { + "tags": [ + "accent", + "annotate", + "annotation", + "attention", + "color", + "curve", + "doc", + "document", + "document editor", + "drawing", + "edit", + "editing", + "editor", + "emphasize", + "emphasizing", + "fill", + "flash", + "focus", + "format", + "formatting", + "highlight", + "important", + "ink", + "light", + "line", + "marker", + "marker pen", + "note", + "paint", + "pen", + "review", + "select", + "selection", + "shape", + "sheet", + "spreadsheet", + "style", + "text", + "tool", + "type", + "underline", + "write", + "writing", + "yellow" + ], + "popularity": 5571 + }, + "HIGHLIGHT_ALT": { + "tags": [ + "alt", + "angle", + "area selection", + "arrow", + "bounding box", + "box", + "choose", + "click", + "corner", + "cursor", + "designate", + "draw", + "editing", + "focus", + "graphic design", + "graphics", + "highlight", + "indicate", + "ink selection", + "lines", + "marker", + "pick", + "pointer", + "range selection", + "select", + "selection", + "shape", + "square", + "target", + "text highlight", + "text select", + "tools", + "word select", + "zone selection" + ], + "popularity": 9154 + }, + "HIGHLIGHT_OFF": { + "tags": [ + "abort", + "action", + "block", + "button", + "cancel", + "circle", + "clear", + "close", + "cross", + "delete", + "deny", + "deselect", + "discard", + "dismiss", + "error", + "exit", + "failure", + "forbidden", + "highlight", + "highlight off", + "invalid", + "negative", + "no", + "off", + "quit", + "reject", + "remove", + "revoke", + "round", + "stop", + "turn off", + "unselect", + "x" + ], + "popularity": 125243 + }, + "HIKING": { + "tags": [ + "activity", + "adventure", + "backpacking", + "bag", + "climbing", + "duffle", + "exercise", + "exploration", + "hiking", + "human", + "journey", + "leisure", + "man", + "mountain", + "mountain range", + "mountains", + "nature", + "outdoors", + "path", + "person", + "recreation", + "silhouette", + "social", + "sport", + "sports", + "stick", + "trail", + "travel", + "trek", + "walking", + "wanderlust" + ], + "popularity": 11653 + }, + "HISTORY": { + "tags": [ + "activity", + "arrow", + "back", + "backup", + "backwards", + "circular", + "clear", + "clock", + "cycle", + "data", + "date", + "defaults", + "device", + "factory", + "history", + "home", + "initialize", + "log", + "nest", + "previous", + "reboot", + "recover", + "refresh", + "renew", + "repair", + "reset", + "restart", + "restore", + "retrieve", + "reverse", + "revert", + "rollback", + "rotate", + "save", + "schedule", + "settings", + "system", + "time", + "timeline", + "turn", + "undo", + "update" + ], + "popularity": 95766 + }, + "HISTORY_EDU": { + "tags": [ + "academic", + "archive", + "book", + "clock", + "college", + "degree", + "diploma", + "document", + "edu", + "education", + "exam", + "feather", + "future", + "graduation", + "history", + "hour", + "knowledge", + "learning", + "lesson", + "letters", + "memory", + "minute", + "paper", + "past", + "pen", + "present", + "quill", + "reading", + "school", + "second", + "story", + "student", + "study", + "teaching", + "test", + "time", + "timeline", + "tools", + "university", + "write", + "writing" + ], + "popularity": 25004 + }, + "HISTORY_TOGGLE_OFF": { + "tags": [ + "activity", + "clock", + "control", + "dash", + "dashed", + "date", + "deactivate", + "disable", + "disable history", + "disabled.", + "element", + "events", + "history", + "history toggle off", + "logs", + "off", + "off state", + "option", + "past", + "previous", + "recent", + "record", + "schedule", + "setting", + "state", + "stop", + "switch", + "time", + "timeline", + "toggle", + "toggle off", + "turn off", + "turn off history", + "ui control" + ], + "popularity": 11124 + }, + "HIVE": { + "tags": [ + "abstract", + "apiary", + "bee", + "beehive", + "cluster", + "collection", + "colony", + "community", + "connection", + "data", + "database", + "geometric", + "group", + "hexagon", + "hexagonal", + "hive", + "honey", + "honeycomb", + "insect", + "nature", + "network", + "organization", + "pattern", + "shape", + "storage", + "structure", + "system" + ], + "popularity": 5093 + }, + "HLS": { + "tags": [ + "alphabet", + "broadcast", + "broadcasting", + "character", + "communication", + "connectivity", + "content", + "data", + "develop", + "developer", + "digital", + "engineer", + "engineering", + "entertainment", + "font", + "hls", + "http live streaming", + "internet", + "letters", + "live", + "media", + "multimedia", + "network", + "online", + "platform", + "play", + "player", + "protocol", + "signal", + "stream", + "streaming", + "symbol", + "technology", + "technology standard", + "text", + "transfer", + "type", + "video", + "video streaming", + "web" + ], + "popularity": 816 + }, + "HLS_OFF": { + "tags": [ + "alphabet", + "character", + "connection", + "cross", + "develop", + "developer", + "diagonal", + "disable", + "disabled", + "enabled", + "engineer", + "engineering", + "font", + "hls", + "hls off", + "inactive", + "letters", + "line", + "media", + "media controls", + "media player", + "multimedia", + "network", + "off", + "offline", + "on", + "platform", + "playback", + "slash", + "slashes", + "stream", + "streaming", + "strike", + "symbol", + "technology", + "text", + "type", + "unavailable", + "video", + "video controls", + "video player" + ], + "popularity": 817 + }, + "HOLIDAY_VILLAGE": { + "tags": [ + "accommodation", + "architecture", + "beach", + "buildings", + "camping", + "city", + "cityscape", + "collection", + "community", + "cottage", + "destination", + "estate", + "group", + "holiday", + "holiday village", + "home", + "house", + "houses", + "housing", + "lake", + "lodge", + "lodging", + "maps", + "neighborhood", + "perspective", + "place", + "property", + "real", + "real estate", + "residence", + "residential", + "rural", + "settlement", + "skyline", + "stay", + "street", + "suburban", + "tourism", + "town", + "travel", + "traveling", + "urban", + "vacation", + "village" + ], + "popularity": 8997 + }, + "HOME": { + "tags": [ + "abode", + "address", + "app", + "application--house", + "architecture", + "beginning", + "building", + "button", + "components", + "dashboard", + "design", + "domicile", + "dwelling", + "estate", + "filled", + "geometry", + "home", + "homepage", + "house", + "interface", + "layout", + "link", + "lodging", + "main", + "menu", + "navigation", + "outline", + "place", + "property", + "real", + "real estate", + "residence", + "residential", + "screen", + "shape", + "shelter", + "site", + "solid", + "start", + "startup", + "stroke", + "structure", + "tab", + "ui", + "unit", + "ux", + "web", + "website", + "window" + ], + "popularity": 796440 + }, + "HOME_MAX": { + "tags": [ + "address", + "architecture", + "area", + "building", + "device", + "domicile", + "door", + "dwelling", + "enlarge", + "entrance", + "expand", + "fill", + "front", + "full screen", + "gadget", + "hardware", + "home", + "house", + "increase", + "internet", + "iot", + "living", + "location", + "max", + "maximize", + "navigation", + "nest", + "place", + "property", + "real estate", + "residence", + "roof", + "scale", + "smart", + "structure", + "things", + "windows", + "zoom" + ], + "popularity": 1672 + }, + "HOME_MINI": { + "tags": [ + "address", + "architecture", + "basic", + "building", + "button", + "compact", + "device", + "diagram", + "dwelling", + "gadget", + "hardware", + "home", + "house", + "icon", + "internet", + "iot", + "location", + "mini", + "minimal", + "navigation", + "nest", + "outline", + "property", + "real estate", + "residence", + "shape", + "shelter", + "simple", + "small", + "smart", + "structure", + "symbol", + "things" + ], + "popularity": 1299 + }, + "HOME_REPAIR_SERVICE": { + "tags": [ + "adjustable wrench", + "box", + "building", + "construction", + "equipment", + "fix", + "gear", + "hammer", + "handyman", + "home", + "house", + "improvement", + "installation", + "job", + "kit", + "labor", + "maintenance", + "mechanic", + "pliers", + "professional", + "renovation", + "repair", + "repairing", + "screwdriver", + "service", + "setup", + "spanner", + "technician", + "tool", + "toolbox", + "tools", + "work", + "workshop", + "wrench" + ], + "popularity": 15306 + }, + "HOME_WORK": { + "tags": [ + "address", + "architecture", + "building", + "business", + "commercial", + "company", + "destination", + "dwelling", + "employment", + "estate", + "factory", + "headquarters", + "home", + "house", + "industry", + "job", + "location", + "maps", + "navigation", + "office", + "place", + "real", + "real estate", + "residence", + "residential", + "shelter", + "structure", + "work", + "workplace" + ], + "popularity": 17320 + }, + "HORIZONTAL_DISTRIBUTE": { + "tags": [ + "align", + "alignment", + "application", + "arrangement", + "arrows", + "bar", + "button", + "diagram", + "distribute", + "editing", + "editor", + "elements", + "equal", + "even", + "format", + "formatting", + "graphic design", + "horizontal", + "layout", + "lines", + "objects", + "order", + "organize", + "paragraph", + "position", + "rectangles", + "rule", + "rules", + "software", + "space", + "spacing", + "style", + "text", + "tool" + ], + "popularity": 2412 + }, + "HORIZONTAL_RULE": { + "tags": [ + "basic", + "boundary", + "content separator", + "divide", + "divider", + "element", + "gap", + "geometry", + "gmail", + "horizontal", + "line", + "line break", + "novitas", + "partition", + "rule", + "section", + "section break", + "separator", + "shape", + "simple", + "spacing", + "split", + "visual break" + ], + "popularity": 11051 + }, + "HORIZONTAL_SPLIT": { + "tags": [ + "arrangement", + "bars", + "content organization", + "display", + "display options", + "divide", + "double panel", + "dual view", + "format", + "horizontal", + "horizontal division", + "horizontal split", + "interface layout", + "layout", + "layout management", + "lines", + "multi-panel", + "multiple panels", + "organization", + "panel", + "partition", + "screen division", + "screen split", + "section", + "separation", + "split", + "stacked", + "two panels", + "user interface element", + "view", + "view options", + "window" + ], + "popularity": 4989 + }, + "HOT_TUB": { + "tags": [ + "bath", + "bathing", + "bathroom", + "bathtub", + "bubbles", + "circle", + "comfort", + "health", + "hot", + "hot tub", + "hotel", + "human", + "hydrotherapy", + "jacuzzi", + "leisure", + "lines", + "person", + "pool", + "recreation", + "relaxation", + "resort", + "rounded rectangle", + "shower", + "soak", + "soaking", + "spa", + "steam", + "steam lines", + "therapy", + "travel", + "tub", + "warm", + "water", + "wellness" + ], + "popularity": 3530 + }, + "HOTEL": { + "tags": [ + "accommodation", + "apartment", + "bed", + "body", + "booking", + "building", + "guesthouse", + "holiday", + "hospitality", + "hostel", + "hotel", + "hotel icon", + "house", + "human", + "inn", + "lodging", + "lodging icon", + "motel", + "people", + "person", + "place", + "rectangle", + "rent", + "reservation", + "resort", + "room", + "shelter", + "sleep", + "square", + "stay", + "structure", + "tourism", + "travel", + "travel destination", + "triangle", + "trip", + "vacation" + ], + "popularity": 14908 + }, + "HOTEL_CLASS": { + "tags": [ + "accommodation", + "achievement", + "bed", + "booking", + "bookmark", + "building", + "class", + "comfort", + "destination", + "favorite", + "guesthouse", + "highlight", + "hospitality", + "hostel", + "hotel", + "important", + "inn", + "journey", + "lodging", + "luxury", + "marked", + "motel", + "quality", + "rank", + "ranking", + "rate", + "rating", + "reservation", + "review", + "reward", + "room", + "save", + "saved", + "service", + "shape", + "special", + "star", + "star rating", + "stars", + "stay", + "tourism", + "travel", + "trip", + "vacation" + ], + "popularity": 9851 + }, + "HOURGLASS_BOTTOM": { + "tags": [ + "bottom", + "clock", + "completed", + "completion", + "countdown", + "deadline", + "deadline exceeded", + "delay", + "duration", + "end", + "expiration", + "final", + "finished", + "future", + "half", + "half full", + "history", + "hourglass", + "loading", + "measure", + "measurement", + "minute", + "minutes", + "past", + "pending", + "processing", + "progress", + "remaining", + "sand", + "time", + "timer", + "wait", + "waiting" + ], + "popularity": 18456 + }, + "HOURGLASS_DISABLED": { + "tags": [ + "angled line", + "circle", + "clock", + "complete", + "countdown", + "cross out", + "delay", + "diagonal line", + "disabled", + "duration", + "elapsed time", + "empty", + "enabled", + "end", + "expired", + "finished", + "hourglass", + "inactive", + "limit", + "loading", + "measure", + "measure time", + "minute", + "minutes", + "off", + "on", + "pause", + "sand", + "slash", + "stop", + "time", + "timer", + "unavailable", + "wait", + "waiting" + ], + "popularity": 3925 + }, + "HOURGLASS_EMPTY": { + "tags": [ + "abstract", + "clock", + "countdown", + "delay", + "duration", + "empty", + "full", + "future", + "history", + "hourglass", + "indicator", + "interval", + "lapse", + "loading", + "measure", + "minutes", + "outline", + "passage", + "past", + "pending", + "period", + "processing", + "progress", + "sand", + "shape", + "status", + "time", + "timer", + "ui element", + "wait", + "waiting" + ], + "popularity": 27577 + }, + "HOURGLASS_FULL": { + "tags": [ + "antique", + "classic", + "countdown", + "delay", + "duration", + "elapsed", + "empty", + "flow", + "full", + "hourglass", + "icon", + "indicator", + "loading", + "measurement", + "minutes", + "pending", + "period", + "progress", + "retro", + "sand", + "symbol", + "temporal", + "time", + "timer", + "ui icon", + "vintage", + "wait", + "waiting" + ], + "popularity": 8867 + }, + "HOURGLASS_TOP": { + "tags": [ + "antique", + "bulb", + "classic", + "countdown", + "delay", + "duration", + "epoch", + "era", + "flow", + "future", + "glass", + "half", + "hourglass", + "indicator", + "loading", + "measurement", + "measuring", + "minute", + "minutes", + "object", + "past", + "pending", + "period", + "progress", + "sand", + "science", + "shape", + "time", + "timer", + "tool", + "top", + "vessel", + "vintage", + "wait", + "waiting" + ], + "popularity": 17968 + }, + "HOUSE": { + "tags": [ + "abode", + "architecture", + "basic", + "building", + "button", + "door", + "dwelling", + "element", + "estate", + "family", + "geometric", + "graphic", + "home", + "homepage", + "house", + "icon", + "line", + "navigation", + "outline", + "place", + "places", + "property", + "real", + "real estate", + "rectangle", + "residence", + "residential", + "roof", + "shelter", + "simple", + "square", + "structure", + "symbol", + "triangle", + "wall", + "window" + ], + "popularity": 20970 + }, + "HOUSE_SIDING": { + "tags": [ + "aluminum", + "architectural", + "architecture", + "building", + "building material", + "construction", + "design", + "dwelling", + "estate", + "exterior", + "facade", + "home", + "horizontal lines", + "house", + "house siding", + "housing", + "layered", + "material", + "overlapping", + "paneling", + "pattern", + "property", + "real", + "real estate", + "renovation", + "repair", + "residential", + "shelter", + "siding", + "structure", + "textured", + "vinyl", + "wall", + "wood" + ], + "popularity": 3547 + }, + "HOUSEBOAT": { + "tags": [ + "accommodation", + "aquatic", + "architecture", + "beach", + "boat", + "building", + "dwelling", + "estate", + "floating", + "holiday", + "home", + "house", + "houseboat", + "lake", + "leisure", + "living", + "lodging", + "maps", + "marine", + "nautical", + "place", + "property", + "real", + "real estate", + "recreation", + "rental", + "residence", + "residential", + "river", + "sea", + "stay", + "tourism", + "transport", + "travel", + "travel industry", + "traveling", + "vacation", + "vessel", + "watercraft" + ], + "popularity": 2417 + }, + "HOW_TO_REG": { + "tags": [ + "accept", + "access", + "account", + "add user", + "approve", + "authorization", + "ballot", + "check", + "checkmark", + "circle", + "complete", + "confirmed", + "done", + "election", + "entry", + "head", + "how", + "join", + "mark", + "member", + "new user", + "ok", + "permission", + "person", + "poll", + "profile", + "register", + "registration", + "select", + "shape", + "shoulders", + "sign up", + "silhouette", + "successful", + "tick", + "to reg", + "user", + "validate", + "verified", + "vote", + "yes" + ], + "popularity": 34559 + }, + "HOW_TO_VOTE": { + "tags": [ + "ballot", + "ballot box", + "ballot paper", + "casting a vote", + "check", + "choice", + "choosing", + "civic duty", + "deciding", + "democracy", + "election", + "government", + "hand", + "hand with x mark", + "how", + "how to vote", + "mark", + "participation", + "political", + "poll", + "polling station", + "selection", + "selection process", + "survey", + "to", + "vote", + "voting", + "voting guide", + "voting process", + "x" + ], + "popularity": 6413 + }, + "HTML": { + "tags": [ + "alphabet", + "angle brackets", + "brackets", + "character", + "code", + "coding", + "computer", + "computing", + "css", + "develop", + "developer", + "development", + "development tools", + "digital", + "document", + "engineer", + "engineering", + "file", + "font", + "greater than sign", + "html", + "internet", + "internet code", + "it", + "language", + "less than sign", + "letters", + "markup", + "markup language", + "platform", + "programming", + "programming language", + "script", + "software", + "source code", + "symbol", + "tags", + "technology", + "text", + "type", + "web", + "web design", + "web development" + ], + "popularity": 4812 + }, + "HTTP": { + "tags": [ + "access", + "address", + "address bar", + "alphabet", + "browser", + "character", + "client", + "communication", + "computer", + "computing", + "connect", + "connection", + "data", + "digital", + "domain", + "font", + "global", + "http", + "http protocol", + "internet", + "letters", + "link", + "navigation", + "network", + "online", + "secure", + "server", + "symbol", + "technology", + "text", + "transfer", + "type", + "url", + "web", + "website", + "world" + ], + "popularity": 6244 + }, + "HTTPS": { + "tags": [ + "access", + "authentication", + "authorization", + "browser", + "closed", + "confidential", + "connection", + "data", + "digital", + "encryption", + "https", + "internet", + "key", + "lock", + "locked", + "network", + "outline", + "padlock", + "password", + "privacy", + "private", + "protected", + "protection", + "protocol", + "restrict", + "safe", + "safeguard", + "safety", + "secure", + "security", + "ssl", + "tls", + "website" + ], + "popularity": 19461 + }, + "HUB": { + "tags": [ + "access", + "center", + "central", + "collection", + "connect", + "connection", + "convergence", + "core", + "data", + "diagram", + "distribution", + "flow", + "focal point", + "hub", + "information", + "interconnected", + "join", + "links", + "network", + "node", + "nodes", + "nucleus", + "organization", + "point", + "relations", + "source", + "structure", + "system", + "topology" + ], + "popularity": 15056 + }, + "HVAC": { + "tags": [ + "ac", + "adjustment", + "air", + "air conditioning", + "air flow", + "air vent", + "airflow", + "airflow direction", + "blower", + "building systems", + "central air", + "climate", + "climate control", + "comfort", + "conditioning", + "control", + "ductwork", + "environment", + "fan", + "heat", + "heating", + "hvac", + "interior", + "settings", + "smart home", + "system", + "temperature", + "temperature control", + "thermostat", + "vent", + "ventilation", + "wind" + ], + "popularity": 2872 + }, + "ICE_SKATING": { + "tags": [ + "activity", + "athlete", + "athletic", + "blade", + "boot", + "cold", + "entertainment", + "equipment", + "exercise", + "figure skating", + "footwear", + "hobby", + "hockey skate", + "ice", + "ice skate", + "leisure", + "olympics", + "recreation", + "sharp", + "shoe", + "skate", + "skates", + "skating", + "social", + "speed skating", + "sport", + "sports", + "travel", + "winter", + "winter sport" + ], + "popularity": 2155 + }, + "ICECREAM": { + "tags": [ + "cafe", + "celebration", + "circle", + "cold", + "cone", + "cool", + "cream", + "delicious", + "dessert", + "event", + "food", + "frozen", + "fun", + "happy", + "ice", + "ice cream", + "icecream", + "indulgence", + "joy", + "menu", + "party", + "picnic", + "refreshing", + "restaurant", + "scoop", + "snack", + "summer", + "sweet", + "tasty", + "travel", + "treat", + "triangle", + "vacation" + ], + "popularity": 5567 + }, + "IMAGE": { + "tags": [ + "add", + "adjust", + "album", + "asset", + "camera", + "collection", + "crop", + "display", + "edit", + "editor", + "file", + "frame", + "gallery", + "graphic", + "image", + "import", + "insert", + "landscape", + "library", + "media", + "mountain", + "mountains", + "original", + "photo", + "photography", + "picture", + "rectangle", + "restore", + "square", + "upload", + "view", + "visual" + ], + "popularity": 100959 + }, + "IMAGE_ASPECT_RATIO": { + "tags": [ + "adjust", + "aspect", + "aspect ratio", + "crop", + "dimensions", + "display", + "format", + "height", + "image", + "media", + "movie", + "orientation", + "photo", + "photography", + "picture", + "presentation", + "proportion", + "ratio", + "rectangle", + "resize", + "resolution", + "scale", + "screen", + "settings", + "size", + "square", + "video", + "view", + "visual", + "width" + ], + "popularity": 1166 + }, + "IMAGE_NOT_SUPPORTED": { + "tags": [ + "alert", + "broken", + "cancel", + "content", + "disabled", + "disallowed", + "enabled", + "error", + "failed", + "forbidden", + "graphic", + "image", + "invalid", + "landscape", + "media", + "missing", + "mountain", + "mountains", + "no", + "not", + "not found", + "not loaded", + "off", + "on", + "photo", + "photography", + "picture", + "placeholder", + "problem", + "restricted", + "slash", + "stop", + "supported", + "unavailable", + "unsupported", + "warning" + ], + "popularity": 5470 + }, + "IMAGE_SEARCH": { + "tags": [ + "analyze", + "bing visual search", + "camera search", + "content search", + "database search", + "digital eye", + "discover image", + "discovery", + "explore", + "find", + "find image", + "find similar", + "glass", + "google lens", + "identify", + "image", + "image input", + "image search", + "internet search", + "landscape", + "look", + "look up", + "magnify", + "magnifying", + "magnifying glass", + "media search", + "mountain", + "mountains", + "object recognition", + "online search", + "photo", + "photo search", + "photography", + "picture", + "picture search", + "reverse image search", + "scan", + "search", + "search bar", + "see", + "visual search", + "web search" + ], + "popularity": 8057 + }, + "IMAGESEARCH_ROLLER": { + "tags": [ + "appearance", + "applicator", + "apply", + "art", + "brush", + "coating", + "color", + "construction", + "creative", + "customize", + "decoration", + "design", + "drawing", + "edit", + "editing", + "fill", + "house painting", + "image", + "imagesearch", + "implement", + "paint", + "paint brush", + "paint roller", + "painting", + "pattern", + "renovation", + "resurface", + "roller", + "search", + "smooth", + "style", + "texture", + "tools", + "wall painting" + ], + "popularity": 2331 + }, + "IMPORT_CONTACTS": { + "tags": [ + "address", + "address book", + "book", + "communicate", + "contacts", + "data", + "diary", + "directory", + "download", + "education", + "import", + "info", + "information", + "journal", + "knowledge", + "learning", + "library", + "literature", + "migration", + "notebook", + "open", + "opened book", + "pages", + "reading", + "receive", + "send", + "share", + "sync", + "synchronize", + "textbook", + "transfer", + "upload" + ], + "popularity": 20605 + }, + "IMPORT_EXPORT": { + "tags": [ + "arrow", + "arrows", + "bidirectional", + "connection", + "data", + "direction", + "direction change", + "document", + "down", + "exchange", + "explort", + "export", + "file", + "flow", + "import", + "interchange", + "link", + "move", + "process", + "reorder", + "shuffle", + "sort", + "swap", + "switch", + "sync", + "synchronize", + "transaction", + "transfer", + "up", + "up down", + "vertical" + ], + "popularity": 19265 + }, + "IMPORTANT_DEVICES": { + "tags": [ + "access", + "android", + "communication", + "computer", + "connected", + "connection", + "critical", + "data", + "desktop", + "devices", + "digital", + "electronics", + "equipment", + "essential", + "gadgets", + "hardware", + "important", + "information", + "ios", + "key", + "mobile", + "monitor", + "network", + "os", + "phone", + "screen", + "security", + "sharing", + "star", + "synchronization", + "tablet", + "tech", + "technology", + "web" + ], + "popularity": 11666 + }, + "INBOX": { + "tags": [ + "archive", + "arrival", + "box", + "category", + "communication", + "container", + "correspondence", + "email", + "folder", + "inbox", + "inbox folder", + "incoming", + "letters", + "mail", + "mail folder", + "message", + "message box", + "messages", + "messages list", + "new messages", + "notifications", + "receive", + "receive mail", + "storage", + "tray", + "unread" + ], + "popularity": 15894 + }, + "INCOMPLETE_CIRCLE": { + "tags": [ + "active", + "activity indicator", + "animation", + "arc", + "broken circle", + "busy", + "chart", + "circle", + "curve", + "geometric", + "graphic", + "incomplete", + "incomplete circle", + "indicator", + "line", + "loading", + "loading spinner", + "open circle", + "partial circle", + "pending", + "process", + "progress", + "progress indicator", + "refresh", + "refresh spinner", + "reload", + "ring", + "round", + "segment", + "shape", + "spinning", + "waiting" + ], + "popularity": 4224 + }, + "INDETERMINATE_CHECK_BOX": { + "tags": [ + "app", + "application", + "box", + "box with line", + "button", + "check", + "checkbox", + "checkbox with line", + "components", + "control", + "dash", + "design", + "form", + "form control", + "half", + "horizontal line", + "incomplete", + "indeterminate", + "indeterminate state", + "input", + "interface", + "mark", + "mixed", + "option", + "option box", + "partial", + "screen", + "select", + "selected", + "selection", + "selection box", + "site", + "square", + "state", + "tick", + "toggle", + "toggle box", + "ui", + "ui element", + "undetermined", + "ux", + "web", + "website" + ], + "popularity": 16658 + }, + "INFO": { + "tags": [ + "about", + "alert", + "announcement", + "assistance", + "circle", + "content", + "data", + "details", + "dialog", + "dot", + "guide", + "help", + "i", + "important", + "indicator", + "info", + "information", + "knowledge", + "learn", + "letter i", + "line", + "message", + "notice", + "popup", + "query", + "question", + "read", + "round", + "service", + "support", + "symbol", + "tip" + ], + "popularity": 465882 + }, + "INPUT": { + "tags": [ + "accept", + "apply", + "approve", + "arrow", + "box", + "button", + "check", + "circle", + "complete", + "confirmed", + "correct", + "done", + "download", + "finished", + "input", + "login", + "mark", + "marker", + "move", + "ok", + "ready", + "right", + "round", + "shape", + "success", + "tick", + "valid", + "verified" + ], + "popularity": 19518 + }, + "INSERT_CHART": { + "tags": [ + "add", + "analysis", + "analytics", + "assessment", + "bar", + "bar chart", + "bars", + "business", + "chart", + "columns", + "create", + "data", + "diagram", + "finance", + "graph", + "growth", + "infographic", + "insert", + "manage", + "measure", + "metrics", + "options", + "performance", + "poll", + "progress", + "report", + "representation", + "results", + "statistics", + "survey", + "tracking", + "visualize" + ], + "popularity": 9260 + }, + "INSERT_CHART_OUTLINED": { + "tags": [ + "add", + "analysis", + "analytics", + "assessment", + "bar", + "bar chart", + "bars", + "business", + "chart", + "columns", + "create", + "data", + "diagram", + "finance", + "graph", + "growth", + "infographic", + "insert", + "manage", + "measure", + "metrics", + "options", + "outlined", + "performance", + "poll", + "progress", + "report", + "representation", + "results", + "statistics", + "survey", + "tracking", + "visualize" + ], + "popularity": 14099 + }, + "INSERT_COMMENT": { + "tags": [ + "add", + "add comment", + "balloon", + "bubble", + "chat", + "comment", + "communication", + "conversation", + "create", + "create comment", + "dialogue", + "discussion", + "feedback", + "insert", + "message", + "new", + "new comment", + "plus", + "rectangle", + "reply", + "respond", + "speech", + "square", + "square bubble", + "talk", + "text", + "text bubble", + "write comment" + ], + "popularity": 8180 + }, + "INSERT_DRIVE_FILE": { + "tags": [ + "add", + "archive", + "blank", + "cloud", + "content", + "create", + "data", + "doc", + "document", + "draft", + "drive", + "edit", + "file", + "form", + "format", + "insert", + "item", + "material", + "memo", + "new", + "note", + "office", + "page", + "paper", + "record", + "report", + "sheet", + "slide", + "storage", + "text", + "upload", + "view", + "write" + ], + "popularity": 28183 + }, + "INSERT_EMOTICON": { + "tags": [ + "account", + "add", + "character", + "chat", + "cheerful", + "circle", + "communication", + "emoji", + "emoticon", + "emotion", + "expression", + "face", + "feeling", + "grin", + "happy", + "human", + "insert", + "joy", + "message", + "mood", + "outline", + "people", + "person", + "profile", + "reaction", + "round", + "select", + "sentiment", + "smile", + "smiley", + "symbol", + "tag", + "text", + "user" + ], + "popularity": 14420 + }, + "INSERT_INVITATION": { + "tags": [ + "add", + "add event", + "add invitation", + "add to calendar", + "agenda", + "appointment", + "booking", + "calendar", + "daily", + "date", + "day", + "event", + "insert", + "insert invitation", + "invitation", + "invite", + "mark", + "meeting", + "month", + "monthly", + "new event", + "new invitation", + "organizing", + "planning", + "plus", + "range", + "remember", + "reminder", + "reservation", + "schedule", + "schedule event", + "square", + "time", + "today", + "week", + "weekly" + ], + "popularity": 10876 + }, + "INSERT_LINK": { + "tags": [ + "add", + "anchor", + "arrow", + "attach", + "attachment", + "chain", + "circle", + "circular", + "clip", + "connect", + "connection", + "direction", + "external", + "file", + "global", + "globe", + "hyperlink", + "insert", + "international", + "internet", + "join", + "line", + "link", + "mail", + "media", + "navigation", + "network", + "point", + "reference", + "round", + "sphere", + "url", + "web", + "website", + "world", + "www" + ], + "popularity": 11344 + }, + "INSERT_PAGE_BREAK": { + "tags": [ + "break", + "content break", + "dash", + "dashed", + "dashed line", + "divide", + "divider", + "doc", + "document", + "document formatting", + "document layout", + "file", + "formatting", + "formatting break", + "horizontal divider", + "horizontal line", + "insert", + "insert break", + "layout", + "line", + "line divider", + "new page", + "page", + "page break", + "paper", + "row", + "section break", + "separation", + "split", + "text", + "text division", + "text editing", + "writing" + ], + "popularity": 1376 + }, + "INSERT_PHOTO": { + "tags": [ + "add", + "adjust", + "album", + "asset", + "camera", + "collection", + "crop", + "display", + "edit", + "editor", + "file", + "frame", + "gallery", + "graphic", + "image", + "import", + "insert", + "landscape", + "library", + "media", + "mountain", + "mountains", + "original", + "photo", + "photography", + "picture", + "rectangle", + "restore", + "square", + "upload", + "view", + "visual" + ], + "popularity": 13822 + }, + "INSIGHTS": { + "tags": [ + "ai", + "analysis", + "analytics", + "analytics report", + "artificial", + "automatic", + "automation", + "bar", + "bars", + "business", + "business intelligence", + "chart", + "circle", + "custom", + "data", + "data visualization", + "diagram", + "financial analysis", + "genai", + "graph", + "growth", + "increase", + "infographic", + "information", + "insights", + "intelligence", + "magic", + "market data", + "measure", + "metrics", + "overview", + "performance", + "performance data", + "performance metrics", + "progress", + "report", + "results", + "smart", + "spark", + "sparkle", + "star", + "stars", + "statistics", + "statistics report", + "summary", + "tracking", + "trend analysis", + "trends", + "up arrow" + ], + "popularity": 58629 + }, + "INSTALL_DESKTOP": { + "tags": [ + "add", + "android", + "app", + "application", + "chrome", + "computer", + "computing", + "configuration", + "deployment", + "desktop", + "device", + "display", + "download", + "electronic", + "fix", + "hard drive", + "hardware", + "install", + "ios", + "mac", + "monitor", + "os", + "pc", + "place", + "plus", + "plus sign", + "program", + "progressive web app", + "pwa", + "rectangle", + "save", + "screen", + "setup", + "software", + "storage", + "system", + "technology", + "web", + "web app", + "window", + "workstation" + ], + "popularity": 3388 + }, + "INSTALL_MOBILE": { + "tags": [ + "android", + "app", + "app install", + "app promo", + "arrow", + "arrows", + "cell", + "device", + "direction", + "down", + "down arrow", + "download", + "download app", + "hardware", + "install", + "install app", + "install mobile", + "ios", + "marketing", + "mobile", + "mobile download", + "os", + "phone", + "phone download", + "promotion", + "security", + "security update", + "software", + "software update", + "system", + "system update", + "system upgrade", + "tablet", + "update", + "upgrade" + ], + "popularity": 2542 + }, + "INTEGRATION_INSTRUCTIONS": { + "tags": [ + "automation", + "brackets", + "build", + "clipboard", + "code", + "coding", + "combine", + "connect", + "connection", + "consolidate", + "css", + "data", + "develop", + "developer", + "development", + "diagram", + "direction", + "doc", + "document", + "engineer", + "engineering clipboard", + "flow", + "guide", + "help", + "html", + "information", + "instructions", + "integration", + "join", + "link", + "merge", + "network", + "platform", + "process", + "programming", + "relation", + "steps", + "structure", + "system", + "unified", + "workflow" + ], + "popularity": 15460 + }, + "INTERESTS": { + "tags": [ + "best", + "bookmark", + "chosen", + "circle", + "collection", + "distinction", + "favorite", + "featured", + "glyph", + "good", + "heart", + "highlighted", + "icon", + "important", + "interests", + "liked", + "marked", + "prefered", + "premium", + "quality", + "rated", + "rating", + "saved", + "selection", + "shape", + "shapes", + "sign", + "social", + "special", + "square", + "star", + "symbol", + "top", + "triangle", + "valuable", + "wishlist" + ], + "popularity": 8890 + }, + "INTERPRETER_MODE": { + "tags": [ + "account", + "accounts", + "assistant", + "audio", + "bilingual", + "chat", + "committee", + "communication", + "conversation", + "dialogue", + "dictation", + "digital translation", + "exchange", + "face", + "family", + "foreign language", + "friends", + "group", + "hear", + "hearing", + "human", + "humans", + "interpretation", + "interpreter", + "keyboard", + "language", + "languages", + "listening", + "machine translation", + "mic", + "microphone", + "mode", + "multilingual", + "network", + "noise", + "people", + "person", + "persons", + "profile", + "profiles", + "record", + "recorder", + "simultaneous", + "social", + "sound", + "speaker", + "speaking", + "speech", + "symbol", + "talk", + "team", + "translate", + "translation", + "understand", + "understanding", + "user", + "users", + "voice" + ], + "popularity": 2912 + }, + "INVENTORY": { + "tags": [ + "archive", + "box", + "boxes", + "chain", + "clipboard", + "commerce", + "container", + "containers", + "control", + "crate", + "crates", + "distribution", + "doc", + "document", + "e-commerce", + "file", + "goods", + "inventory", + "items", + "logistics", + "manage", + "management", + "organize", + "package", + "packages", + "product", + "products", + "receive", + "retail", + "send", + "shipping", + "stack", + "stacking", + "stock", + "storage", + "supply", + "warehouse" + ], + "popularity": 61341 + }, + "INVENTORY_2": { + "tags": [ + "archive", + "assets", + "box", + "boxes", + "collection", + "container", + "count", + "crate", + "delivery", + "file", + "goods", + "inventory", + "items", + "items.", + "logistics", + "management", + "objects", + "organize", + "package", + "packages", + "product", + "quantity", + "resources", + "shipping", + "square", + "stack", + "stock", + "storage", + "supply", + "three dimensional", + "warehouse" + ], + "popularity": 62426 + }, + "INVERT_COLORS": { + "tags": [ + "accessibility", + "accessibility settings", + "adjust", + "adjust colors", + "appearance", + "button", + "change", + "color inversion", + "colors", + "contrast", + "dark mode", + "display", + "drop", + "droplet", + "edit", + "editing", + "hue", + "icon", + "invert", + "invert colors", + "inverted", + "light mode", + "mode", + "modify", + "options", + "palette", + "preferences", + "screen", + "settings", + "switch", + "theme", + "toggle", + "tone", + "ui", + "user interface", + "view", + "visual", + "visual settings", + "water" + ], + "popularity": 11050 + }, + "INVERT_COLORS_OFF": { + "tags": [ + "accessibility", + "accessibility settings", + "appearance", + "circle", + "color", + "color palette", + "color scheme", + "colors", + "dark mode", + "disabled", + "display", + "drop", + "droplet", + "enabled", + "eye", + "high contrast", + "hue", + "inactive", + "invert", + "invert colors off", + "inverted", + "light mode", + "line", + "mode", + "off", + "offline", + "on", + "opacity", + "options", + "palette", + "preferences", + "settings", + "slash", + "switch", + "theme", + "toggle", + "tone", + "vision", + "visual impairment", + "water" + ], + "popularity": 1942 + }, + "IOS_SHARE": { + "tags": [ + "action", + "app", + "apple", + "arrow", + "box", + "button", + "communication", + "connect", + "content", + "distribute", + "export", + "forward", + "ios", + "link", + "menu", + "mobile", + "network", + "post", + "publish", + "rectangle", + "send", + "share", + "sharing", + "social", + "square", + "transfer", + "up", + "upload" + ], + "popularity": 29499 + }, + "IRON": { + "tags": [ + "appliance", + "cleaning", + "clothes", + "clothes iron", + "clothing", + "domestic", + "electric", + "electric iron", + "fabric", + "garment care", + "handle", + "heat", + "home appliance", + "home.", + "household appliance", + "housework", + "iron", + "ironing", + "laundry", + "machine", + "object", + "pressing", + "pressing iron", + "smooth", + "steam", + "steam iron", + "textile care", + "triangle", + "wrinkles" + ], + "popularity": 2254 + }, + "ISO": { + "tags": [ + "add", + "adjustment", + "bar", + "brightness", + "camera", + "controls", + "edit", + "editing", + "effect", + "exposure", + "graphic", + "image", + "indicator", + "iso", + "level", + "light", + "lines", + "minus", + "photo", + "photography", + "picture", + "plus", + "scale", + "sensor", + "settings", + "shutter", + "slider", + "speed", + "subtract", + "toggle", + "visual" + ], + "popularity": 2484 + }, + "JAVASCRIPT": { + "tags": [ + "alphabet", + "back end", + "brackets", + "character", + "code", + "coding", + "computer", + "css", + "develop", + "developer", + "development", + "engineer", + "engineering", + "font", + "front end", + "html", + "internet", + "javascript", + "js", + "language", + "letters", + "online", + "platform", + "programming", + "programming language", + "script", + "scripting language", + "software", + "symbol", + "tech", + "technology", + "technology symbol", + "text", + "type", + "web development" + ], + "popularity": 3671 + }, + "JOIN_FULL": { + "tags": [ + "attend", + "broadcast", + "call", + "circle", + "collaboration", + "combine", + "command", + "conference", + "connect", + "connection", + "full", + "group", + "invite", + "invite full", + "join", + "join meeting", + "left", + "link", + "live", + "meeting", + "meeting full", + "online", + "outer", + "overlap", + "participants", + "people", + "right", + "room", + "session", + "sql", + "start", + "start meeting", + "users", + "video", + "video call", + "video conference" + ], + "popularity": 3849 + }, + "JOIN_INNER": { + "tags": [ + "circle", + "combine", + "combine data", + "combine icon", + "command", + "connect", + "connect data", + "connection icon", + "data", + "data linking", + "data merge", + "data table", + "database", + "inner", + "inner join", + "intersection", + "join", + "join icon", + "join inner", + "link", + "link data", + "link icon", + "matching", + "merge", + "merge icon", + "overlap", + "relationship", + "sql", + "table join", + "two circles", + "union", + "union icon", + "values", + "venn diagram" + ], + "popularity": 3351 + }, + "JOIN_LEFT": { + "tags": [ + "access", + "arrow", + "branch", + "circle", + "combine", + "command", + "connect", + "connection", + "convergence", + "curve", + "direction", + "directionality", + "entry", + "flow", + "geometry", + "input", + "integration", + "join", + "join left", + "junction", + "left", + "line", + "link", + "matching", + "merge", + "node", + "overlap", + "path", + "point", + "route", + "segment", + "shape", + "sql", + "values", + "way" + ], + "popularity": 2351 + }, + "JOIN_RIGHT": { + "tags": [ + "align right", + "alignment", + "arrow", + "association", + "chain link", + "circle", + "combining", + "command", + "connect right", + "connecting", + "connection", + "data alignment", + "database join", + "direction", + "direction right", + "flow", + "forward arrow", + "integration", + "join", + "join right", + "joining", + "link", + "link right", + "matching", + "merge right", + "merging", + "overlap", + "pairing", + "process flow", + "relationship", + "right", + "right arrow", + "sql", + "table join", + "two links", + "values" + ], + "popularity": 2083 + }, + "KAYAKING": { + "tags": [ + "activity", + "adventure", + "athlete", + "athletic", + "boat", + "body", + "canoe", + "entertainment", + "excursion", + "exercise", + "fitness", + "hobby", + "human", + "kayak", + "kayaking", + "lake", + "leisure", + "line icon", + "outdoor", + "outline icon", + "paddle", + "paddling", + "people", + "person", + "rafting", + "recreation", + "river", + "row", + "social", + "sport", + "sports", + "summer", + "tour", + "transportation", + "travel", + "vacation", + "vehicle", + "water" + ], + "popularity": 3760 + }, + "KEBAB_DINING": { + "tags": [ + "actions", + "additional options", + "chef", + "choices", + "context menu", + "cooking", + "cuisine", + "cutlery", + "dining", + "dining options", + "dinner", + "eating", + "ellipsis", + "food", + "food choices", + "food menu", + "kebab", + "kitchen", + "meal", + "meat", + "menu", + "more", + "options", + "overflow menu", + "restaurant", + "restaurant menu", + "skewer", + "three dots", + "three points", + "utensils", + "vertical dots" + ], + "popularity": 1332 + }, + "KEY": { + "tags": [ + "access", + "access key", + "authentication", + "authorization", + "code", + "data", + "decryption key", + "digital", + "door", + "encryption", + "encryption key", + "entry", + "information", + "key", + "lock", + "login", + "padlock", + "password", + "permission", + "private", + "private access", + "private key", + "secret", + "secure", + "secure access", + "security", + "technology", + "unlock" + ], + "popularity": 24071 + }, + "KEY_OFF": { + "tags": [ + "access", + "barred", + "blocked", + "circle", + "closed", + "deactivated", + "disabled", + "door", + "enabled", + "entry", + "hole", + "inaccessible", + "inactive", + "key", + "lock", + "locked", + "object", + "off", + "offline", + "on", + "outline", + "password", + "private", + "restricted", + "rounded", + "secure", + "security", + "slash", + "square", + "unavailable", + "unlock" + ], + "popularity": 1568 + }, + "KEYBOARD": { + "tags": [ + "access", + "chat", + "code", + "communication", + "computer", + "control", + "data entry", + "device", + "device input", + "digital", + "edit", + "grid", + "hardware", + "input", + "keyboard", + "keypad", + "keys", + "letters", + "message", + "office", + "peripheral", + "programming", + "rectangle", + "search", + "software", + "squares", + "technology", + "text", + "text field", + "type", + "typing", + "virtual keyboard", + "writing" + ], + "popularity": 17175 + }, + "KEYBOARD_ALT": { + "tags": [ + "alphanumeric", + "buttons", + "chat", + "compose", + "computer", + "control", + "data entry", + "device", + "digital", + "edit", + "hardware", + "input", + "keyboard", + "keypad", + "keys", + "letters", + "message", + "office", + "on-screen", + "peripheral", + "rectangle", + "search", + "soft", + "software", + "technology", + "text", + "type", + "typing", + "virtual", + "workstation", + "write", + "writing" + ], + "popularity": 4202 + }, + "KEYBOARD_ARROW_DOWN": { + "tags": [ + "access", + "arrow", + "arrows", + "bottom", + "caret", + "chevron", + "collapse", + "control", + "direction", + "down", + "dropdown", + "expand", + "filter", + "hide", + "indicator", + "keyboard", + "menu", + "more", + "navigation", + "next", + "page", + "point", + "pointer", + "reveal", + "scroll", + "select", + "selector", + "show", + "sort", + "triangle", + "unfold", + "v-shape" + ], + "popularity": 73256 + }, + "KEYBOARD_ARROW_LEFT": { + "tags": [ + "angle", + "arrow", + "arrows", + "back", + "basic", + "button", + "chevron", + "control", + "direction", + "indicator", + "key", + "keyboard", + "left", + "list", + "menu", + "minimal", + "move", + "move left", + "navigate", + "navigation", + "page", + "point", + "pointer", + "previous", + "scroll", + "sideways", + "simple", + "triangle", + "ui control" + ], + "popularity": 19787 + }, + "KEYBOARD_ARROW_RIGHT": { + "tags": [ + "advance", + "angle", + "arrow", + "arrows", + "caret", + "carousel", + "chevron", + "continue", + "direction", + "expand", + "forward", + "go", + "greater than", + "indicator", + "item", + "keyboard", + "link", + "list", + "menu", + "more", + "move", + "navigate", + "navigation", + "next", + "open", + "pointer", + "proceed", + "prompt", + "right", + "select", + "slider" + ], + "popularity": 36529 + }, + "KEYBOARD_ARROW_UP": { + "tags": [ + "accordion", + "angle", + "arrow", + "arrows", + "ascend", + "caret", + "chevron", + "collapse", + "control", + "direction", + "dropdown", + "expand", + "expandable", + "hide", + "indicator", + "less", + "list", + "menu", + "move up", + "navigate", + "navigation", + "paginate", + "point", + "pointer", + "previous", + "return to top", + "scroll", + "scroll up", + "show", + "sort", + "top", + "triangle", + "up" + ], + "popularity": 22388 + }, + "KEYBOARD_BACKSPACE": { + "tags": [ + "action", + "arrow", + "back", + "backspace", + "caret", + "clear", + "close", + "control", + "delete", + "direction", + "editor", + "erase", + "escape", + "exit", + "go back", + "input", + "keyboard", + "left", + "left arrow", + "line", + "navigation", + "point", + "previous", + "remove", + "return", + "shape", + "symbol", + "text", + "undo" + ], + "popularity": 22991 + }, + "KEYBOARD_CAPSLOCK": { + "tags": [ + "arrow", + "button", + "capslock", + "computer", + "control", + "direction", + "function", + "input", + "key", + "keyboard", + "letters", + "line", + "pointing", + "shift", + "text", + "triangle", + "typing", + "up", + "uppercase", + "writing" + ], + "popularity": 2137 + }, + "KEYBOARD_COMMAND_KEY": { + "tags": [ + "action", + "apple", + "button", + "command", + "command key", + "computer key", + "computing", + "control", + "device", + "digital", + "function", + "glyph", + "hardware", + "input", + "interface element", + "key", + "keyboard", + "mac", + "macos", + "operating system", + "option", + "outline", + "shortcut", + "special key", + "stroke", + "symbol", + "technology" + ], + "popularity": 1840 + }, + "KEYBOARD_CONTROL_KEY": { + "tags": [ + "arrow", + "code", + "command", + "computer", + "control", + "control key", + "direction", + "function key", + "go up", + "input", + "key", + "keyboard", + "move up", + "navigation", + "programming", + "scroll up", + "symbol", + "text", + "text input", + "top", + "typing", + "up arrow" + ], + "popularity": 1060 + }, + "KEYBOARD_DOUBLE_ARROW_DOWN": { + "tags": [ + "advance", + "angle", + "arrow", + "arrows", + "bottom", + "chevron", + "continue", + "control", + "descend", + "direction", + "directional", + "dive", + "double", + "down", + "drop", + "end", + "fall", + "forward", + "indicator", + "keyboard", + "lower", + "move", + "multiple", + "navigation", + "next", + "page", + "point", + "pointer", + "scroll", + "sharp", + "submerge", + "triangle", + "v-shape" + ], + "popularity": 12176 + }, + "KEYBOARD_DOUBLE_ARROW_LEFT": { + "tags": [ + "angle left", + "arrow", + "arrow left", + "arrows", + "back", + "back button", + "chevron left", + "direction", + "direction left", + "double", + "double arrow", + "fast backward", + "fast reverse", + "go back", + "history", + "left", + "left arrow", + "media control", + "move left", + "multiple", + "multiple arrows", + "navigation", + "playback", + "pointing left", + "previous", + "return", + "reverse", + "rewind", + "rewind button", + "skip back", + "step back", + "two arrows" + ], + "popularity": 14397 + }, + "KEYBOARD_DOUBLE_ARROW_RIGHT": { + "tags": [ + "accelerate", + "advance", + "arrow", + "arrows", + "chevron", + "chevrons", + "control", + "direction", + "double", + "double arrow", + "double chevron", + "fast forward", + "forward", + "go", + "input", + "key", + "keyboard", + "move", + "movement", + "multiple", + "navigation", + "next", + "next page", + "progress", + "right", + "right arrow", + "rightward", + "skip", + "step forward", + "symbol" + ], + "popularity": 21803 + }, + "KEYBOARD_DOUBLE_ARROW_UP": { + "tags": [ + "arrow", + "arrow up", + "arrows", + "caret", + "chevron", + "chevrons", + "collapse", + "direction", + "direction up", + "double", + "double arrow", + "double caret", + "double up arrow", + "expand", + "fast forward", + "fast up", + "go up", + "indicator", + "jump up", + "keyboard", + "keyboard icon", + "maximize", + "minimize", + "move up", + "multiple", + "navigate up", + "navigation", + "page up", + "pointer", + "scroll up", + "skip up", + "to top", + "top", + "up", + "up arrow", + "upward" + ], + "popularity": 9203 + }, + "KEYBOARD_HIDE": { + "tags": [ + "arrow", + "buttons", + "chevron", + "close", + "collapse", + "computer", + "conceal", + "control", + "descend", + "device", + "direction", + "disappear", + "dismiss", + "down", + "exit keyboard", + "form", + "hardware", + "hide", + "input", + "keyboard", + "keypad", + "keys", + "message", + "minimize", + "mobile", + "put away", + "qwerty", + "remove", + "soft keyboard", + "text", + "text entry", + "toggle", + "typing", + "virtual keyboard" + ], + "popularity": 2929 + }, + "KEYBOARD_OPTION_KEY": { + "tags": [ + "accessibility", + "alt", + "alt key", + "alternate", + "character", + "command", + "computer", + "configuration", + "control", + "customization", + "device", + "flat", + "function", + "input", + "key", + "keyboard", + "line", + "minimal", + "modifier key", + "option", + "outline", + "rectangle", + "settings", + "special key", + "square", + "stroke", + "symbol", + "technology", + "text", + "typing" + ], + "popularity": 737 + }, + "KEYBOARD_RETURN": { + "tags": [ + "angle", + "arrow", + "back", + "bend", + "break line", + "carriage return", + "coding", + "command", + "computer key", + "curved arrow", + "directional arrow", + "down arrow", + "enter key", + "function", + "glyph", + "icon", + "input", + "keyboard", + "keyboard return", + "keyboard symbol", + "left", + "left arrow", + "newline", + "programming", + "return", + "return key", + "shape", + "symbol", + "text editing", + "text entry", + "text formatting", + "typography" + ], + "popularity": 21433 + }, + "KEYBOARD_TAB": { + "tags": [ + "arrow", + "character", + "computer", + "control", + "document", + "editing", + "element", + "glyph", + "indent", + "input", + "interface", + "jump", + "key", + "keyboard", + "keyboard tab", + "left", + "move", + "navigation", + "next", + "right", + "right arrow", + "space", + "spacing", + "symbol", + "tab", + "tab key", + "technology", + "text", + "word processing", + "writing" + ], + "popularity": 5944 + }, + "KEYBOARD_VOICE": { + "tags": [ + "audio", + "audio button", + "audio capture", + "audio input", + "audio recording", + "chat", + "communication", + "dictate", + "dictation", + "hear", + "hearing", + "input", + "keyboard", + "messaging", + "mic", + "mic button", + "microphone", + "microphone button", + "multimedia", + "noise", + "record", + "recorder", + "recording", + "recording button", + "sound", + "sound capture", + "sound input", + "sound recording", + "speak", + "speaker", + "speech", + "talk", + "voice", + "voice button", + "voice command", + "voice input" + ], + "popularity": 10682 + }, + "KING_BED": { + "tags": [ + "accommodation", + "apartment", + "bed", + "bedroom", + "building", + "comfort", + "domestic", + "double", + "double bed", + "furniture", + "home", + "horizontal", + "hotel", + "house", + "housing", + "interior", + "king", + "king bed", + "king size", + "large bed", + "lodging", + "master bedroom", + "night", + "pillows", + "property", + "queen", + "real estate", + "rectangle", + "relax", + "rest", + "room", + "sleep" + ], + "popularity": 8597 + }, + "KITCHEN": { + "tags": [ + "appliance", + "appliances", + "building", + "building structure", + "cabinets", + "cold", + "cooking", + "cooking area", + "cooking space", + "culinary", + "dining", + "domestic", + "eat", + "food", + "food preparation", + "fridge", + "furniture", + "home", + "home appliance", + "house", + "ice", + "interior", + "kitchen", + "line art", + "outline", + "oven", + "places", + "rectangle", + "refrigerator", + "residential", + "room", + "shape", + "simple", + "storage", + "stove" + ], + "popularity": 9273 + }, + "KITESURFING": { + "tags": [ + "action", + "activity", + "adventure", + "athlete", + "athletic", + "beach", + "board", + "body", + "dynamic", + "entertainment", + "exercise", + "extreme sport", + "figure", + "hobby", + "human", + "kite", + "kiteboarding", + "kitesurfing", + "leisure", + "ocean", + "outdoor", + "people", + "person", + "recreation", + "sea", + "silhouette", + "social", + "sport", + "sports", + "surf", + "surfing", + "travel", + "vacation", + "water", + "water sport", + "waves", + "wind" + ], + "popularity": 2428 + }, + "LABEL": { + "tags": [ + "angled shape", + "badge", + "bookmark", + "category", + "classification", + "corner", + "designation", + "detail", + "details", + "emblem", + "favorite", + "geometric", + "highlight", + "identification", + "indent", + "indicator", + "information", + "label", + "library", + "mail", + "marker", + "name", + "organize", + "outline", + "pointed shape", + "polygon", + "price tag", + "remember", + "save", + "shape", + "stamp", + "sticker", + "tag", + "title" + ], + "popularity": 35851 + }, + "LABEL_IMPORTANT": { + "tags": [ + "angled", + "bookmark", + "categorization", + "categorize", + "chevron", + "corner", + "data", + "favorite", + "filled", + "filter", + "flag", + "geometry", + "highlight", + "identifier", + "important", + "indent", + "indication", + "information.", + "label", + "library", + "mail", + "mark", + "marker", + "note", + "organization", + "organize", + "outline", + "point", + "record", + "remember", + "right", + "save", + "shape", + "sharp", + "sort", + "stamp", + "sticker", + "tag", + "wing" + ], + "popularity": 16777 + }, + "LABEL_OFF": { + "tags": [ + "angles", + "badge off", + "deactivate label", + "disable", + "disable label", + "disabled", + "enabled", + "favorite", + "flag off", + "geometric", + "hide label", + "identifier off", + "indent", + "indicator off", + "label", + "label off", + "library", + "mail", + "marker off", + "minimal", + "modern", + "name tag off", + "off", + "on", + "outline", + "point", + "price tag off", + "remember", + "remove label", + "save", + "sharp", + "slash", + "stamp", + "sticker", + "sticker off", + "tag", + "tag off", + "toggle off", + "unlabel", + "untag", + "wing" + ], + "popularity": 2732 + }, + "LAN": { + "tags": [ + "access", + "business", + "communication", + "communications", + "computer", + "computers", + "connected", + "connection", + "connections", + "data", + "desktop", + "device", + "devices", + "document", + "documents", + "file", + "files", + "folder", + "folders", + "internet", + "lan", + "local area network", + "network", + "networking", + "office", + "server", + "servers", + "service", + "sharing", + "transfer", + "work" + ], + "popularity": 6539 + }, + "LANDSCAPE": { + "tags": [ + "chart", + "contour", + "data", + "diagram", + "elevation", + "environment", + "geography", + "graphic", + "hill", + "hills", + "image", + "land", + "landscape", + "location", + "map", + "mountain", + "mountains", + "natural", + "nature", + "outdoor", + "peak", + "photo", + "photography", + "picture", + "region", + "scenery", + "terrain", + "travel", + "view" + ], + "popularity": 10161 + }, + "LANDSLIDE": { + "tags": [ + "accident", + "alert", + "caution", + "collapse", + "crisis", + "danger", + "disaster", + "earth", + "earth movement", + "emergency", + "falling rocks", + "geological", + "geology", + "ground", + "hazard", + "landslide", + "mountain", + "natural", + "natural disaster", + "nature", + "notification", + "outdoor", + "rain", + "risk", + "road", + "rockfall", + "sign", + "slope", + "storm", + "symbol", + "terrain", + "travel", + "unstable", + "warning", + "weather" + ], + "popularity": 1002 + }, + "LANGUAGE": { + "tags": [ + "announcement", + "bubble", + "caption", + "chat", + "communicate", + "communication", + "dialogue", + "discussion", + "globe", + "headline", + "internet", + "language", + "language switcher", + "menu", + "multiple languages", + "news", + "options", + "planet", + "preferences", + "settings", + "speak", + "speech", + "talk", + "talking", + "text", + "text balloon", + "thought bubble", + "translate", + "translation", + "typography", + "website", + "words", + "world", + "www" + ], + "popularity": 190097 + }, + "LAPTOP": { + "tags": [ + "accessory", + "android", + "chrome", + "communication", + "computer", + "computing", + "data", + "desk", + "desktop", + "device", + "digital", + "display", + "electronic", + "electronic device", + "gadget", + "hardware", + "internet", + "ios", + "laptop", + "mac", + "monitor", + "network", + "notebook", + "office", + "os", + "pc", + "peripheral", + "personal computer", + "screen", + "server", + "system", + "technology", + "technology device", + "web", + "windows", + "work", + "workstation" + ], + "popularity": 20483 + }, + "LAPTOP_CHROMEBOOK": { + "tags": [ + "android", + "angled", + "chrome", + "chromebook", + "computer", + "computing", + "device", + "display", + "electronic", + "flat", + "graphic", + "hardware", + "horizontal", + "icon", + "internet", + "ios", + "keyboard", + "laptop", + "mac chromebook", + "minimal", + "mobile", + "monitor", + "os", + "outline", + "personal", + "portable", + "rectangle", + "screen", + "symbol", + "technology", + "thin", + "vector", + "web", + "window", + "work" + ], + "popularity": 5757 + }, + "LAPTOP_MAC": { + "tags": [ + "android", + "chrome", + "computer", + "computing", + "connection", + "data", + "desktop", + "device", + "digital", + "display", + "electronic", + "electronics", + "gadget", + "hardware", + "internet", + "ios", + "keyboard", + "laptop", + "mac", + "macbook", + "mobile", + "monitor", + "network", + "office", + "os", + "portable", + "presentation", + "rectangle", + "remote", + "screen", + "shape", + "technology", + "web", + "window", + "work", + "workstation" + ], + "popularity": 7858 + }, + "LAPTOP_WINDOWS": { + "tags": [ + "android", + "angled", + "chrome", + "computer", + "computing", + "device", + "digital", + "display", + "education", + "electronic", + "hardware", + "ios", + "laptop", + "mac", + "monitor", + "notebook", + "office", + "open", + "os", + "pc", + "personal computer", + "portable", + "rectangle", + "screen", + "technology", + "technology device", + "web", + "window", + "windows", + "work" + ], + "popularity": 3586 + }, + "LAST_PAGE": { + "tags": [ + "advance", + "app", + "application", + "arrow", + "boundary", + "chevron", + "components", + "double arrow", + "double lines", + "end", + "fast forward", + "final", + "finish", + "forward", + "interface", + "last", + "last page", + "limit", + "line", + "media control", + "move", + "navigation", + "next", + "page", + "rewind", + "right", + "right arrow", + "screen", + "seek", + "shape", + "site", + "skip", + "skip forward", + "ui", + "ux", + "vertical lines", + "web", + "website" + ], + "popularity": 14699 + }, + "LAUNCH": { + "tags": [ + "access", + "action", + "app", + "application", + "arrow", + "box", + "button", + "components", + "depart", + "destination", + "exit", + "expand", + "external", + "follow", + "forward", + "go", + "interface", + "launch", + "link", + "navigate", + "new", + "open", + "out", + "page", + "pop out", + "portal", + "redirect", + "reference", + "screen", + "share", + "site", + "square", + "tab", + "ui", + "url", + "ux", + "web", + "website", + "window" + ], + "popularity": 45428 + }, + "LAYERS": { + "tags": [ + "arrange", + "composition", + "content", + "depth", + "disabled", + "display", + "document", + "enabled", + "file", + "group", + "hierarchy", + "interaction", + "layers", + "levels", + "manage", + "maps", + "multiple", + "off", + "on", + "order", + "organize", + "overlap", + "overlay", + "pages", + "panels", + "planes", + "sections", + "segments", + "sheets", + "slash", + "stack", + "structure", + "view" + ], + "popularity": 23851 + }, + "LAYERS_CLEAR": { + "tags": [ + "3d", + "arrange", + "cancel", + "clear", + "delete", + "delete layers", + "depth", + "disabled", + "dismiss", + "documents", + "empty", + "enabled", + "erase", + "files", + "hierarchy", + "interaction", + "layers", + "layers clear", + "levels", + "maps", + "none", + "off", + "offset", + "on", + "order", + "organization", + "overlapping", + "overlay", + "pages", + "papers", + "perspective", + "reject", + "remove layers", + "sheets", + "slash", + "stack", + "structure", + "three dimensional", + "wipe", + "zero" + ], + "popularity": 4473 + }, + "LEADERBOARD": { + "tags": [ + "achievement", + "achievements", + "analytics", + "bar", + "bar chart", + "bars", + "best", + "chart", + "columns", + "competition", + "competitive", + "data", + "diagram", + "graph", + "high score", + "highscores", + "infographic", + "leaderboard", + "levels", + "list", + "measure", + "medal", + "metrics", + "podium", + "points", + "progress", + "rank", + "ranking", + "score", + "scores", + "statistics", + "stats", + "tiers", + "top", + "tracking", + "winner", + "winners" + ], + "popularity": 43497 + }, + "LEAK_ADD": { + "tags": [ + "add", + "assembly", + "attach", + "build", + "connect", + "connection", + "construct", + "construction", + "creation", + "data", + "drip", + "droplet", + "expand", + "flow", + "form", + "include", + "increase", + "insert", + "issue", + "join", + "leak", + "link", + "liquid", + "maintenance", + "network", + "new", + "pipe", + "plumbing", + "plus", + "problem", + "repair", + "service", + "signals", + "sound", + "stream", + "synce", + "water", + "wireless" + ], + "popularity": 4151 + }, + "LEAK_REMOVE": { + "tags": [ + "anti leak", + "blocked", + "cancel", + "connection", + "data", + "delete", + "disabled", + "drop", + "droplet", + "eliminate", + "enabled", + "fix leak", + "forbidden", + "leak", + "leak detection", + "leak prevention", + "link", + "liquid", + "network", + "no leak", + "no pipe leak", + "no plumbing issue", + "no water leak", + "off", + "offline", + "on", + "pipe", + "plug leak", + "plumbing repair", + "prohibited", + "remove", + "remove leak", + "seal leak", + "service", + "signals", + "slash", + "sound", + "stop leak", + "synce", + "water", + "water damage prevention", + "wireless" + ], + "popularity": 1360 + }, + "LEGEND_TOGGLE": { + "tags": [ + "analytics", + "box", + "chart", + "collapse", + "control", + "data", + "description", + "diagram", + "display", + "expand", + "explanation", + "filter", + "graph", + "hide", + "infographic", + "information", + "key", + "labels", + "layers", + "legend", + "lines", + "map", + "measure", + "menu", + "metrics", + "monitoring", + "options", + "rectangular", + "settings", + "show", + "stackdriver", + "statistics", + "switch", + "text", + "three lines", + "toggle", + "tracking", + "view", + "visualization" + ], + "popularity": 6531 + }, + "LENS": { + "tags": [ + "active", + "angle", + "badge", + "basic", + "centralized", + "circle", + "complete", + "disc", + "dot", + "element", + "eye", + "filled", + "fish", + "focused", + "full", + "geometry", + "image", + "indicator", + "isolated", + "lens", + "lone", + "marker", + "minimal", + "moon", + "orb", + "panorama", + "perfect", + "photo", + "photography", + "picture", + "point", + "round", + "selected", + "shape", + "simple", + "single", + "solid", + "sphere", + "status", + "unified", + "whole", + "wide" + ], + "popularity": 9727 + }, + "LENS_BLUR": { + "tags": [ + "abstract", + "aperture", + "artistic effect", + "blur", + "bokeh", + "camera", + "camera lens", + "circle", + "circular blur", + "circular shape", + "depth of field", + "dim", + "dot", + "effect", + "filter", + "focus", + "foggy", + "fuzzy", + "image", + "image adjustment", + "image effect", + "lens", + "lens blur", + "lens effect", + "optical effect", + "out of focus", + "photo", + "photo editing", + "photo filter", + "photography", + "photography tool", + "radiating lines", + "radiating pattern", + "soft edges", + "soft focus", + "soften", + "unfocused", + "visual effect", + "visual filter" + ], + "popularity": 4678 + }, + "LIBRARY_ADD": { + "tags": [ + "+", + "add", + "archive", + "book", + "catalog", + "collection", + "content", + "create", + "data", + "document", + "entry", + "file", + "index", + "insert", + "item", + "layers", + "library", + "list", + "media", + "multiple", + "music", + "new", + "organize", + "page", + "playlist", + "plus", + "queue", + "record", + "register", + "save", + "stacked", + "store", + "symbol", + "video" + ], + "popularity": 16201 + }, + "LIBRARY_ADD_CHECK": { + "tags": [ + "action", + "add", + "approve", + "archive", + "bookmark", + "box", + "button", + "check", + "collection", + "complete", + "confirmed", + "control", + "corners", + "document", + "done", + "feedback", + "file", + "folder", + "inclusion", + "layers", + "library", + "line", + "list", + "mark", + "multiple", + "music", + "new item", + "ok", + "plus", + "saved", + "select", + "square", + "stacked", + "success", + "symbol", + "task", + "tick", + "ui", + "validate", + "verified", + "video", + "yes" + ], + "popularity": 9172 + }, + "LIBRARY_BOOKS": { + "tags": [ + "academy", + "add", + "album", + "archives", + "audio", + "bibliography", + "book", + "books", + "bookstore", + "catalog", + "collection", + "content", + "database", + "directory", + "documents", + "education", + "files", + "index", + "information", + "knowledge", + "learning", + "library", + "list", + "literature", + "publications", + "read", + "reading", + "records", + "research", + "resources", + "stacked", + "stacked books", + "study" + ], + "popularity": 34703 + }, + "LIBRARY_MUSIC": { + "tags": [ + "add", + "album", + "archive", + "audio", + "audio collection", + "audio files", + "audio library", + "collection", + "documents", + "files", + "folder", + "library", + "media", + "media library", + "multimedia", + "music", + "music archive", + "music collection", + "music library", + "music player", + "music symbol", + "musical notes", + "notes", + "organize", + "playlist", + "rectangle", + "song", + "sound", + "sounds", + "storage", + "tracks" + ], + "popularity": 10823 + }, + "LIGHT": { + "tags": [ + "abstract", + "adjust", + "basic", + "bright", + "brightness", + "bulb", + "ceiling", + "concept", + "control", + "electricity", + "energy", + "glow", + "hanging", + "idea", + "illumination", + "indicator", + "inside", + "interior", + "lamp", + "light", + "lighting", + "minimal", + "modern", + "off", + "on", + "outline", + "pendent", + "power", + "preference", + "room", + "setting", + "shine", + "sign", + "simple", + "switch", + "symbol", + "toggle" + ], + "popularity": 6451 + }, + "LIGHT_MODE": { + "tags": [ + "adjustment", + "appearance", + "application", + "bright", + "brightness", + "celestial body", + "circle", + "clear", + "day", + "daytime", + "device", + "display", + "illumination", + "interface", + "light", + "light mode", + "lighting", + "lines", + "mode", + "morning", + "option", + "preference", + "radial", + "setting", + "sky", + "star", + "sun", + "sun rays", + "sunny", + "switch", + "theme", + "toggle", + "visibility" + ], + "popularity": 59499 + }, + "LIGHTBULB": { + "tags": [ + "alert", + "announcement", + "bright", + "bulb", + "concept", + "creativity", + "disabled", + "education", + "empty", + "glow", + "hint", + "idea", + "inactive", + "incandescent", + "info", + "information", + "innovation", + "inspiration", + "invention", + "knowledge", + "learning", + "led", + "light", + "lightbulb", + "not lit", + "outline", + "smart", + "solution", + "suggestion", + "thinking", + "thought", + "tip", + "turned off", + "unlit" + ], + "popularity": 98284 + }, + "LIGHTBULB_CIRCLE": { + "tags": [ + "alert", + "announcement", + "bright", + "bulb", + "button", + "circle", + "circular", + "contained", + "control", + "creativity", + "discovery", + "graphic", + "hint", + "icon", + "idea", + "incandescent", + "info", + "information", + "inspiration", + "knowledge", + "learning", + "led", + "light", + "lightbulb", + "outline", + "shape", + "smart", + "solution", + "suggestion", + "symbol", + "thinking", + "thought", + "tip", + "ui", + "ui element.", + "understanding" + ], + "popularity": 3868 + }, + "LINE_AXIS": { + "tags": [ + "accuracy", + "analytics", + "axis", + "chart", + "coordinate system", + "coordinates", + "dash", + "data", + "diagram", + "engineering", + "graph", + "grid", + "gridline", + "horizontal", + "line", + "math", + "mathematics", + "measurement", + "plot", + "plotting", + "precision", + "quantitative", + "quantitative data", + "ruler", + "scale", + "science", + "statistics", + "stroke", + "technical", + "vertical", + "visual data", + "visualization", + "x axis", + "y axis" + ], + "popularity": 1595 + }, + "LINE_STYLE": { + "tags": [ + "adjust", + "alignment", + "bullet points", + "content", + "customize", + "dash", + "document", + "document editing", + "dotted", + "editor", + "formatting", + "horizontal lines", + "indent", + "layout", + "line", + "list", + "menu", + "modify", + "numbering", + "options", + "paragraph", + "paragraph style", + "rule", + "settings", + "spacing", + "structure", + "style", + "text", + "text style", + "three lines", + "typing", + "word processing", + "writing" + ], + "popularity": 3615 + }, + "LINE_WEIGHT": { + "tags": [ + "adjust", + "bars", + "content", + "different sizes", + "document", + "editing", + "editor", + "file", + "formatting", + "height", + "horizontal lines", + "line", + "line weight", + "lines", + "measure", + "modify", + "paragraph lines", + "paragraph rules", + "rules", + "size", + "spacing", + "stacked lines", + "stroke", + "style", + "text lines", + "thickness", + "three lines", + "typography", + "varying thickness", + "weight", + "width", + "writing" + ], + "popularity": 5111 + }, + "LINEAR_SCALE": { + "tags": [ + "adjust", + "adjustment", + "app", + "application", + "calibrate", + "components", + "configuration", + "control", + "degree", + "design", + "dots", + "extent", + "gauge", + "horizontal", + "horizontal line", + "indicator", + "interface", + "layout", + "level", + "line", + "linear", + "linear scale", + "markers", + "measure", + "measurement", + "menu", + "options", + "points", + "progress", + "range", + "ruler", + "scale", + "screen", + "set", + "settings", + "site", + "slider", + "ticks", + "ui", + "ux", + "value", + "web", + "website", + "window" + ], + "popularity": 8775 + }, + "LINK": { + "tags": [ + "anchor", + "arrow", + "attach", + "attachment", + "chain", + "circle", + "circular", + "clip", + "connect", + "connection", + "direction", + "external", + "global", + "globe", + "hyperlink", + "international", + "internet", + "join", + "line", + "link", + "linked", + "links", + "multimedia", + "navigation", + "network", + "point", + "reference", + "round", + "sphere", + "url", + "web", + "website", + "world", + "www" + ], + "popularity": 83987 + }, + "LINK_OFF": { + "tags": [ + "attached", + "broken chain", + "broken connection", + "broken hyperlink", + "broken link", + "broken link icon", + "chain", + "clip", + "connection", + "connection broken", + "connection off", + "disable hyperlink", + "disable link", + "disabled", + "disconnect icon", + "disconnect web link", + "disconnected", + "enabled", + "hyperlink", + "link", + "link broken", + "link disabled", + "link icon", + "link off", + "link removed", + "linked", + "links", + "multimedia", + "off", + "on", + "remove hyperlink", + "remove link", + "remove web link", + "slash", + "unlink", + "url", + "web address", + "web icon", + "web link", + "website" + ], + "popularity": 15648 + }, + "LINKED_CAMERA": { + "tags": [ + "attached", + "camera", + "capture", + "chain", + "connect", + "connected", + "connection", + "device", + "digital", + "equipment", + "image", + "internet", + "lens", + "link", + "linked", + "linked camera", + "linked media", + "media", + "multimedia", + "multimedia connection", + "network", + "photo", + "photography", + "photography equipment", + "picture", + "recording", + "share", + "sharing", + "shoot", + "signal", + "signals", + "snapshot", + "social media", + "sync", + "visual", + "wireless" + ], + "popularity": 2743 + }, + "LIQUOR": { + "tags": [ + "alcohol", + "app", + "bar", + "beverage", + "bottle", + "celebration", + "cheers", + "club", + "cocktail", + "container", + "drink", + "entertainment", + "food", + "glass", + "graphic", + "icon", + "leisure", + "liquid", + "liquor", + "menu", + "nightlife", + "party", + "pour", + "pub", + "restaurant", + "spirits", + "stemware", + "store", + "symbol", + "toast", + "ui", + "ux", + "web", + "wine" + ], + "popularity": 9018 + }, + "LIST": { + "tags": [ + "agenda", + "bullet points", + "bulleted list", + "catalog", + "checklist", + "content list", + "directory", + "enumeration", + "expandable menu", + "file", + "format", + "hamburger", + "index", + "itemize", + "items", + "list", + "menu", + "navigation menu", + "options", + "order", + "organized list", + "sequence", + "stacked lines", + "steps", + "table of contents", + "task list", + "three lines", + "to-do list", + "vertical lines" + ], + "popularity": 141853 + }, + "LIST_ALT": { + "tags": [ + "agreement", + "alt", + "application", + "apply", + "archive", + "archive file", + "box", + "checklist", + "contained", + "contract", + "data entry", + "document", + "document archive", + "file", + "form", + "format", + "forms", + "input", + "lines", + "list", + "note", + "notes", + "order", + "outline", + "paper", + "paper forms", + "questionnaire", + "record", + "register", + "registration", + "reorder", + "report", + "sign up", + "signup", + "stacked", + "survey", + "text", + "title" + ], + "popularity": 53885 + }, + "LIVE_HELP": { + "tags": [ + "?", + "advice", + "aid", + "answer", + "assistance", + "bubble", + "chat", + "comment", + "communicate", + "communication", + "contact", + "conversation", + "customer service", + "dialog", + "faq", + "guidance", + "guide", + "help", + "info", + "information", + "instant", + "interaction", + "live", + "message", + "problem", + "punctuation", + "query", + "question", + "question mark", + "quick help", + "real-time", + "recent", + "restore", + "solution", + "speech", + "speech bubble", + "support", + "symbol", + "talk", + "troubleshooting" + ], + "popularity": 18728 + }, + "LIVE_TV": { + "tags": [ + "android", + "antenna", + "antennas hardware", + "broadcast", + "broadcasting", + "channel", + "chrome", + "content", + "desktop", + "device", + "display", + "electronic", + "entertainment", + "film", + "ios", + "live", + "live tv", + "mac", + "media", + "monitor", + "movie", + "on demand", + "ondemand video", + "os", + "play", + "playback", + "rectangle", + "screen", + "show", + "signal", + "stream", + "streaming", + "technology", + "television", + "tv", + "video", + "watch", + "web", + "window" + ], + "popularity": 19419 + }, + "LIVING": { + "tags": [ + "account", + "account icon", + "avatar", + "basic", + "bust", + "chair", + "comfort", + "couch", + "decoration", + "figure", + "furniture", + "generic", + "head", + "home", + "house", + "human", + "identity", + "individual", + "living", + "living being", + "lounging", + "loveseat", + "minimal", + "outline", + "person", + "person icon", + "placeholder", + "profile", + "profile icon", + "representation", + "room", + "seat", + "seating", + "shape", + "shoulders", + "silhouette", + "simple", + "sofa", + "user", + "user icon" + ], + "popularity": 3390 + }, + "LOCAL_ACTIVITY": { + "tags": [ + "access", + "activity", + "admission", + "attendance", + "cinema", + "coupon", + "cutout", + "entertainment", + "entertainment pass", + "entry", + "event", + "event pass", + "event ticket", + "local", + "movie", + "movie ticket", + "pass", + "perforation", + "play", + "rectangular", + "shape", + "show", + "star", + "stub", + "tear-off", + "theater", + "things", + "ticket", + "ticket stub", + "voucher" + ], + "popularity": 18062 + }, + "LOCAL_AIRPORT": { + "tags": [ + "active", + "air", + "air travel", + "aircraft", + "airplane", + "airplane icon", + "airplane mode", + "airport", + "communication off", + "disable connectivity", + "disable wireless", + "enabled", + "flight", + "flight mode", + "flying", + "local airport", + "network off", + "on", + "plane", + "signal off", + "transport", + "transportation", + "travel", + "travel mode", + "trip", + "turn off radio", + "vehicle" + ], + "popularity": 8395 + }, + "LOCAL_ATM": { + "tags": [ + "atm", + "automated teller machine", + "bank", + "banking", + "bill", + "brick and mortar", + "building", + "card", + "cart", + "cash", + "cash machine", + "coin", + "commerce", + "credit", + "currency", + "debit", + "deposit", + "dollars", + "establishment", + "finance", + "financial", + "find", + "local", + "locate", + "location", + "machine", + "money", + "navigate", + "nearby", + "online", + "pay", + "payment", + "point of interest", + "retail", + "service", + "shopping", + "structure", + "symbol", + "transaction", + "withdrawal" + ], + "popularity": 18538 + }, + "LOCAL_BAR": { + "tags": [ + "alcohol", + "bar", + "beer", + "beverage", + "bottle", + "celebrate", + "cheers", + "club", + "cocktail", + "cocktails", + "dining", + "drink", + "entertainment", + "establishment", + "food", + "food and drink", + "glass", + "going out", + "happy hour", + "hospitality", + "leisure", + "liquor", + "local", + "location", + "nightlife", + "party", + "place", + "pub", + "relax", + "restaurant", + "social", + "spirits", + "stemware", + "unwind", + "wine" + ], + "popularity": 10155 + }, + "LOCAL_CAFE": { + "tags": [ + "beverage", + "bottle", + "break", + "breakfast", + "cafe", + "caffeine", + "ceramic", + "coffee", + "cup", + "diner", + "dining", + "drink", + "eatery", + "food", + "handle", + "hot drink", + "kitchen", + "local", + "morning", + "mug", + "order", + "refreshment", + "relax", + "restaurant", + "service", + "shop", + "steam", + "store", + "tea", + "warm" + ], + "popularity": 17303 + }, + "LOCAL_CAR_WASH": { + "tags": [ + "auto", + "automobile", + "brush", + "bubble", + "business", + "car", + "car wash", + "cars", + "clean", + "cleaning", + "detail", + "detailing", + "directions", + "hose", + "local", + "location", + "map", + "maps", + "navigation", + "place", + "point of interest", + "service", + "service station", + "shine", + "soap", + "sprayer", + "square", + "suds", + "transportation", + "travel", + "vehicle", + "vehicle cleaning", + "wash", + "water", + "window" + ], + "popularity": 2560 + }, + "LOCAL_CONVENIENCE_STORE": { + "tags": [ + "--", + "24", + "awning", + "bill", + "building", + "business", + "buying", + "card", + "cash", + "coin", + "commerce", + "company", + "convenience", + "convenience store", + "corner store", + "credit", + "currency", + "destination", + "dollars", + "door", + "economic", + "entrance", + "facade", + "grocery", + "local", + "location", + "map", + "maps", + "market", + "money", + "navigation", + "neighborhood", + "new", + "online", + "pay", + "payment", + "plus", + "point of interest", + "retail", + "selling", + "shop", + "shopping", + "signage", + "small business", + "store", + "storefront", + "street", + "symbol", + "transaction", + "window" + ], + "popularity": 4146 + }, + "LOCAL_DINING": { + "tags": [ + "bistro", + "breakfast", + "cafe", + "catering", + "cuisine", + "cutlery", + "dining", + "dining experience", + "dining out", + "dinner", + "dish", + "eat", + "eatery", + "eating utensils", + "food", + "food and drink", + "food service", + "fork", + "gastronomy", + "knife", + "local", + "lunch", + "meal", + "menu", + "plate", + "restaurant", + "restaurant finder", + "setting", + "silverware", + "spoon", + "table setting" + ], + "popularity": 7947 + }, + "LOCAL_DRINK": { + "tags": [ + "alcohol", + "bar", + "beverage", + "cafe", + "catering", + "cheers", + "coffee", + "cold drink", + "cup", + "dining", + "drink", + "drink location", + "drink spot", + "drop", + "droplet", + "food", + "glass", + "hot drink", + "hydration", + "juice", + "liquid", + "local", + "mug", + "park", + "refreshment", + "restaurant", + "service", + "soda", + "tea", + "toast", + "vessel", + "water" + ], + "popularity": 7456 + }, + "LOCAL_FIRE_DEPARTMENT": { + "tags": [ + "911", + "alert", + "blaze", + "burning", + "climate", + "danger", + "department", + "discovery", + "emergency", + "explore", + "fire", + "fire department", + "fire icon", + "firefighter", + "flame", + "flame icon", + "heat", + "home", + "hot", + "hot topics", + "ignition", + "inferno", + "local", + "nest", + "news", + "popular", + "social media", + "spark", + "thermostat", + "top videos", + "trending", + "trending topics", + "trending videos", + "video", + "viral", + "warning", + "youtube" + ], + "popularity": 43933 + }, + "LOCAL_FLORIST": { + "tags": [ + "beauty", + "bloom", + "blooming", + "blossom", + "botany", + "decorative", + "ecological", + "environment", + "flora", + "floral", + "florist", + "flourish", + "flower", + "fresh", + "garden", + "growing", + "growth", + "leaf", + "leaves", + "local", + "natural", + "nature", + "organic", + "petal", + "petals", + "plant", + "shop", + "spring", + "sprout", + "stem", + "summer" + ], + "popularity": 12598 + }, + "LOCAL_GAS_STATION": { + "tags": [ + "area", + "auto", + "automotive", + "car", + "diesel", + "discover", + "dispenser", + "energy", + "filling up", + "fuel", + "gas", + "gas nozzle", + "gas station", + "gasoline", + "journey", + "local", + "location", + "map", + "navigation", + "nearby", + "oil", + "petrol station", + "point of interest", + "pump", + "refueling", + "road trip", + "search", + "service", + "station", + "transportation", + "travel", + "vehicle" + ], + "popularity": 13044 + }, + "LOCAL_GROCERY_STORE": { + "tags": [ + "add to cart", + "basket", + "buy", + "buying", + "carriage", + "cart", + "checkout", + "commerce", + "e-commerce", + "general store", + "goods", + "grocery", + "items", + "local", + "market", + "merchandise", + "online shopping", + "products", + "purchase", + "retail", + "retail store", + "sale", + "shop", + "shopping", + "shopping bag", + "shopping cart", + "store", + "trolley" + ], + "popularity": 14416 + }, + "LOCAL_HOSPITAL": { + "tags": [ + "911", + "aid", + "ambulance", + "building", + "care", + "clinic", + "cross", + "doctor", + "emergency", + "facility", + "first", + "health", + "healthcare", + "help", + "hospital", + "local", + "location", + "map", + "medical", + "medicine", + "navigation", + "nurse", + "pharmacy", + "pin", + "plus", + "pointer", + "treatment" + ], + "popularity": 20987 + }, + "LOCAL_HOTEL": { + "tags": [ + "accommodation", + "apartment", + "bed", + "body", + "booking", + "building", + "guesthouse", + "holiday", + "hospitality", + "hostel", + "hotel", + "hotel icon", + "house", + "human", + "inn", + "local", + "lodging", + "lodging icon", + "motel", + "people", + "person", + "place", + "rectangle", + "rent", + "reservation", + "resort", + "room", + "shelter", + "sleep", + "square", + "stay", + "structure", + "tourism", + "travel", + "travel destination", + "triangle", + "trip", + "vacation" + ], + "popularity": 2662 + }, + "LOCAL_LAUNDRY_SERVICE": { + "tags": [ + "amenity", + "apparel", + "bubble", + "bubbles", + "business", + "chores", + "cleaner", + "cleaning", + "cleaning supplies", + "clothes", + "clothing", + "domestic", + "droplet", + "dry", + "dryer", + "establishment", + "facility", + "hotel", + "household", + "hygiene", + "laundromat", + "laundry", + "local", + "location", + "marker", + "pinpoint", + "service", + "service area", + "shop", + "textile", + "washer", + "washing", + "washing machine", + "water drop" + ], + "popularity": 7661 + }, + "LOCAL_LIBRARY": { + "tags": [ + "academy", + "archive", + "book", + "book icon", + "book stack", + "book symbol", + "books", + "collection", + "community learning", + "education", + "education icon", + "information", + "knowledge", + "knowledge base", + "knowledge icon", + "learn", + "learning icon", + "library", + "literacy", + "literature", + "literature stack", + "local", + "local library", + "read", + "reading", + "reading icon", + "research", + "resources", + "school", + "stack of books", + "study", + "university" + ], + "popularity": 19971 + }, + "LOCAL_MALL": { + "tags": [ + "bag", + "basket", + "bill", + "boutique", + "building", + "business", + "buy", + "buying", + "card", + "cart", + "cash", + "coin", + "commerce", + "commercial", + "consumer", + "consumerism", + "credit", + "currency", + "department store", + "dollars", + "e-commerce", + "goods", + "handbag", + "items", + "local", + "mall", + "market", + "marketplace", + "money", + "online", + "outlet", + "pay", + "payment", + "products", + "purchase", + "purchasing", + "retail", + "retail store", + "shop", + "shopping", + "shopping bag", + "shopping center", + "store", + "storefront" + ], + "popularity": 29017 + }, + "LOCAL_MOVIES": { + "tags": [ + "box office", + "cinema", + "clip", + "documentary", + "entertainment", + "feature", + "film", + "independent", + "local", + "media", + "movie", + "perforation", + "performance", + "play", + "playback", + "production", + "projector", + "rectangle", + "reel", + "rounded corners", + "screening", + "short", + "show", + "square", + "stream", + "theater", + "theaters", + "video", + "view", + "watch" + ], + "popularity": 3726 + }, + "LOCAL_OFFER": { + "tags": [ + "bargain", + "commerce", + "coupon", + "deal", + "discount", + "label", + "market", + "offer", + "pointed shape", + "price", + "promotion", + "retail", + "sale", + "shape", + "shop", + "shopping", + "special offer", + "store", + "tag", + "tag shape", + "voucher" + ], + "popularity": 61822 + }, + "LOCAL_PARKING": { + "tags": [ + "alphabet", + "auto", + "block", + "car", + "character", + "city", + "destination", + "driving", + "find parking", + "font", + "garage", + "letter p", + "letters", + "local", + "location", + "map", + "navigation", + "p symbol", + "park", + "parking", + "parking area", + "parking lot", + "parking spot", + "poi", + "point of interest", + "road", + "sign", + "space", + "square", + "street", + "symbol", + "text", + "transportation", + "travel", + "type", + "urban", + "vehicle" + ], + "popularity": 12420 + }, + "LOCAL_PHARMACY": { + "tags": [ + "911", + "aid", + "building", + "clinic", + "cross", + "cure", + "drug", + "drugstore", + "emergency", + "find", + "first", + "first aid", + "health", + "healthcare", + "hospital", + "local", + "location", + "map", + "medical", + "medicine", + "navigation", + "pharmacy", + "pin", + "places", + "plus", + "pointer", + "prescription", + "retail", + "rx", + "shop", + "store", + "symbol", + "treatment" + ], + "popularity": 5384 + }, + "LOCAL_PHONE": { + "tags": [ + "audio", + "booth", + "business", + "call", + "communication", + "connect", + "connection", + "contact", + "contact us", + "customer service", + "device", + "dial", + "directory", + "emergency", + "handset", + "help", + "incoming", + "local phone", + "mobile", + "office", + "outgoing", + "phone", + "phone alt", + "receiver", + "ring", + "speak", + "support", + "talk", + "telecommunication", + "telephone", + "voice" + ], + "popularity": 14252 + }, + "LOCAL_PIZZA": { + "tags": [ + "catering", + "cheese", + "circle", + "circular", + "cooking", + "cuisine", + "delivery", + "dining", + "dish", + "drink", + "eat", + "fastfood", + "food", + "food and drink", + "ingredients", + "italian", + "italy", + "local", + "meal", + "menu", + "pizza", + "restaurant", + "round", + "slice", + "slices", + "takeaway", + "tomato", + "toppings", + "triangle", + "triangles" + ], + "popularity": 7046 + }, + "LOCAL_PLAY": { + "tags": [ + "access", + "activity", + "admission", + "attendance", + "cinema", + "coupon", + "cutout", + "entertainment", + "entertainment pass", + "entry", + "event", + "event pass", + "local", + "movie", + "movie ticket", + "pass", + "perforation", + "play", + "rectangular", + "shape", + "show", + "stub", + "tear-off", + "theater", + "ticket", + "ticket stub", + "voucher" + ], + "popularity": 1719 + }, + "LOCAL_POLICE": { + "tags": [ + "911", + "authority", + "authority symbol", + "badge", + "crime", + "emblem", + "government", + "identification", + "identification badge", + "investigation", + "justice", + "law", + "law and order", + "law enforcement", + "local", + "local police", + "military", + "officer", + "official", + "police", + "police department", + "police emblem", + "police star", + "protect", + "protection", + "safety", + "security", + "shield", + "star", + "symbol", + "uniform" + ], + "popularity": 16078 + }, + "LOCAL_POST_OFFICE": { + "tags": [ + "address", + "building", + "building exterior", + "business", + "communication", + "delivery", + "destination", + "email", + "envelop", + "envelope", + "government", + "institution", + "landmark", + "letter", + "letters", + "local", + "location", + "mail", + "map", + "message", + "navigation", + "office", + "package", + "parcel", + "pin", + "place", + "pointer", + "post", + "post office", + "postal", + "receiving", + "send", + "sending", + "service", + "sign", + "stamp", + "structure", + "symbol" + ], + "popularity": 11562 + }, + "LOCAL_PRINTSHOP": { + "tags": [ + "copier", + "copy", + "device", + "document", + "draft", + "fax", + "hardware", + "ink", + "local", + "machine", + "office", + "output", + "paper", + "press", + "print", + "printer", + "printing", + "printing press", + "printshop", + "publication", + "publish", + "scanner", + "send" + ], + "popularity": 7404 + }, + "LOCAL_SEE": { + "tags": [ + "camera", + "capture", + "cinema", + "event", + "film", + "footage", + "gallery", + "lens", + "live", + "local", + "media", + "movie", + "observation", + "optic", + "photo", + "photography", + "picture", + "post", + "production", + "record", + "see", + "shoot", + "sight", + "snapshot", + "story", + "stream", + "studio", + "upload", + "video camera", + "videography", + "view", + "vision" + ], + "popularity": 4783 + }, + "LOCAL_SHIPPING": { + "tags": [ + "automobile", + "box", + "business", + "car", + "cargo", + "cars", + "commerce", + "delivery", + "distribution", + "drive", + "freight", + "goods", + "letters", + "local", + "logistics", + "lorry", + "mail", + "maps", + "merchandise", + "move", + "office", + "package", + "parcel", + "post", + "postal", + "road", + "send", + "shipping", + "shopping", + "stamp", + "supply chain", + "transport", + "transportation", + "travel", + "truck", + "van", + "vehicle", + "wheels" + ], + "popularity": 223945 + }, + "LOCAL_TAXI": { + "tags": [ + "appointment", + "auto", + "automobile", + "booking", + "cab", + "call", + "car", + "cars", + "city", + "direction", + "driver", + "drop off", + "hire", + "local", + "location", + "lyft", + "map", + "maps", + "navigation", + "passenger", + "pick up", + "public", + "public transportation", + "rent", + "ride", + "road", + "route", + "service", + "street", + "taxi", + "transport", + "transportation", + "travel", + "uber", + "vehicle", + "yellow" + ], + "popularity": 7748 + }, + "LOCATION_CITY": { + "tags": [ + "apartments", + "architecture", + "area", + "building", + "buildings", + "business", + "city", + "community", + "construction", + "destination", + "district", + "downtown", + "estate", + "geography", + "home", + "landmark", + "landscape", + "location", + "map marker", + "metropolis", + "neighborhood", + "place", + "point of interest", + "real", + "real estate", + "rectangle", + "region", + "residence", + "residential", + "shelter", + "skyline", + "square", + "structure", + "town", + "travel", + "urban" + ], + "popularity": 30191 + }, + "LOCATION_DISABLED": { + "tags": [ + "access denied", + "alert", + "blocked", + "circle", + "cross", + "deny", + "destination", + "diagonal line", + "direction", + "disabled", + "enabled", + "error", + "forbidden", + "geolocation", + "gps off", + "location", + "location disabled", + "lost", + "map", + "maps", + "marker", + "navigation", + "no signal", + "not found", + "off", + "on", + "pin", + "pinpoint", + "place", + "pointer", + "positioning", + "prohibition", + "restricted", + "satellite", + "slash", + "stop", + "tracking", + "unavailable", + "warning" + ], + "popularity": 1388 + }, + "LOCATION_OFF": { + "tags": [ + "address", + "blocked", + "cross out", + "denied", + "destination", + "direction", + "disabled", + "geo", + "geo-location", + "gps", + "hide location", + "location", + "location access", + "location disabled", + "location privacy", + "location services", + "map", + "map pin", + "maps", + "marker", + "navigation", + "no location", + "not tracking", + "off", + "pin", + "place", + "position", + "privacy", + "private", + "restricted", + "security", + "stop", + "stop tracking", + "tracking off", + "unavailable" + ], + "popularity": 4096 + }, + "LOCATION_ON": { + "tags": [ + "address", + "area", + "current location", + "destination", + "direction", + "drop", + "find", + "geography", + "geotag", + "gps", + "landmark", + "locate", + "location", + "map", + "maps", + "marker", + "navigation", + "nearby", + "on", + "pin", + "place", + "point of interest", + "pointer", + "position", + "proximity", + "region", + "route", + "site", + "spot", + "stop", + "teardrop", + "travel", + "venue" + ], + "popularity": 211574 + }, + "LOCATION_SEARCHING": { + "tags": [ + "acquire", + "acquiring", + "coordinates", + "current location", + "destination", + "direction", + "finding", + "gps", + "locate", + "location", + "map", + "maps", + "navigate", + "navigation", + "not fixed", + "pin", + "pinpoint", + "place", + "pointer", + "pointing", + "position", + "radar", + "scan", + "scanning", + "search", + "searching", + "searching signal", + "signal", + "stop", + "target", + "tracking" + ], + "popularity": 8533 + }, + "LOCK": { + "tags": [ + "access", + "authentication", + "authorization", + "browser", + "closed", + "confidential", + "connection", + "data", + "digital", + "encryption", + "https", + "internet", + "key", + "lock", + "locked", + "network", + "outline", + "padlock", + "password", + "privacy", + "private", + "protected", + "protection", + "protocol", + "restrict", + "safe", + "safeguard", + "safety", + "secure", + "security", + "ssl", + "tls", + "website" + ], + "popularity": 224060 + }, + "LOCK_CLOCK": { + "tags": [ + "access", + "access control", + "access time", + "clock", + "control", + "controlled access", + "date", + "delay", + "hours", + "limited access", + "lock", + "locked", + "minutes", + "padlock", + "password", + "privacy", + "private", + "protection", + "restriction", + "safety", + "schedule", + "scheduled", + "secure", + "secure time", + "security", + "security lock", + "temporal lock", + "time", + "time limit", + "time locked", + "time-based", + "timed access", + "timing", + "unlock time", + "watch" + ], + "popularity": 8391 + }, + "LOCK_OPEN": { + "tags": [ + "access", + "action open", + "authorized", + "button open", + "control open", + "freedom", + "grant access", + "keyhole", + "lock", + "lock open", + "open", + "open door", + "padlock open", + "password", + "permission", + "privacy", + "privacy open", + "private", + "protection", + "protection open", + "release", + "safety", + "safety open", + "secure", + "security", + "security open", + "state open", + "symbol open", + "toggle lock", + "unblocked", + "unlock", + "unlocked", + "unrestricted", + "unsecure", + "vulnerability" + ], + "popularity": 64093 + }, + "LOCK_PERSON": { + "tags": [ + "access", + "access control", + "account", + "authentication", + "authorization", + "confidential", + "entry.", + "figure", + "human", + "identity", + "key", + "lock", + "login", + "padlock", + "permission", + "person", + "privacy", + "private", + "profile", + "protected", + "protection", + "restricted", + "safeguard", + "safety", + "secrecy", + "secure", + "security", + "shield", + "silhouette", + "user" + ], + "popularity": 3131 + }, + "LOCK_RESET": { + "tags": [ + "access", + "around", + "arrow", + "authentication", + "authorization", + "circle", + "clockwise", + "closed", + "entry", + "inprogress", + "key", + "keyhole", + "load", + "loading refresh", + "lock", + "locked", + "login", + "loop", + "padlock", + "password", + "privacy", + "private", + "protected", + "protection", + "redo", + "refresh", + "reload", + "renew", + "reset", + "restart", + "rotate", + "rotation", + "safety", + "secret", + "secure", + "security", + "turn", + "unlocked" + ], + "popularity": 8535 + }, + "LOGIN": { + "tags": [ + "access", + "account", + "app", + "application", + "arrow", + "authentication", + "authorization", + "avatar", + "circle", + "components", + "design", + "enter", + "entrance", + "entry", + "head", + "human", + "id", + "identity", + "in", + "interface", + "left", + "log", + "login", + "member", + "outline", + "person", + "personal", + "privacy", + "profile", + "registration", + "screen", + "secure", + "sign", + "sign in", + "sign on", + "silhouette", + "site", + "ui", + "user", + "ux", + "web", + "website" + ], + "popularity": 132503 + }, + "LOGO_DEV": { + "tags": [ + "app", + "application", + "brand", + "build", + "building", + "business", + "code", + "coding", + "company", + "computer", + "creating", + "creator", + "design", + "dev", + "dev.to", + "developer", + "development", + "digital", + "identity", + "internet", + "logo", + "mark", + "online", + "product", + "programming", + "software", + "startup", + "symbol", + "tech", + "technology", + "web", + "website" + ], + "popularity": 2073 + }, + "LOGOUT": { + "tags": [ + "access", + "account", + "app", + "application", + "arrow", + "arrow pointing right", + "arrow right", + "authentication", + "away", + "components", + "design", + "door", + "door icon", + "exit", + "exit symbol", + "interface", + "leave", + "line", + "log", + "log out", + "login", + "logout", + "off", + "open door", + "profile", + "rectangle", + "right", + "screen", + "security", + "session", + "sign out", + "signing off", + "site", + "square", + "system", + "ui", + "user", + "ux", + "web", + "website" + ], + "popularity": 260057 + }, + "LOOKS": { + "tags": [ + "accessory", + "circle", + "clarity", + "enhancement", + "eyeglasses", + "eyes", + "eyewear", + "fashion", + "focus", + "frames", + "glasses", + "half", + "lenses", + "looking", + "looks", + "magnifying glass", + "ophthalmology", + "optical", + "optometrist", + "perception", + "rainbow", + "reading glasses", + "see", + "seeing", + "sight", + "spectacles", + "style", + "sunglasses", + "view", + "vision" + ], + "popularity": 2736 + }, + "LOOKS_3": { + "tags": [ + "3", + "arrangement", + "controls", + "count", + "customization", + "data", + "digit", + "filter", + "grouping", + "hierarchy", + "information", + "layers", + "level", + "list", + "looks", + "menu", + "number 3", + "numbers", + "numerical", + "options", + "ordered", + "organization", + "priority", + "ranking", + "segmentation", + "sequence", + "settings", + "sort", + "square", + "stacking", + "symbol", + "three" + ], + "popularity": 8788 + }, + "LOOKS_4": { + "tags": [ + "4", + "block", + "block four", + "count", + "design", + "digit", + "digit four", + "element", + "figure", + "four square", + "geometry", + "graphic", + "icon", + "interface", + "looks", + "looks 4", + "number", + "number four", + "numbers", + "numeral", + "numeral four", + "quantity", + "shape", + "square", + "symbol", + "ui", + "ux", + "value" + ], + "popularity": 4829 + }, + "LOOKS_5": { + "tags": [ + "5", + "browse", + "digit", + "discover", + "enlarge", + "examine", + "explore", + "find", + "find icon", + "find symbol", + "focus", + "input", + "inspection", + "investigate", + "locate", + "look", + "look for", + "look through", + "look up", + "looks", + "magnifying glass", + "magnifying glass symbol", + "numbers", + "observe", + "query", + "review", + "scan", + "search", + "search bar", + "search field", + "search symbol", + "square", + "survey", + "symbol", + "view", + "zoom" + ], + "popularity": 3654 + }, + "LOOKS_6": { + "tags": [ + "6", + "achievement", + "approval", + "badge", + "bookmark", + "choice", + "digit", + "endorse", + "evaluate", + "excellence", + "favorite", + "five star", + "gold star", + "highlight", + "important", + "like", + "looks", + "mark", + "numbers", + "positive", + "preference", + "premium", + "quality", + "ranking", + "rating", + "recommend", + "review", + "reward", + "save", + "select", + "square", + "star", + "success", + "symbol" + ], + "popularity": 2771 + }, + "LOOKS_ONE": { + "tags": [ + "1", + "beginning", + "competition", + "count", + "counting", + "digit", + "exclusive", + "first", + "initial", + "leading", + "looks", + "major", + "math", + "mathematics", + "number one", + "numbers", + "numeral", + "numerical", + "one", + "original", + "position", + "primary", + "principal", + "ranked", + "ranking", + "single", + "sole", + "square", + "start", + "symbol", + "top", + "unique", + "winner" + ], + "popularity": 19030 + }, + "LOOKS_TWO": { + "tags": [ + "2", + "digit", + "double", + "eye", + "eyes", + "glasses", + "lenses", + "look", + "looks", + "numbers", + "observation", + "oculist", + "opthalmology", + "optical", + "optics", + "pair", + "perceive", + "seeing", + "sight", + "spectacles", + "square", + "symbol", + "two", + "view", + "vision", + "visual", + "watch" + ], + "popularity": 10009 + }, + "LOOP": { + "tags": [ + "action", + "around", + "arrow", + "arrows", + "autorenew", + "circle", + "circular", + "circular arrow", + "content", + "continuous", + "curved arrow", + "cycle", + "data", + "direction", + "endless", + "inprogress", + "load", + "loading refresh", + "loop", + "media", + "music", + "navigation", + "playback", + "process", + "redo", + "refresh", + "refresh data", + "refresh page", + "reload", + "renew", + "repeat", + "repeat playlist", + "repeat song", + "restart", + "rotate", + "synchronize", + "turn", + "update" + ], + "popularity": 20748 + }, + "LOUPE": { + "tags": [ + "+", + "add", + "analyze", + "circle", + "details", + "discover", + "enlarge", + "explore", + "field", + "find", + "focus", + "glass", + "handle", + "input", + "inquiry", + "investigate", + "line", + "locate", + "look", + "loupe", + "magnify", + "magnifying", + "magnifying glass", + "navigation", + "new", + "plus", + "probe", + "query", + "research", + "search", + "seek", + "symbol", + "tool", + "utility", + "zoom" + ], + "popularity": 5356 + }, + "LOW_PRIORITY": { + "tags": [ + "arrange", + "arrow", + "arrow down", + "backward", + "bottom", + "decrease priority", + "demote", + "down direction", + "down priority", + "downward arrow", + "horizontal line", + "less important", + "line", + "list", + "low", + "low priority", + "lower priority", + "minimum", + "minimum priority", + "minor", + "move", + "non-critical", + "not urgent", + "order", + "priority", + "queue", + "ranking", + "re-sort", + "reorder", + "sorting", + "straight line", + "task priority", + "unimportant" + ], + "popularity": 7638 + }, + "LOYALTY": { + "tags": [ + "achievement", + "award", + "benefit", + "benefits", + "best", + "bonus", + "card", + "client", + "credit", + "customer", + "exclusive", + "five point star", + "gift", + "good", + "gratitude", + "heart", + "loyalty", + "membership", + "miles", + "perk", + "points", + "points system", + "premium", + "present", + "prize", + "program", + "quality", + "recognition", + "reward", + "sparkle", + "special", + "star", + "subscription", + "tag", + "travel", + "trip", + "value", + "vip" + ], + "popularity": 24004 + }, + "LTE_MOBILEDATA": { + "tags": [ + "access", + "alphabet", + "bar", + "bars", + "broadband", + "cellular", + "character", + "communications", + "connection", + "data", + "font", + "high speed", + "indicator", + "internet", + "label", + "letter", + "letters", + "level", + "lte", + "mobile", + "mobiledata", + "network", + "online", + "signal", + "speed", + "status", + "strength", + "symbol", + "technology", + "telecommunications", + "text", + "type", + "typography", + "wifi", + "wireless" + ], + "popularity": 1360 + }, + "LTE_PLUS_MOBILEDATA": { + "tags": [ + "+", + "alphabet", + "cell", + "character", + "characters", + "communication", + "connection", + "data", + "font", + "icon", + "indicator", + "internet", + "letter", + "letters", + "lte", + "mobile", + "network", + "plus", + "quality", + "sign", + "signal", + "speed", + "status", + "strength", + "symbol", + "text", + "type", + "wifi", + "wireless" + ], + "popularity": 1115 + }, + "LUGGAGE": { + "tags": [ + "airport", + "bag", + "baggage", + "belongings", + "box", + "carry", + "carry-on", + "essentials", + "expedition", + "flight", + "getaway", + "handle", + "holiday", + "hotel", + "journey", + "luggage", + "movement", + "on", + "packing", + "personal items", + "rectangle", + "square", + "suitcase", + "tourism", + "transport", + "travel", + "travel bag", + "travel essentials", + "travel gear", + "trip", + "trunk", + "vacation", + "vacation items" + ], + "popularity": 11183 + }, + "LUNCH_DINING": { + "tags": [ + "bar", + "breakfast", + "breakfast time", + "brunch", + "cafe", + "canteen", + "cutlery", + "dining", + "dining area", + "dining location", + "dining room", + "dinner", + "dinner time", + "drink", + "eat", + "eating", + "eating area", + "eating place", + "fastfood", + "food", + "fork", + "hamburger", + "kitchen", + "knife", + "lunch", + "lunch time", + "meal", + "meal time", + "restaurant", + "restaurant location", + "service", + "silverware", + "spoon", + "supper" + ], + "popularity": 20414 + }, + "LYRICS": { + "tags": [ + "audio", + "bubble", + "chat", + "comment", + "communicate", + "display lyrics", + "document", + "document icon", + "document outline", + "feedback", + "key", + "language", + "lines", + "lyrics", + "message", + "music", + "music icon", + "music note", + "note", + "paper", + "paper icon", + "paragraph", + "reading", + "reading icon", + "script", + "show lyrics", + "singing", + "song", + "sound", + "speech", + "text", + "text icon", + "text lines", + "track", + "view lyrics", + "vocal", + "words", + "writing", + "writing icon" + ], + "popularity": 1550 + }, + "MACRO_OFF": { + "tags": [ + "camera", + "camera off", + "camera settings", + "circle", + "close-up off", + "controls", + "deactivate", + "detailed view off", + "diagonal line", + "disable", + "disabled", + "editing tools", + "effect off", + "enabled", + "feature off", + "filter off", + "fine detail off", + "flower", + "focus off", + "garden", + "image", + "image editing", + "lens off", + "macro", + "macro off", + "magnification off", + "off", + "offline", + "on", + "photography off", + "photography tools", + "slash", + "small object off", + "strike through", + "switch off", + "toggle off", + "zoom off" + ], + "popularity": 371 + }, + "MAIL": { + "tags": [ + "communication", + "communication icon", + "contact", + "contact icon", + "correspondence", + "diagonal lines", + "digital", + "electronic mail", + "email", + "empty", + "envelop", + "envelope", + "fold", + "icon", + "inbox", + "inbox icon", + "internet", + "letter", + "letters", + "mail", + "message", + "message icon", + "new message", + "online", + "outline", + "paper", + "receive", + "rectangle", + "send", + "symbol", + "thin line", + "unread" + ], + "popularity": 86676 + }, + "MAIL_LOCK": { + "tags": [ + "access", + "closed mail", + "communication", + "confidential", + "confidential mail", + "correspondence", + "email", + "email security", + "encrypted", + "envelop", + "envelope", + "letters", + "lock", + "locked", + "locked mail", + "mail", + "message", + "padlock", + "password", + "privacy", + "private", + "private message", + "protected message", + "protection", + "restricted", + "restricted access", + "safety", + "sealed", + "secure", + "secure communication", + "security", + "security lock", + "send" + ], + "popularity": 1846 + }, + "MAIL_OUTLINE": { + "tags": [ + "communication", + "communication icon", + "contact", + "contact icon", + "correspondence", + "diagonal lines", + "digital", + "electronic mail", + "email", + "empty", + "envelop", + "envelope", + "fold", + "icon", + "inbox", + "inbox icon", + "internet", + "letter", + "letters", + "mail", + "message", + "message icon", + "new message", + "online", + "outline", + "paper", + "receive", + "rectangle", + "send", + "symbol", + "thin line", + "unread" + ], + "popularity": 68753 + }, + "MALE": { + "tags": [ + "account", + "avatar", + "avatar icon", + "body", + "body icon", + "boy", + "circle", + "figure", + "figure icon", + "gender", + "gender icon", + "head", + "head icon", + "human", + "human icon", + "identity", + "male", + "man", + "man icon", + "person", + "person icon", + "profile", + "profile icon", + "shoulders", + "shoulders icon", + "silhouette", + "silhouette icon", + "social", + "symbol", + "user", + "user icon" + ], + "popularity": 13396 + }, + "MAN": { + "tags": [ + "account", + "avatar", + "body", + "boy", + "character", + "figure", + "gender", + "graphic", + "head", + "human", + "icon", + "identity", + "individual", + "login", + "male", + "man", + "member", + "member profile", + "outline", + "people", + "person", + "profile", + "profile picture", + "representation", + "shoulders", + "silhouette", + "social", + "symbol", + "user", + "user account", + "user profile" + ], + "popularity": 7216 + }, + "MAN_2": { + "tags": [ + "account", + "avatar", + "biography", + "boy", + "bust", + "contact", + "contact information", + "gender", + "head", + "human", + "individual", + "login", + "male", + "man", + "my account", + "people", + "person", + "person icon", + "personal details", + "profile", + "profile page", + "settings", + "shoulders", + "single user", + "social", + "symbol", + "user", + "user account", + "user data", + "user management", + "user profile", + "user settings" + ], + "popularity": 1023 + }, + "MAN_3": { + "tags": [ + "abstract", + "account", + "avatar", + "boy", + "circle", + "contact", + "figure", + "gender", + "glyph", + "head", + "human", + "icon", + "identity", + "individual", + "login", + "male", + "man", + "member", + "outline", + "person", + "profile", + "shape", + "shoulders", + "signup", + "silhouette", + "social", + "symbol", + "user" + ], + "popularity": 540 + }, + "MAN_4": { + "tags": [ + "abstract", + "account", + "account icon", + "account management", + "avatar", + "boy", + "community", + "contact", + "figure", + "gender", + "head", + "human", + "identity", + "individual", + "login", + "male", + "man", + "member", + "people", + "person", + "person icon", + "profile", + "profile icon", + "shoulders", + "silhouette", + "social", + "symbol", + "user", + "user icon", + "user profile" + ], + "popularity": 682 + }, + "MANAGE_ACCOUNTS": { + "tags": [ + "access", + "accounts", + "administration", + "avatar", + "bust", + "change", + "circle", + "control", + "customization", + "data", + "details", + "editing", + "face", + "figure", + "gear", + "group", + "human", + "identity", + "individual", + "information", + "manage", + "members", + "options", + "people", + "permissions", + "person", + "preferences", + "profile", + "security", + "service", + "settings", + "team", + "user", + "users" + ], + "popularity": 160425 + }, + "MANAGE_HISTORY": { + "tags": [ + "administration", + "application", + "arrangement", + "arrow", + "back", + "backwards", + "change", + "chronology", + "circular", + "clock", + "cog", + "control", + "date", + "details", + "events", + "future", + "gear", + "history", + "list", + "log", + "management", + "options", + "order", + "organization", + "past", + "pointer", + "present", + "record", + "refresh", + "renew", + "reverse", + "review", + "rewind", + "rotate", + "schedule", + "sequence", + "settings", + "time", + "timeline", + "tracking", + "turn" + ], + "popularity": 5934 + }, + "MANAGE_SEARCH": { + "tags": [ + "administration", + "configure", + "control", + "discover", + "explore", + "filter", + "find", + "find and manage", + "glass", + "history", + "interface", + "lens", + "locate", + "magnifying", + "magnifying glass", + "manage", + "options", + "organize", + "preferences", + "query", + "results", + "search", + "search and organize", + "search filters", + "search results", + "settings", + "system", + "text", + "tool", + "utility" + ], + "popularity": 45396 + }, + "MAP": { + "tags": [ + "address", + "atlas", + "cartography", + "city", + "continent", + "country", + "destination", + "direction", + "directions", + "discover", + "earth", + "explore", + "geography", + "gps", + "guide", + "journey", + "location", + "map", + "maps", + "marker", + "navigation", + "pin", + "place", + "point of interest", + "position", + "region", + "route", + "stop", + "street", + "territory", + "track", + "travel", + "world" + ], + "popularity": 60412 + }, + "MAPS_HOME_WORK": { + "tags": [ + "address", + "architecture", + "building", + "business", + "commercial", + "company", + "destination", + "dwelling", + "employment", + "factory", + "headquarters", + "home", + "house", + "industry", + "job", + "location", + "maps", + "navigation", + "office", + "place", + "real estate", + "residential", + "structure", + "work", + "workplace" + ], + "popularity": 33128 + }, + "MAPS_UGC": { + "tags": [ + "+", + "add", + "add data", + "bubble", + "cartography", + "comment", + "communicate", + "contribution", + "create", + "data", + "destination", + "destination pin", + "direction", + "feedback", + "generate", + "geography", + "location", + "location pin", + "map", + "map marker", + "map pin", + "maps", + "marker", + "message", + "navigation", + "new", + "pin", + "pinpoint", + "place", + "plus", + "point", + "position", + "share", + "speech", + "submit", + "symbol", + "travel", + "ugc", + "upload", + "user contribution" + ], + "popularity": 7768 + }, + "MARGIN": { + "tags": [ + "adjust", + "adjust text", + "alignment", + "border", + "boundaries", + "box", + "contract", + "decrease", + "design", + "document", + "dots", + "edge", + "expand", + "format", + "increase", + "indent", + "layout", + "line", + "lines", + "margin", + "measurement", + "options", + "padding", + "paragraph", + "properties", + "rule", + "settings", + "size", + "spacing", + "square", + "text", + "text settings" + ], + "popularity": 1988 + }, + "MARK_AS_UNREAD": { + "tags": [ + "alert", + "as", + "attention", + "badge", + "bookmark", + "chat", + "circle", + "circular", + "communication", + "dot", + "email", + "emblem", + "envelop", + "highlight", + "important", + "indicator", + "letters", + "mail", + "mark", + "message", + "new", + "notification", + "pending", + "point", + "post", + "postal", + "read", + "receive", + "round", + "send", + "signal", + "sphere", + "status", + "symbol", + "unread", + "urgent" + ], + "popularity": 9877 + }, + "MARK_CHAT_READ": { + "tags": [ + "approve", + "bubble", + "chat", + "chat bubble", + "chat icon", + "check", + "checked", + "checkmark", + "checkmark icon", + "comment", + "communicate", + "communication", + "communication icon", + "complete", + "complete icon", + "confirmed", + "conversation", + "conversation icon", + "done", + "done check", + "done icon", + "email", + "email icon", + "inbox", + "mail", + "mail icon", + "mark", + "mark read", + "mark read icon", + "message", + "message icon", + "ok", + "read", + "read message", + "select", + "sent", + "sms", + "speech", + "speech bubble", + "tick", + "verified", + "yes" + ], + "popularity": 5355 + }, + "MARK_CHAT_UNREAD": { + "tags": [ + "alarm", + "alert", + "balloon", + "bubble", + "chat", + "chat bubble", + "circle", + "comment", + "communicate", + "communication", + "conversation", + "direct message", + "discussion", + "dm", + "dot", + "engagement", + "indicator", + "interaction", + "mark", + "mark as unread", + "message", + "new message", + "notification", + "notifications", + "notify", + "private message", + "reminder", + "social", + "speech", + "speech bubble", + "status", + "talk", + "thought bubble", + "unread", + "unread chat", + "unread message" + ], + "popularity": 8298 + }, + "MARK_EMAIL_READ": { + "tags": [ + "acknowledge", + "approve", + "archive", + "box", + "check", + "checked", + "communication", + "complete", + "confirmation", + "correspondence", + "correspondence.", + "delivered", + "document", + "done", + "email", + "envelop", + "envelope", + "inbox", + "letter", + "letters", + "mail", + "mark", + "mark as read", + "message", + "note", + "notification", + "ok", + "opened", + "paper", + "read", + "received", + "reviewed", + "select", + "send", + "sent", + "success", + "tick", + "validated", + "verified", + "yes" + ], + "popularity": 16473 + }, + "MARK_EMAIL_UNREAD": { + "tags": [ + "alert", + "check", + "circle", + "communication", + "contact", + "correspondence", + "dot", + "email", + "envelop", + "envelope", + "icon", + "inbox", + "interface element", + "letter", + "letters", + "mail", + "mark", + "message", + "new", + "note", + "notification", + "send", + "status", + "symbol", + "ui element", + "unread" + ], + "popularity": 12035 + }, + "MARK_UNREAD_CHAT_ALT": { + "tags": [ + "alarm", + "alert", + "bubble", + "bubble and dot", + "chat", + "circle", + "comment", + "communicate", + "communication", + "conversation", + "correspondence", + "dialog", + "dot", + "envelope", + "graphic", + "inbox", + "indicator", + "line", + "mail", + "mark", + "message", + "new message", + "notification", + "notifications", + "notify", + "pending", + "point", + "reminder", + "shape", + "speech", + "speech bubble", + "status", + "text message", + "unread", + "vector" + ], + "popularity": 2553 + }, + "MARKUNREAD": { + "tags": [ + "communication", + "communication icon", + "contact", + "contact icon", + "correspondence", + "diagonal lines", + "digital", + "electronic mail", + "email", + "empty", + "envelop", + "envelope", + "fold", + "icon", + "inbox", + "inbox icon", + "internet", + "letter", + "letters", + "mail", + "markunread", + "message", + "message icon", + "new message", + "online", + "outline", + "paper", + "receive", + "rectangle", + "send", + "symbol", + "thin line", + "unread" + ], + "popularity": 12274 + }, + "MARKUNREAD_MAILBOX": { + "tags": [ + "alert", + "box", + "communication", + "deliver", + "delivery", + "envelop", + "envelope", + "flag", + "inbox", + "incoming mail", + "indicator", + "letter", + "letters", + "mail", + "mailbox", + "mark", + "marker", + "markunread", + "message", + "new", + "new message", + "notification", + "pending", + "post", + "post office", + "postal", + "postbox", + "receive", + "received", + "rectangle", + "send", + "signal", + "status.", + "symbol", + "unopened", + "unread" + ], + "popularity": 7487 + }, + "MASKS": { + "tags": [ + "air", + "breath", + "contagion", + "cover", + "covid", + "disease", + "face", + "face covering", + "health", + "health and safety", + "healthcare", + "hospital", + "hygiene", + "illness", + "layered", + "mask", + "masks", + "medical", + "medical mask", + "mouth covering", + "nose covering", + "pandemic", + "pollution", + "prevention", + "protection", + "public health", + "respirator", + "respiratory", + "safety", + "sick", + "sickness", + "social", + "spread", + "surgical mask", + "two masks", + "virus" + ], + "popularity": 10997 + }, + "MAXIMIZE": { + "tags": [ + "action", + "app", + "application", + "arrows", + "box", + "components", + "computer", + "control", + "corners", + "design", + "display", + "element", + "enlarge", + "expand", + "extend", + "full screen", + "fullscreen", + "increase", + "interface", + "line", + "maximize", + "open", + "outward", + "program", + "rectangle", + "resize", + "scale", + "screen", + "shape", + "site", + "size", + "square", + "system", + "ui", + "ux", + "video", + "view", + "web", + "website", + "window", + "zoom" + ], + "popularity": 12534 + }, + "MEDIA_BLUETOOTH_OFF": { + "tags": [ + "audio", + "bluetooth", + "communication", + "connect", + "connection", + "connection off", + "connectivity", + "cross", + "data", + "device", + "devices", + "diagonal", + "disabled", + "disconnected", + "enabled", + "line", + "link", + "media", + "music", + "network", + "note", + "off", + "offline", + "on", + "pairing", + "pairing mode", + "paring", + "share", + "signal", + "signal off", + "slash", + "strikethrough", + "symbol", + "technology", + "technology off", + "transfer", + "unpaired", + "wireless", + "wireless off" + ], + "popularity": 825 + }, + "MEDIA_BLUETOOTH_ON": { + "tags": [ + "active", + "audio", + "bluetooth", + "communication", + "computer", + "connect", + "connected", + "connection", + "connectivity", + "device", + "disabled", + "electronic", + "enabled", + "link", + "media", + "mobile", + "music", + "network", + "note", + "off", + "on", + "online", + "paired", + "pairing", + "paring", + "phone", + "power on", + "signal", + "slash", + "sound", + "state", + "status", + "symbol", + "technology", + "turn on", + "wireless" + ], + "popularity": 1308 + }, + "MEDIATION": { + "tags": [ + "agreement", + "alliance", + "arrow", + "arrows", + "binding", + "binding agreement", + "chain", + "circle", + "collaboration", + "communication", + "compromise", + "connected", + "connection", + "cooperation", + "direction", + "dots", + "group", + "joining", + "link", + "links", + "mediation", + "negotiation", + "network", + "nodes", + "partnership", + "relationship", + "resolution", + "right", + "rings", + "segments", + "team", + "three points", + "together", + "understanding", + "unity" + ], + "popularity": 8845 + }, + "MEDICAL_INFORMATION": { + "tags": [ + "badge", + "card", + "chart", + "clinic", + "cross", + "data", + "details", + "document", + "file", + "folder", + "health", + "health information", + "health record", + "healthcare", + "history", + "hospital", + "icon", + "id", + "id card", + "identification", + "information", + "medical", + "medical chart", + "medical file", + "medical record", + "medicine", + "patient", + "patient data", + "patient history", + "patient record", + "plus sign", + "prescription", + "report", + "services", + "symbol" + ], + "popularity": 4980 + }, + "MEDICAL_SERVICES": { + "tags": [ + "aid", + "assistance", + "bag", + "briefcase", + "care", + "clinic", + "cross", + "doctor", + "doctor's bag", + "emergency", + "first", + "first aid", + "health", + "health services", + "health symbol", + "healthcare", + "healthcare services", + "hospital", + "kit", + "medic", + "medical", + "medical cross", + "medical facility", + "medical help", + "medical kit", + "medical symbol", + "medicine", + "pharmacy", + "plus", + "rescue", + "services", + "treatment", + "wellness" + ], + "popularity": 22982 + }, + "MEDICATION": { + "tags": [ + "capsule", + "doctor", + "drug", + "drug icon", + "emergency", + "health", + "healthcare", + "healthcare icon", + "healthcare item", + "hospital", + "medical", + "medical icon", + "medical treatment", + "medication", + "medication icon", + "medicine", + "medicine icon", + "pharmaceutical", + "pharmacy", + "pharmacy icon", + "pill", + "pill icon", + "pills", + "prescription", + "tablet", + "treatment", + "treatment and cure", + "treatment icon", + "wellness" + ], + "popularity": 19021 + }, + "MEDICATION_LIQUID": { + "tags": [ + "+", + "bottle", + "container", + "cough syrup", + "cure", + "doctor", + "dosage", + "drop", + "drug", + "flask", + "glass", + "health", + "healthcare", + "hospital", + "illness", + "liquid", + "liquid medication", + "medical", + "medication", + "medications", + "medicine", + "oval", + "pharmacy", + "prescription", + "remedy", + "science", + "sickness", + "spoon", + "syrup", + "treatment", + "vessel", + "vial" + ], + "popularity": 2387 + }, + "MEETING_ROOM": { + "tags": [ + "access", + "arch", + "building", + "business", + "closed", + "collaboration", + "communication", + "conference", + "door", + "doorway", + "entrance", + "exit", + "gathering", + "group", + "home", + "house", + "interior", + "meeting", + "meeting room", + "office", + "open", + "people", + "places", + "rectangular", + "room", + "space", + "square", + "team", + "threshold", + "work" + ], + "popularity": 21520 + }, + "MEMORY": { + "tags": [ + "access", + "card", + "chip", + "circuit", + "component", + "computer", + "connection", + "data", + "device", + "digital", + "electronic", + "hardware", + "information", + "integrated circuit", + "lines", + "memory", + "micro", + "module", + "pins", + "processing", + "processor", + "ram", + "rectangle", + "sd", + "square", + "storage", + "system", + "technical", + "technology" + ], + "popularity": 18384 + }, + "MENU": { + "tags": [ + "action menu", + "app", + "app menu", + "application", + "application menu", + "bars", + "burger", + "collapse", + "components", + "control", + "drawer", + "expand", + "expandable menu", + "hamburger", + "horizontal lines", + "interface", + "kebab", + "layers", + "line", + "lines", + "list", + "main menu", + "menu", + "more", + "more options", + "navigation", + "navigation menu", + "options", + "screen", + "settings", + "side menu", + "sidebar", + "site", + "stack", + "stacked bars", + "stripes", + "three bars", + "ui", + "ux", + "web", + "website" + ], + "popularity": 371689 + }, + "MENU_BOOK": { + "tags": [ + "book", + "catalog", + "dictionary", + "dining", + "directory", + "documentation", + "education", + "food", + "glossary", + "guide", + "help", + "information", + "journal", + "knowledge", + "learn", + "library", + "list", + "literature", + "manual", + "meal", + "menu", + "notebook", + "novel", + "pages", + "reading", + "recipe", + "reference", + "research", + "restaurant", + "school", + "story", + "study", + "textbook", + "wisdom" + ], + "popularity": 75183 + }, + "MENU_OPEN": { + "tags": [ + "app", + "application", + "arrow", + "back", + "bar menu", + "burger", + "chevron", + "close", + "close menu", + "collapse", + "components", + "details", + "directional", + "expand", + "forward", + "hamburger", + "hamburger menu", + "hide", + "interface", + "items", + "left", + "line", + "lines", + "list", + "menu", + "menu open", + "more", + "navigation", + "open", + "open menu", + "options", + "panel", + "right", + "screen", + "settings", + "show", + "side menu", + "sidebar", + "site", + "three lines", + "toggle", + "ui", + "ux", + "web", + "website" + ], + "popularity": 44548 + }, + "MERGE": { + "tags": [ + "arrow", + "arrows", + "branches", + "bring together", + "code", + "combine", + "confluence", + "connect", + "consolidate", + "converging lines", + "data", + "development", + "direction", + "directions", + "file operations", + "flow", + "git", + "graph", + "integration", + "join", + "link", + "maps", + "merge", + "navigation", + "network", + "path", + "process", + "route", + "sign", + "source control", + "together", + "traffic", + "two into one", + "union", + "unity", + "version control" + ], + "popularity": 3446 + }, + "MERGE_TYPE": { + "tags": [ + "arrow", + "arrows", + "branch", + "combine", + "combine branches", + "combine content", + "combine data", + "combine documents", + "connect", + "connection", + "connection points", + "data", + "diagram", + "direction", + "flow", + "fork", + "format", + "join", + "join points", + "junction", + "lines", + "link", + "link branches", + "merge", + "merge content", + "merge data", + "merge documents", + "merge type", + "organization", + "points", + "process", + "relationship", + "structure", + "text", + "type", + "visual", + "workflow" + ], + "popularity": 4946 + }, + "MESSAGE": { + "tags": [ + "alert", + "bubble", + "chat", + "comment", + "communicate", + "communication", + "connect", + "contact", + "conversation", + "dialogue", + "discussion", + "feedback", + "help", + "im", + "inbox", + "instant message", + "message", + "messaging", + "messenger", + "new", + "notification", + "receive", + "send", + "sms", + "social", + "speak", + "speech", + "support", + "talk", + "text" + ], + "popularity": 27997 + }, + "MIC": { + "tags": [ + "audio", + "audio button", + "audio capture", + "audio input", + "audio recording", + "chat", + "communication", + "dictate", + "dictation", + "hear", + "hearing", + "input", + "keyboard", + "messaging", + "mic", + "mic button", + "microphone", + "microphone button", + "multimedia", + "noise", + "record", + "recorder", + "recording", + "recording button", + "sound", + "sound capture", + "sound input", + "sound recording", + "speak", + "speaker", + "speech", + "talk", + "voice", + "voice button", + "voice command", + "voice input" + ], + "popularity": 64340 + }, + "MIC_EXTERNAL_OFF": { + "tags": [ + "audio", + "audio device", + "audio input", + "broken", + "circle", + "communication", + "diagonal line", + "disabled", + "enabled", + "error", + "external", + "external microphone", + "media", + "mic", + "microphone", + "mute", + "not connected", + "not working", + "off", + "on", + "recording", + "rectangle", + "slash", + "sound", + "sound device", + "sound input", + "speech", + "stand", + "technology", + "voice", + "volume", + "warning" + ], + "popularity": 853 + }, + "MIC_EXTERNAL_ON": { + "tags": [ + "active", + "audio", + "broadcast", + "circle", + "communication", + "conference", + "connected", + "connected mic", + "disabled", + "enabled", + "equipment", + "external", + "external mic", + "input", + "input device", + "line", + "live", + "media", + "meeting", + "mic", + "microphone", + "off", + "on", + "oval", + "podcast", + "recording", + "slash", + "sound", + "sound input", + "speak", + "streaming", + "studio", + "talk", + "voice" + ], + "popularity": 3380 + }, + "MIC_NONE": { + "tags": [ + "audio", + "audio button", + "audio capture", + "audio input", + "audio recording", + "chat", + "communication", + "dictate", + "dictation", + "hear", + "hearing", + "input", + "keyboard", + "messaging", + "mic", + "mic button", + "microphone", + "microphone button", + "multimedia", + "noise", + "record", + "recorder", + "recording", + "recording button", + "sound", + "sound capture", + "sound input", + "sound recording", + "speak", + "speaker", + "speech", + "talk", + "voice", + "voice button", + "voice command", + "voice input" + ], + "popularity": 10974 + }, + "MIC_OFF": { + "tags": [ + "audio", + "audio input disabled", + "audio off", + "audio settings", + "bar", + "call control", + "communication", + "diagonal line", + "disabled", + "enabled", + "hear", + "hearing", + "input settings", + "meeting control", + "mic", + "mic disabled", + "mic symbol", + "microphone", + "microphone icon", + "microphone muted", + "microphone off", + "mute", + "no audio", + "no sound", + "noise", + "off", + "on", + "privacy", + "quiet", + "record", + "recording", + "recording mute", + "recording off", + "security", + "silenced", + "slash", + "sound", + "sound off", + "speak off", + "talk mute", + "voice", + "voice input off", + "voice mute", + "voice off" + ], + "popularity": 15578 + }, + "MICROWAVE": { + "tags": [ + "appliance", + "buttons", + "controls", + "convenience", + "cook", + "cooking", + "defrost", + "domestic", + "door", + "easy", + "electric", + "electronics", + "food", + "heat", + "heating", + "home", + "house", + "kitchen", + "machine", + "meal", + "microwave", + "oven", + "panel", + "prepare", + "quick", + "rectangle", + "reheat", + "square", + "warm" + ], + "popularity": 4265 + }, + "MILITARY_TECH": { + "tags": [ + "accomplishment", + "achievement", + "air force", + "army", + "award", + "badge", + "decoration", + "defense", + "excellence", + "guarantee", + "high quality", + "honor", + "insignia", + "marines", + "medal", + "merit", + "military", + "navy", + "order", + "premium", + "privilege", + "prize", + "quality", + "rank", + "ranking", + "reward", + "ribbon", + "soldier", + "star", + "status", + "success", + "symbol", + "tech", + "technology", + "trophy", + "verified", + "veteran", + "warfare", + "win", + "winner" + ], + "popularity": 27103 + }, + "MINIMIZE": { + "tags": [ + "action", + "app", + "application", + "bar", + "basic", + "bottom", + "button", + "close", + "collapse", + "compact", + "components", + "contract", + "control", + "design", + "down", + "element", + "essential", + "exit", + "hide", + "horizontal", + "interaction", + "interface", + "less", + "line", + "minimize", + "reduce", + "remove", + "screen", + "shape", + "shrink", + "simple", + "site", + "smaller", + "standard", + "system", + "ui", + "ux", + "web", + "website", + "window" + ], + "popularity": 30501 + }, + "MINOR_CRASH": { + "tags": [ + "accident", + "alert", + "attention", + "auto", + "automobile", + "car", + "cars", + "caution", + "collision", + "critical", + "danger", + "directions", + "emergency", + "error", + "exclamation", + "exclamation mark", + "hazard", + "important", + "issue", + "maps", + "notification", + "point", + "problem", + "public", + "risk", + "security", + "transportation", + "triangle", + "urgent", + "vehicle", + "warning" + ], + "popularity": 1450 + }, + "MISCELLANEOUS_SERVICES": { + "tags": [], + "popularity": 13970 + }, + "MISSED_VIDEO_CALL": { + "tags": [ + "absent", + "alert", + "arrow", + "call", + "camera", + "cancelled", + "chat", + "communication", + "conference", + "contact", + "declined", + "diagonal line", + "ended", + "failed", + "film", + "filming", + "hardware", + "history", + "image", + "log", + "meeting", + "message", + "missed", + "motion", + "multimedia", + "notification", + "online", + "phone", + "picture", + "record", + "ring", + "teleconference", + "telephone", + "unavailable", + "video", + "video call", + "videography", + "webcam" + ], + "popularity": 1362 + }, + "MMS": { + "tags": [ + "attachment", + "bubble", + "chat", + "comment", + "communicate", + "conversation", + "dialogue bubble", + "document", + "envelope", + "feedback", + "file", + "image", + "image message", + "landscape", + "letter", + "mail", + "message", + "message bubble", + "mms", + "mountain", + "mountains", + "multimedia", + "multimedia message", + "photo", + "photo message", + "photography", + "picture", + "picture message", + "receive", + "send", + "sms", + "speech", + "speech bubble", + "talk bubble", + "text message" + ], + "popularity": 2267 + }, + "MOBILE_FRIENDLY": { + "tags": [ + "android", + "approve", + "approved", + "cell", + "check", + "checkmark", + "complete", + "device", + "display", + "done", + "friendly", + "good", + "hardware", + "icon", + "ios", + "mark", + "mobile", + "mobile check", + "mobile phone", + "ok", + "os", + "phone", + "protection", + "safe", + "screen", + "secure", + "security", + "security update", + "select", + "smartphone", + "success", + "symbol", + "system", + "system update", + "tablet", + "technology", + "tick", + "ui", + "update", + "validate", + "validated", + "verified", + "yes" + ], + "popularity": 5233 + }, + "MOBILE_OFF": { + "tags": [ + "access", + "airplane mode", + "android", + "barred", + "cell", + "cell off", + "communication", + "crossed out", + "deactivated", + "device", + "diagonal line", + "disabled", + "disconnected", + "do not disturb", + "electronics", + "enabled", + "forbidden", + "gadget", + "hardware", + "ios", + "line", + "mobile", + "mobile off", + "mute", + "network", + "no ring", + "off", + "on", + "os", + "phone", + "phone off", + "portable", + "restricted", + "signal", + "silence", + "silent", + "slash", + "tablet", + "technology", + "unavailable" + ], + "popularity": 1363 + }, + "MOBILE_SCREEN_SHARE": { + "tags": [ + "access", + "android", + "app", + "application", + "broadcast", + "cast", + "casting", + "cell", + "connect", + "connection", + "data", + "device", + "direct link", + "display", + "hardware", + "instant access", + "ios", + "link", + "mirror", + "mirroring", + "mobile", + "monitor", + "network", + "os", + "output", + "phone", + "projection", + "quick launch", + "screen", + "screen share", + "screencast", + "share", + "shortcut", + "stream", + "streaming", + "tablet", + "transmit", + "tv", + "wireless" + ], + "popularity": 2915 + }, + "MOBILEDATA_OFF": { + "tags": [ + "arrow", + "cellular", + "cellular connection off", + "cellular data off", + "cellular network off", + "connection lost", + "connectivity off", + "cross", + "data", + "data disabled", + "data disconnected", + "data usage", + "diagonal line", + "disabled", + "disconnection", + "down", + "enabled", + "internet", + "internet off", + "line", + "mobile", + "mobile data off", + "mobile network off", + "network", + "network disconnected", + "network off", + "network status", + "no connection", + "no data", + "no internet", + "off", + "offline", + "on", + "phone signal off", + "slash", + "speed", + "triangle", + "up", + "wifi", + "wireless" + ], + "popularity": 3130 + }, + "MODE": { + "tags": [ + "action", + "alter", + "author", + "change", + "compose", + "control", + "create", + "document", + "draft", + "draw", + "edit", + "form", + "glyph", + "input", + "mode", + "mode_edit", + "mode_edit_outline", + "modify", + "outline", + "pen", + "pencil", + "revise", + "shape", + "stroke", + "text", + "tool", + "update", + "write", + "writing" + ], + "popularity": 12970 + }, + "MODE_COMMENT": { + "tags": [ + "balloon", + "bubble", + "cartoon", + "chat", + "chat bubble", + "comic", + "comment", + "comment bubble", + "communicate", + "communication", + "communication mode", + "conversation", + "conversation mode", + "dialog", + "dialogue", + "discussion", + "feedback", + "graphic", + "icon", + "instant message", + "message", + "mode", + "mode comment", + "online chat", + "pointer", + "rectangular", + "rounded corner", + "speak", + "speech", + "speech bubble", + "symbol", + "talk", + "text", + "thought bubble", + "triangle" + ], + "popularity": 12388 + }, + "MODE_EDIT": { + "tags": [ + "action", + "alter", + "author", + "change", + "compose", + "control", + "create", + "document", + "draft", + "draw", + "edit", + "form", + "glyph", + "input", + "mode", + "mode_edit", + "mode_edit_outline", + "modify", + "outline", + "pen", + "pencil", + "revise", + "shape", + "stroke", + "text", + "tool", + "update", + "write", + "writing" + ], + "popularity": 52412 + }, + "MODE_EDIT_OUTLINE": { + "tags": [ + "action", + "alter", + "author", + "change", + "compose", + "control", + "create", + "document", + "draft", + "draw", + "edit", + "form", + "glyph", + "input", + "mode", + "mode_edit", + "mode_edit_outline", + "modify", + "outline", + "pen", + "pencil", + "revise", + "shape", + "stroke", + "text", + "tool", + "update", + "write", + "writing" + ], + "popularity": 11101 + }, + "MODE_FAN_OFF": { + "tags": [ + "air", + "air conditioner", + "angular", + "appliance", + "blades", + "circle", + "climate", + "controls", + "cool", + "cooling", + "disable", + "disabled", + "electrical", + "enabled", + "fan", + "household", + "inactive", + "lines", + "machinery", + "mode", + "nest", + "nonoperational", + "off", + "on", + "power", + "propeller", + "radial", + "rotating", + "settings", + "slash", + "stop", + "symbol", + "toggle", + "ventilation", + "weather" + ], + "popularity": 1316 + }, + "MODE_NIGHT": { + "tags": [ + "adjust", + "adjustment", + "brightness", + "contrast", + "control", + "crescent", + "dark", + "dim", + "display", + "disturb", + "icon", + "interface", + "light", + "lunar", + "mode", + "moon", + "night", + "screen", + "setting", + "sleep", + "switch", + "symbol", + "theme", + "toggle", + "ui element", + "view", + "visibility", + "visual" + ], + "popularity": 6745 + }, + "MODE_OF_TRAVEL": { + "tags": [ + "adventure", + "air", + "arrow", + "bicycle", + "choice", + "commute", + "destination", + "direction", + "driving", + "explore", + "get around", + "journey", + "location", + "mapping", + "maps", + "means", + "method", + "mobility", + "mode", + "movement", + "navigation", + "of", + "options", + "path", + "pedestrian", + "pin", + "place", + "rail", + "road", + "route", + "stop", + "transit", + "transport", + "transportation", + "travel", + "trip", + "vehicle", + "water", + "way" + ], + "popularity": 2596 + }, + "MODE_STANDBY": { + "tags": [ + "button", + "control", + "control element", + "device", + "disturb", + "electronics", + "energy saver", + "energy saving", + "icon", + "idle", + "inactive", + "interface", + "mode", + "mode standby", + "on/off", + "pause", + "power", + "power button", + "power off", + "power on", + "sleep", + "standby", + "standby mode", + "stop", + "suspend", + "switch", + "symbol", + "system", + "system control", + "target", + "toggle", + "ui element" + ], + "popularity": 3765 + }, + "MODEL_TRAINING": { + "tags": [ + "ai", + "algorithm", + "analysis", + "arrow", + "artificial intelligence", + "brain", + "bulb", + "computation", + "connection", + "data modeling", + "data science", + "deep learning", + "development", + "digital", + "futuristic", + "idea", + "innovation", + "inprogress", + "intelligence", + "learning", + "light", + "link", + "load", + "loading", + "machine learning", + "mind", + "ml", + "model", + "network", + "neural network", + "node", + "processing", + "progress", + "refresh", + "renew", + "restore", + "reverse", + "rotate", + "science", + "smart", + "system", + "technology", + "training" + ], + "popularity": 13670 + }, + "MONETIZATION_ON": { + "tags": [ + "activate", + "active", + "arrows", + "beginning", + "bill", + "business", + "card", + "cash", + "circle", + "coin", + "commerce", + "cost", + "credit", + "currency", + "cyclical", + "dollar", + "dollars", + "earn", + "enabled", + "finance", + "financial", + "income", + "initiate", + "monetization", + "money", + "on", + "ongoing", + "online", + "pay", + "payment", + "recurring", + "revenue", + "shopping", + "start", + "symbol", + "trade", + "transaction" + ], + "popularity": 49878 + }, + "MONEY": { + "tags": [ + "100", + "accounting", + "banking", + "bill", + "budget", + "card", + "cash", + "coin", + "commerce", + "cost", + "credit", + "currency", + "deposit", + "digit", + "dollar", + "dollars", + "economy", + "finance", + "financial", + "fund", + "investment", + "money", + "numbers", + "online", + "pay", + "payment", + "price", + "purchase", + "rate", + "revenue", + "savings", + "shopping", + "symbol", + "transaction", + "value", + "wealth", + "withdrawal" + ], + "popularity": 11706 + }, + "MONEY_OFF": { + "tags": [ + "bill", + "blocked", + "card", + "cart", + "cash", + "cheap", + "circle", + "coin", + "commerce", + "cost", + "credit", + "cross", + "currency", + "debt", + "denied", + "diagonal line", + "disabled", + "discount", + "dollars", + "enabled", + "expense", + "forbidden", + "free", + "funds", + "invalid", + "loss", + "money", + "no cash", + "no money", + "off", + "on", + "online", + "outline", + "paid", + "pay", + "payment", + "price", + "rejected", + "shopping", + "slash", + "symbol", + "unavailable", + "zero" + ], + "popularity": 8396 + }, + "MONEY_OFF_CSRED": { + "tags": [ + "bill", + "blocked", + "card", + "cart", + "cash", + "cheap", + "circle", + "coin", + "commerce", + "cost", + "credit", + "cross", + "csred", + "currency", + "debt", + "denied", + "diagonal line", + "disabled", + "discount", + "dollars", + "enabled", + "expense", + "forbidden", + "free", + "funds", + "invalid", + "loss", + "money", + "no cash", + "no money", + "off", + "on", + "online", + "outline", + "paid", + "pay", + "payment", + "price", + "rejected", + "shopping", + "slash", + "symbol", + "unavailable", + "zero" + ], + "popularity": 3984 + }, + "MONITOR": { + "tags": [ + "android", + "base", + "chrome", + "communication", + "computer", + "dashboard", + "data", + "desktop", + "device", + "display", + "electronic", + "electronic device", + "gadget", + "hardware", + "home", + "ios", + "mac", + "media", + "monitor", + "office", + "os", + "output", + "peripheral", + "presentation", + "rectangle", + "screen", + "stand", + "technology", + "television", + "tv", + "video", + "viewing", + "web", + "window", + "work" + ], + "popularity": 5795 + }, + "MONITOR_HEART": { + "tags": [ + "baseline", + "cardiogram", + "care", + "computer", + "device", + "diagnostics", + "digital health", + "display", + "doctor", + "ecc", + "ecg", + "ekg", + "electronics", + "fitness", + "health", + "health check", + "health data", + "health monitoring", + "health status", + "healthcare", + "heart", + "heartbeat", + "hospital", + "life", + "medical", + "medical device", + "monitor", + "patient", + "pulse", + "screen", + "technology", + "track", + "vital signs", + "wellness" + ], + "popularity": 13642 + }, + "MONITOR_WEIGHT": { + "tags": [ + "accuracy", + "analysis", + "balance", + "body", + "body composition", + "body weight", + "calibration", + "check", + "data", + "device", + "diet", + "digital scale", + "fitness", + "health", + "impedance", + "kilogram", + "measure", + "measurement", + "medical", + "monitor", + "monitoring", + "pound", + "precision", + "progress", + "reading", + "report", + "scale", + "smart", + "smart scale", + "track", + "weight", + "wellness" + ], + "popularity": 7399 + }, + "MONOCHROME_PHOTOS": { + "tags": [ + "album", + "black", + "black and white", + "camera", + "collection", + "digital media", + "editing", + "effect", + "filter", + "gallery", + "grayscale", + "image", + "library", + "media", + "monochrome", + "multimedia", + "multiple photos", + "organize", + "photo", + "photograph", + "photography", + "photos", + "picture", + "snapshot", + "square", + "stack", + "view", + "visual", + "white" + ], + "popularity": 1530 + }, + "MOOD": { + "tags": [ + "add", + "character", + "chat", + "cheerful", + "circle", + "communication", + "emoji", + "emoticon", + "emotion", + "emotions", + "expression", + "expressions", + "face", + "feeling", + "feelings", + "glad", + "grin", + "happiness", + "happy", + "insert", + "joy", + "like", + "message", + "mood", + "outline", + "person", + "pleased", + "reaction", + "round", + "select", + "smile", + "smiley", + "smiling", + "social", + "survey", + "symbol", + "tag", + "text" + ], + "popularity": 15514 + }, + "MOOD_BAD": { + "tags": [ + "avatar", + "bad", + "circle", + "circular", + "disappointment", + "dislike", + "distress", + "emoji", + "emotion", + "emotions", + "expression", + "expressions", + "face", + "feeling", + "feelings", + "frown", + "frowny face", + "glyph", + "icon", + "illustration", + "mood", + "negative", + "person", + "rating", + "sad", + "sad face", + "social", + "solid", + "sorrow", + "survey", + "symbol", + "unhappiness", + "unhappy", + "unhappy face", + "unpleased", + "unsmile", + "unsmiling", + "upset" + ], + "popularity": 9831 + }, + "MOPED": { + "tags": [ + "automobile", + "bike", + "buy", + "car", + "cars", + "commerce", + "courier", + "delivery", + "dining", + "dispatch", + "driving", + "drop off", + "fast", + "food", + "line icon", + "logistics", + "maps", + "moped", + "motorcycle", + "movement", + "order", + "pick up", + "purchase", + "quick", + "riding", + "scooter", + "service", + "shipping", + "shop", + "store", + "transport", + "transportation", + "travel", + "two-wheeled", + "urban", + "vehicle", + "vespa" + ], + "popularity": 3692 + }, + "MORE": { + "tags": [ + "3", + "action", + "additional", + "archive", + "bookmark", + "button", + "circle", + "content", + "context", + "control", + "details", + "dots", + "ellipsis", + "etc", + "expand", + "extra", + "favorite", + "icon", + "indent", + "information", + "label", + "list", + "menu", + "menu item", + "more", + "navigation", + "options", + "overflow", + "remember", + "reveal", + "rounded", + "save", + "secondary", + "settings", + "stamp", + "sticker", + "tab", + "tag", + "tertiary", + "three", + "three dots", + "vertical" + ], + "popularity": 10314 + }, + "MORE_HORIZ": { + "tags": [ + "3", + "actions", + "additional", + "app", + "application", + "bar menu", + "button", + "choices", + "components", + "content menu", + "context menu", + "control", + "disable_ios", + "dots", + "dropdown", + "edit", + "ellipsis", + "etc", + "expand", + "further", + "horiz", + "horizontal", + "indicator", + "interface", + "ios", + "kebab menu", + "manage", + "menu", + "more", + "options", + "overflow", + "preference", + "reveal", + "screen", + "see more", + "selection", + "settings", + "show more", + "site", + "three", + "three dots", + "tool", + "ui", + "ux", + "web", + "website" + ], + "popularity": 103773 + }, + "MORE_TIME": { + "tags": [ + "+", + "add", + "add time", + "alarm", + "appointment", + "calendar", + "chronometer", + "circle", + "clock", + "countdown", + "date", + "duration", + "event", + "extend time", + "hands of clock", + "hours", + "increase time", + "minutes", + "more", + "more time", + "new", + "planning", + "plus", + "plus time", + "reminder", + "schedule", + "seconds", + "stopwatch", + "symbol", + "time", + "time management", + "timekeeper", + "timer", + "timing", + "watch" + ], + "popularity": 12699 + }, + "MORE_VERT": { + "tags": [ + "3", + "actions", + "additional options", + "android", + "app", + "application", + "components", + "context menu", + "controls", + "detail menu", + "disable_ios", + "dots", + "dropdown menu", + "ellipsis", + "etc", + "expand menu", + "expanded menu", + "extra options", + "hidden options", + "interface", + "list menu", + "list options", + "menu", + "more", + "more actions", + "more options", + "options menu", + "overflow", + "overflow menu", + "pop-up menu", + "screen", + "settings", + "site", + "submenu", + "tertiary actions", + "three", + "ui", + "ux", + "vert", + "vertical", + "vertical dots", + "web", + "website" + ], + "popularity": 151331 + }, + "MOSQUE": { + "tags": [ + "architecture", + "building", + "dome", + "faith", + "holy place", + "ideology", + "islam", + "islamic", + "islamic architecture", + "islamic art", + "islamic culture", + "islamic history", + "landmark", + "masjid", + "middle east", + "minaret", + "mosque", + "muslim", + "orient", + "pilgrimage", + "prayer", + "ramadan", + "religion", + "religious building", + "sanctuary", + "spiritual", + "structure", + "temple", + "tourism", + "travel", + "worship" + ], + "popularity": 2171 + }, + "MOTION_PHOTOS_AUTO": { + "tags": [ + "a", + "advanced photo", + "alphabet", + "animation", + "auto", + "auto play", + "automatic", + "camera", + "capture", + "character", + "cinematic", + "circle", + "creative photo", + "digital media", + "dot", + "enhanced photo", + "feature", + "font", + "gif", + "interface", + "letters", + "lines", + "live", + "live photo", + "live view", + "motion", + "motion photos auto", + "moving image", + "multimedia", + "option", + "photography", + "photos", + "play", + "recording", + "settings", + "smart photo", + "symbol", + "technology", + "text", + "type", + "video" + ], + "popularity": 2529 + }, + "MOTION_PHOTOS_OFF": { + "tags": [ + "animated", + "animation", + "block", + "camera", + "cancel", + "capture", + "circle", + "circle with line", + "deny", + "diagonal line", + "disable", + "disabled", + "enabled", + "image", + "line", + "live", + "live photo", + "media", + "motion", + "motion photo", + "off", + "on", + "photo", + "photography", + "photos", + "picture", + "recording", + "slash", + "snapshot", + "stop", + "toggle off", + "video", + "visual" + ], + "popularity": 1232 + }, + "MOTION_PHOTOS_ON": { + "tags": [ + "active", + "animation", + "camera", + "capture", + "circle", + "content", + "digital", + "disabled", + "enable", + "enabled", + "feature", + "film", + "function", + "image", + "live", + "media", + "motion", + "movement", + "movie", + "moving", + "multimedia", + "off", + "on", + "photo", + "photography", + "photos", + "picture", + "play", + "playback", + "record", + "recording", + "setting", + "slash", + "technology", + "video", + "visual" + ], + "popularity": 3565 + }, + "MOTION_PHOTOS_PAUSE": { + "tags": [ + "action", + "animation", + "button", + "camera", + "capture", + "circle", + "control", + "frame", + "freeze frame", + "halt", + "icon", + "interaction", + "live photo", + "live photos", + "media", + "media control", + "moment", + "motion", + "motion photo", + "motion photos", + "pause", + "paused", + "photography", + "photos", + "playback", + "playback control", + "still", + "still image", + "stop", + "symbol", + "video", + "video control" + ], + "popularity": 1232 + }, + "MOTION_PHOTOS_PAUSED": { + "tags": [ + "action", + "animation", + "button", + "camera", + "capture", + "circle", + "control", + "frame", + "freeze frame", + "halt", + "icon", + "interaction", + "live photo", + "live photos", + "media", + "media control", + "moment", + "motion", + "motion photo", + "motion photos", + "pause", + "paused", + "photography", + "photos", + "playback", + "playback control", + "still", + "still image", + "stop", + "symbol", + "video", + "video control" + ], + "popularity": 1535 + }, + "MOUSE": { + "tags": [ + "action", + "click", + "computer", + "computing", + "control", + "cursor", + "desktop", + "device", + "digital", + "hardware", + "input", + "interaction", + "laptop", + "minimal", + "mouse", + "navigation", + "object", + "outline", + "peripheral", + "pointer", + "pointing device", + "scrolling", + "select", + "shape", + "simple", + "technology", + "touchscreen", + "trackpad", + "wireless" + ], + "popularity": 11202 + }, + "MOVE_DOWN": { + "tags": [ + "action", + "arrow", + "arrow down", + "arrow head", + "basic", + "button", + "command", + "control", + "direction", + "down", + "downwards", + "essential", + "geometric", + "indicator", + "interface", + "jump", + "line", + "move", + "move down", + "movement", + "navigate down", + "navigation", + "pointer", + "pointing down", + "scroll", + "scroll down", + "shape", + "simple", + "symbol", + "transfer", + "ui element" + ], + "popularity": 3308 + }, + "MOVE_TO_INBOX": { + "tags": [ + "archive", + "arrow", + "box", + "communication", + "container", + "direction", + "down", + "email", + "email client", + "envelop", + "filing", + "folder", + "forward", + "inbox", + "incoming", + "into", + "letters", + "mail", + "mailing", + "message", + "messages", + "move", + "move to", + "organization", + "place", + "pointed", + "read", + "receive", + "received", + "relocate", + "send", + "sort", + "storage", + "transfer", + "unread" + ], + "popularity": 9670 + }, + "MOVE_UP": { + "tags": [ + "arrow", + "arrow head", + "ascend", + "direction", + "elevate", + "go to top", + "increase", + "indicator", + "jump", + "line", + "move", + "navigate up", + "navigation", + "point", + "pointer", + "position", + "raise", + "relocate", + "rise", + "scroll", + "shift", + "top", + "transfer", + "triangular", + "up", + "upward" + ], + "popularity": 3929 + }, + "MOVIE": { + "tags": [ + "capture", + "cinema", + "creation", + "digital", + "drive", + "edit", + "entertainment", + "file", + "film", + "media", + "movie", + "movie file", + "multimedia", + "play", + "play movie", + "play video", + "playback", + "record", + "recording", + "reel", + "slate", + "storage", + "video", + "video camera", + "video file", + "videotape", + "view", + "watch" + ], + "popularity": 26338 + }, + "MOVIE_CREATION": { + "tags": [ + "capture", + "cinema", + "clapperboard", + "creation", + "digital", + "drive", + "edit", + "entertainment", + "file", + "film", + "media", + "movie", + "movie file", + "movies", + "multimedia", + "play", + "play movie", + "play video", + "playback", + "record", + "recording", + "reel", + "slate", + "storage", + "video", + "video camera", + "video file", + "videotape", + "view", + "watch" + ], + "popularity": 4750 + }, + "MOVIE_FILTER": { + "tags": [ + "adjust", + "adjust video", + "ai", + "artificial", + "automatic", + "automation", + "camera", + "cinema", + "cinema filter", + "clapperboard", + "creation", + "custom", + "edit", + "effect", + "effects", + "enhance video", + "film", + "film filter", + "filter", + "genai", + "intelligence", + "magic", + "media", + "media filter", + "movie", + "movie effects", + "movie filter", + "movies", + "production", + "reel", + "settings", + "slate", + "smart", + "spark", + "sparkle", + "star", + "stars", + "studio", + "video", + "video editing", + "video effects", + "video filter" + ], + "popularity": 4601 + }, + "MOVING": { + "tags": [ + "action", + "active", + "activity", + "advancing", + "alive", + "animate", + "arrow", + "change", + "changing", + "direction", + "dynamic", + "evolving", + "flowing", + "forward", + "going", + "migration", + "motion", + "move", + "movement", + "moving", + "moving object", + "navigation", + "onward", + "potential tags could relate to:\n\nmoving", + "proceeding", + "progress", + "progression", + "relocate", + "shift", + "transferring", + "transition", + "transport", + "travel", + "up" + ], + "popularity": 8646 + }, + "MP": { + "tags": [ + "adjustment", + "alphabet", + "audio", + "audio output", + "button", + "character", + "control", + "dashboard", + "font", + "graphic", + "icon", + "image", + "interface", + "letters", + "level", + "low", + "media", + "megapixel", + "mp", + "multimedia", + "music", + "mute", + "options", + "output", + "photo", + "photography", + "pixels", + "player", + "quality", + "quiet", + "resolution", + "settings", + "silent", + "sound", + "speaker", + "symbol", + "text", + "toggle", + "type", + "ui control", + "voice", + "volume" + ], + "popularity": 793 + }, + "MULTILINE_CHART": { + "tags": [ + "analysis", + "analytics", + "axis", + "bar", + "bars", + "business", + "chart", + "coordinate system", + "data", + "diagram", + "graph", + "graph paper", + "grid", + "growth", + "infographic", + "information", + "line", + "line chart", + "measure", + "metrics", + "multiline chart", + "multiple", + "multiple lines", + "performance", + "plot", + "progress", + "reporting", + "representation", + "statistics", + "tracking", + "trend", + "visualization", + "x-axis", + "y-axis" + ], + "popularity": 3097 + }, + "MULTIPLE_STOP": { + "tags": [ + "action", + "arrows", + "audio", + "button", + "complete", + "control", + "controls", + "dash", + "dashed", + "directions", + "dots", + "double stop", + "end", + "final", + "finished", + "interface element", + "last", + "left", + "maps", + "media", + "multimedia", + "multiple", + "multiple stop", + "music", + "navigation", + "pause", + "playback", + "playback control", + "player", + "player control", + "right", + "skip to end", + "square", + "stop", + "symbol", + "two squares", + "video" + ], + "popularity": 6177 + }, + "MUSEUM": { + "tags": [ + "ancient", + "architecture", + "art", + "artifact", + "attraction", + "building", + "collection", + "columns", + "corinthian", + "culture", + "destination", + "doric", + "education", + "estate", + "event", + "exhibit", + "exhibition", + "exploration", + "explore", + "gallery", + "historic", + "history", + "ionic", + "knowledge", + "landmark", + "learning", + "local", + "monument", + "museum", + "neoclassical", + "pillars", + "places", + "real", + "see", + "shop", + "store", + "structure", + "tour", + "tourism", + "travel" + ], + "popularity": 5530 + }, + "MUSIC_NOTE": { + "tags": [ + "audio", + "audio file", + "audio icon", + "audiotrack", + "clef", + "composition", + "eighth note", + "key", + "listen", + "media", + "media controls", + "melody", + "music", + "music icon", + "musical", + "note", + "play", + "player", + "playlist", + "quaver", + "rhythm", + "score", + "song", + "sound", + "sound icon", + "track", + "tune", + "waveform" + ], + "popularity": 29064 + }, + "MUSIC_OFF": { + "tags": [ + "audio", + "audio off", + "audiotrack", + "block", + "blocked music", + "cross out", + "disable", + "disabled", + "disabled music", + "enabled", + "forbid", + "forbidden music", + "key", + "media", + "media control", + "music", + "music control", + "music disabled", + "music off", + "mute", + "mute audio", + "mute music", + "mute sound", + "mute volume", + "no audio", + "no music", + "no sound", + "note", + "off", + "on", + "quiet", + "silence", + "silent", + "slash", + "slashed music", + "sound", + "sound off", + "track", + "volume", + "volume off" + ], + "popularity": 3006 + }, + "MUSIC_VIDEO": { + "tags": [ + "band", + "broadcast", + "camera", + "cinema", + "clip", + "display", + "entertainment", + "film", + "footage", + "live", + "media", + "movie", + "multimedia", + "music", + "music video", + "pause", + "play", + "player", + "production", + "record", + "recording", + "reel", + "screen", + "streaming", + "studio", + "theatre", + "tv", + "video", + "video camera", + "video screen", + "view", + "watch" + ], + "popularity": 2668 + }, + "MY_LOCATION": { + "tags": [ + "area", + "center location", + "circle", + "compass", + "coordinates", + "current location", + "destination", + "detection", + "direction", + "find location", + "fixed location", + "geographic", + "geolocate", + "gps", + "locate me", + "location", + "map", + "maps", + "marker", + "my location", + "navigation", + "pin", + "pinpoint", + "place", + "point", + "position", + "precise", + "spot", + "stop", + "target location", + "track location", + "user location", + "where am i" + ], + "popularity": 33050 + }, + "NAT": { + "tags": [ + "atlas", + "borders", + "boundaries", + "cartography", + "circle", + "circular", + "communication", + "continents", + "country", + "destination", + "earth", + "flag", + "geography", + "global", + "globe", + "government", + "international", + "landmass", + "map", + "nat", + "nation", + "national", + "planet", + "politics", + "rounded", + "sphere", + "state", + "tourism", + "travel", + "world" + ], + "popularity": 1502 + }, + "NATURE": { + "tags": [ + "biology", + "bloom", + "botanical", + "botany", + "branch", + "eco", + "ecology", + "environment", + "environmental", + "floral", + "flourish", + "foliage", + "forest", + "garden", + "gardening", + "green", + "grow", + "growth", + "leaf", + "leaves", + "life", + "natural", + "nature", + "organic", + "outdoor", + "outside", + "park", + "plant", + "sprout", + "stem", + "tree", + "vegetation", + "wilderness" + ], + "popularity": 4093 + }, + "NATURE_PEOPLE": { + "tags": [ + "activity", + "adventure", + "body", + "camping", + "community", + "environment", + "exploring", + "figures", + "forest", + "gathering", + "green", + "group", + "hiking", + "human", + "landscape", + "mountain", + "natural", + "nature", + "outdoor", + "outdoors", + "outside", + "park", + "people", + "person", + "recreation", + "silhouette", + "together", + "trail", + "tree", + "trees", + "walking", + "wilderness" + ], + "popularity": 6285 + }, + "NAVIGATE_BEFORE": { + "tags": [ + "angle", + "arrow", + "arrows", + "back", + "backward", + "before", + "caret", + "carousel", + "chevron", + "direction", + "directional", + "go back", + "history", + "indicator", + "left", + "less than", + "media control", + "move left", + "navigate", + "navigation", + "page", + "pagination", + "pointer", + "previous", + "prior", + "retreat", + "return", + "rewind", + "scroll", + "slider", + "step back" + ], + "popularity": 37574 + }, + "NAVIGATE_NEXT": { + "tags": [ + "advance", + "angle", + "arrow", + "arrows", + "bracket", + "caret", + "carousel", + "chevron", + "continue", + "direction", + "drilldown", + "entry", + "expand", + "forward", + "go", + "greater than", + "indicator", + "item", + "link", + "list", + "menu", + "more", + "move", + "navigate", + "next", + "pagination", + "pointer", + "proceed", + "right", + "show", + "slider" + ], + "popularity": 121391 + }, + "NAVIGATION": { + "tags": [ + "arrow", + "compass", + "course", + "destination", + "direction", + "directions", + "discovery", + "explore", + "find", + "gps", + "guide", + "journey", + "locate", + "location", + "map", + "maps", + "mark", + "menu", + "navigation", + "orientation", + "path", + "pin", + "place", + "point", + "pointer", + "position", + "road", + "route", + "search", + "site", + "stop", + "track", + "travel", + "wayfinding" + ], + "popularity": 13207 + }, + "NEAR_ME": { + "tags": [ + "area", + "arrow", + "compass", + "current location", + "destination", + "direction", + "directions", + "discover", + "explore", + "find", + "geolocation", + "geotagging", + "local", + "locate", + "locate me", + "locate user", + "location", + "maps", + "me", + "my location", + "navigation", + "near", + "nearby", + "neighborhood", + "pin", + "pinpoint", + "place", + "point", + "pointer", + "points of interest", + "position", + "precise", + "precise location", + "stop", + "travel", + "vicinity" + ], + "popularity": 28295 + }, + "NEAR_ME_DISABLED": { + "tags": [ + "blocked", + "compass blocked", + "compass disabled", + "compass off", + "destination", + "direction", + "direction blocked", + "direction disabled", + "direction off", + "disabled", + "enabled", + "geo blocked", + "geo disabled", + "geo off", + "gps blocked", + "gps disabled", + "gps off", + "location", + "location blocked", + "location disabled", + "location off", + "map blocked", + "map disabled", + "map off", + "maps", + "me", + "navigation", + "navigation blocked", + "navigation disabled", + "navigation off", + "near", + "near me blocked", + "near me disabled", + "near me off", + "off", + "on", + "pin", + "place", + "point", + "position blocked", + "position disabled", + "position off", + "slash" + ], + "popularity": 1415 + }, + "NEARBY_ERROR": { + "tags": [ + "!", + "alert", + "attention", + "caution", + "communication", + "connection", + "danger", + "detection", + "error", + "exclamation", + "failure", + "geometry", + "important", + "indication", + "issue", + "location", + "mark", + "message", + "nearby", + "network", + "notification", + "pinpoint", + "point", + "problem", + "proximity", + "range", + "shape", + "signal", + "status", + "symbol", + "triangle", + "trouble", + "warning" + ], + "popularity": 1873 + }, + "NEARBY_OFF": { + "tags": [ + "area", + "circle", + "close", + "connected off", + "connection", + "cross out", + "detection", + "disabled", + "discover off", + "dot", + "enabled", + "inactive", + "line", + "location off", + "marker", + "near", + "nearby", + "nearby off", + "not active", + "not connected", + "off", + "offline", + "on", + "point", + "proximity off", + "range off", + "scanner off", + "searching off", + "signal", + "slash", + "slashed", + "unavailable", + "vicinity" + ], + "popularity": 685 + }, + "NEST_CAM_WIRED_STAND": { + "tags": [ + "bedroom", + "camera", + "camera on stand", + "cctv", + "device", + "electronic device", + "electronics", + "film", + "filming", + "gadget", + "hardware", + "home automation", + "home security", + "image", + "indoor camera", + "ip camera", + "living room", + "monitoring", + "motion", + "nest", + "nest cam", + "observe", + "office", + "picture", + "record", + "security camera", + "security device", + "smart camera", + "smart home", + "stand", + "surveillance", + "technology", + "video", + "video recording", + "videography", + "watch", + "wired" + ], + "popularity": 735 + }, + "NETWORK_CELL": { + "tags": [ + "bars", + "cell", + "cellular", + "communications", + "connection", + "connectivity", + "data", + "full signal", + "increasing signal", + "indicator", + "internet", + "level", + "mobile", + "network", + "phone", + "pyramid", + "reception", + "signal", + "speed", + "stacked", + "status", + "stepped", + "strength", + "strong signal", + "telecommunications", + "tiered", + "triangle", + "wifi", + "wireless" + ], + "popularity": 3114 + }, + "NETWORK_CHECK": { + "tags": [ + "check", + "confirmed", + "connect", + "connected", + "connection", + "connection check", + "connectivity", + "data", + "good", + "internet", + "internet check", + "internet connection", + "mark", + "meter", + "network", + "network status", + "network test", + "ok", + "signal", + "signal check", + "signal strength", + "speed", + "status", + "tick", + "valid", + "valid connection", + "verified", + "wifi", + "wireless", + "wireless connection" + ], + "popularity": 5367 + }, + "NETWORK_LOCKED": { + "tags": [ + "access", + "alert", + "available", + "cellular", + "chain", + "connection", + "data", + "data locked", + "disconnect", + "error", + "internet", + "limited", + "lock", + "locked", + "mobile", + "network", + "network access", + "network problem", + "network signal", + "not", + "offline", + "privacy", + "private", + "prohibition", + "protected", + "protection", + "restricted", + "restricted access", + "safety", + "secure", + "secure connection", + "security", + "service", + "signal", + "status", + "unavailable", + "warning", + "wi-fi", + "wifi", + "wifi locked", + "wireless" + ], + "popularity": 1440 + }, + "NETWORK_PING": { + "tags": [ + "alert", + "antenna", + "available", + "bars", + "cellular", + "communication", + "connection", + "data", + "data signal", + "diagnostic", + "four bars", + "indicator", + "internet", + "ip", + "latency", + "mobile", + "network", + "network connectivity", + "network status", + "performance", + "ping", + "quality", + "radio waves", + "reception", + "service", + "signal", + "speed", + "status", + "strength", + "technology", + "test", + "three bars", + "waves", + "wifi", + "wireless" + ], + "popularity": 1673 + }, + "NETWORK_WIFI": { + "tags": [ + "access", + "antenna", + "arcs", + "available", + "bars", + "broadcast", + "cell", + "cellular", + "communication", + "computer", + "connection", + "connectivity", + "curves", + "data", + "device", + "hotspot", + "indicator", + "internet", + "internet access", + "mobile", + "network", + "offline", + "online", + "phone", + "private wifi", + "public wifi", + "radio", + "signal", + "speed", + "status", + "strength", + "technology", + "waves", + "wifi", + "wireless" + ], + "popularity": 5417 + }, + "NETWORK_WIFI_1_BAR": { + "tags": [ + "access point", + "antenna", + "bar", + "cell", + "cellular", + "communication", + "communication link", + "connection", + "connectivity", + "connectivity status", + "data", + "internet", + "less strength", + "limited connectivity", + "low signal", + "low signal strength", + "low strength", + "mobile", + "network", + "network status", + "one bar", + "phone", + "radio waves", + "signal", + "signal indicator", + "single bar", + "speed", + "strength", + "transmission", + "weak signal", + "wifi", + "wifi network", + "wifi symbol", + "wireless", + "wireless network" + ], + "popularity": 1520 + }, + "NETWORK_WIFI_2_BAR": { + "tags": [ + "access point", + "antenna", + "arc", + "bars", + "broadcast", + "cell", + "cellular", + "communication", + "connection", + "connectivity", + "data", + "hot spot", + "internet", + "limited signal", + "mobile", + "network", + "partial signal", + "phone", + "radio waves", + "receive", + "signal", + "speed", + "strength", + "technology", + "transmit", + "two bars", + "wave", + "weak signal", + "wifi", + "wireless", + "wlan" + ], + "popularity": 1228 + }, + "NETWORK_WIFI_3_BAR": { + "tags": [ + "access", + "antenna", + "arc", + "bars", + "cell", + "cellular", + "communication", + "connected", + "connection", + "connectivity", + "curved", + "data", + "full", + "indicator", + "information", + "internet", + "level", + "mobile", + "modem", + "network", + "online", + "phone", + "router", + "signal", + "speed", + "status", + "strength", + "symbol", + "technology", + "three bars", + "waves", + "wifi", + "wireless" + ], + "popularity": 1431 + }, + "NEW_LABEL": { + "tags": [ + "+", + "add", + "archive", + "badge", + "banner", + "bookmark", + "category", + "classification", + "create", + "description", + "details", + "discount", + "element", + "emphasis", + "favorite", + "highlight", + "identification", + "information", + "item", + "label", + "library", + "marker", + "new", + "offer", + "plus", + "price tag", + "product", + "promotion", + "read", + "reading", + "remember", + "ribbon", + "sale", + "save", + "sign", + "sticker", + "symbol", + "tag", + "topic" + ], + "popularity": 6241 + }, + "NEW_RELEASES": { + "tags": [ + "accepted", + "accreditation", + "approval", + "approval icon", + "approve", + "authentic", + "authorized", + "badge", + "burst", + "certified", + "check", + "checkmark", + "checkmark in circle", + "complete", + "completed", + "confirmation", + "confirmed", + "credentials", + "done", + "green checkmark", + "identity", + "legitimacy", + "mark", + "official", + "ok", + "registered", + "select", + "stamp of approval", + "star", + "success", + "tick", + "trusted", + "valid", + "validate", + "verified", + "verified account", + "verified user", + "yes" + ], + "popularity": 24289 + }, + "NEWSPAPER": { + "tags": [ + "article", + "book", + "communication", + "current events", + "daily", + "data", + "doc", + "document", + "drive", + "file", + "folder", + "folders", + "headline", + "information", + "journalism", + "lines", + "magazine", + "media", + "news", + "newspaper", + "notes", + "page", + "pages", + "paper", + "press", + "print", + "publication", + "reading", + "rectangle", + "report", + "sheet", + "slide", + "square", + "text", + "update", + "writing" + ], + "popularity": 19522 + }, + "NEXT_PLAN": { + "tags": [ + "agenda", + "arrow", + "blueprint", + "business", + "calendar", + "circle", + "direction", + "document", + "draft", + "file", + "forward", + "future", + "management", + "move", + "next", + "notes", + "office", + "organization", + "page", + "plan", + "planning", + "progress", + "project", + "right", + "right arrow", + "schedule", + "sheet", + "task", + "text", + "work" + ], + "popularity": 7926 + }, + "NEXT_WEEK": { + "tags": [ + "agenda", + "appointment", + "arrow", + "bag", + "baggage", + "box", + "briefcase", + "business", + "button", + "calendar", + "case", + "control", + "date", + "deadline", + "diagonal line", + "event", + "forward", + "future", + "horizontal lines", + "icon", + "lines", + "navigation", + "next", + "organize", + "planning", + "rectangle", + "reminder", + "schedule", + "square", + "suitcase", + "symbol", + "time", + "week" + ], + "popularity": 3889 + }, + "NFC": { + "tags": [ + "access", + "button", + "communication", + "connect", + "contactless", + "data", + "device", + "element", + "field", + "graphic", + "icon", + "interaction", + "logo", + "mobile", + "near", + "near field communication", + "network", + "nfc", + "option", + "payment", + "phone", + "radio", + "setting", + "share", + "signal", + "symbol", + "tap", + "technology", + "transfer", + "transmit", + "waves", + "wireless" + ], + "popularity": 3864 + }, + "NIGHT_SHELTER": { + "tags": [ + "abode", + "accommodation", + "architecture", + "assistance", + "bed", + "building", + "dormitory", + "dwelling", + "emergency", + "estate", + "facade", + "guesthouse", + "help", + "home", + "homeless", + "hostel", + "hotel", + "house", + "housing", + "lodging", + "night", + "place", + "protection", + "real", + "refuge", + "residence", + "residential", + "roof", + "safety", + "shelter", + "sleep", + "sleeping", + "stay", + "structure", + "support", + "temporary" + ], + "popularity": 5259 + }, + "NIGHTLIFE": { + "tags": [ + "activity", + "alcohol", + "bar", + "beer", + "beverage", + "bottle", + "celebrate", + "cheers", + "club", + "cocktail", + "dance", + "disco", + "drink", + "drinks", + "entertainment", + "evening", + "event", + "food", + "fun", + "gathering", + "glass", + "happy hour", + "leisure", + "liquor", + "lounge", + "music", + "night", + "nightlife", + "note", + "party", + "pub", + "recreation", + "social", + "toast", + "wine" + ], + "popularity": 5390 + }, + "NIGHTLIGHT": { + "tags": [ + "astronomy", + "bedtime", + "brightness", + "celestial", + "circle", + "crescent", + "dark", + "display", + "disturb", + "filled", + "graphic", + "icon", + "light", + "mode", + "moon", + "night", + "nightlight", + "round", + "setting", + "shape", + "sky", + "sleep", + "star", + "stars", + "symbol", + "theme", + "toggle", + "view" + ], + "popularity": 11228 + }, + "NIGHTLIGHT_ROUND": { + "tags": [ + "astronomy", + "bedtime", + "brightness", + "celestial", + "circle", + "crescent", + "dark", + "display", + "filled", + "graphic", + "half", + "icon", + "light", + "mode", + "moon", + "night", + "nightlight", + "round", + "setting", + "shape", + "sky", + "sleep", + "star", + "stars", + "symbol", + "theme", + "toggle", + "view" + ], + "popularity": 19687 + }, + "NIGHTS_STAY": { + "tags": [ + "astronomy", + "atmosphere", + "bedroom", + "climate", + "cloud", + "cloudy", + "crescent", + "dark", + "dreams", + "evening", + "forecast", + "hotel", + "lodging", + "lunar", + "meteorology", + "mode", + "moon", + "nature", + "night", + "nights", + "nighttime", + "outdoors", + "partly", + "phases", + "rest", + "silence", + "silent", + "sky", + "sleep", + "stay", + "time", + "travel", + "trip", + "vacation", + "weather" + ], + "popularity": 8845 + }, + "NO_ACCOUNTS": { + "tags": [ + "access", + "access denied", + "account", + "accounts", + "authentication", + "avatar", + "banned", + "blocked", + "cancelled", + "circle", + "denied", + "disabled", + "empty", + "enabled", + "excluded", + "face", + "forbidden", + "human", + "identity", + "invalid", + "line", + "login", + "missing", + "no", + "no accounts", + "none", + "off", + "offline", + "on", + "people", + "person", + "profile", + "profile picture", + "removed", + "restricted", + "slash", + "thumbnail", + "unauthorized", + "unavailable", + "unidentifiable", + "unknown", + "user", + "zero" + ], + "popularity": 11151 + }, + "NO_ADULT_CONTENT": { + "tags": [ + "access control", + "age rating", + "age restriction", + "block", + "censored", + "content restriction", + "disallowed", + "explicit content", + "filter", + "forbidden", + "inappropriate content", + "limit", + "mature", + "mature content", + "no entry", + "not suitable for minors", + "parental advisory", + "parental control", + "privacy", + "private", + "protection", + "rating", + "restricted", + "safety", + "secure", + "sensitive content", + "warning" + ], + "popularity": 792 + }, + "NO_BACKPACK": { + "tags": [ + "access denied", + "accessory", + "alert", + "backpack", + "bag", + "bookbag", + "caution", + "circle", + "denied", + "diagonal line", + "disallowed", + "excluded", + "forbidden", + "knapsack", + "line", + "luggage", + "no", + "not", + "not allowed", + "off limits", + "pack", + "prohibited", + "restriction", + "rucksack", + "slash", + "stop", + "travel", + "unavailable", + "warning" + ], + "popularity": 892 + }, + "NO_CELL": { + "tags": [ + "android", + "cell", + "device", + "disabled", + "enabled", + "hardware", + "ios", + "mobile", + "no", + "off", + "on", + "os", + "phone", + "slash", + "tablet" + ], + "popularity": 1164 + }, + "NO_CRASH": { + "tags": [ + "accident", + "alert", + "auto", + "automobile", + "avoid", + "barrier", + "blocked", + "car", + "cars", + "caution", + "check", + "collision", + "confirm", + "correct", + "crash", + "critical", + "danger", + "deny", + "direction", + "disallowed", + "done", + "eight sides", + "enter", + "error", + "fail", + "failure", + "forbidden", + "limit", + "maps", + "mark", + "no", + "no crash", + "octagon", + "ok", + "okay", + "prevention", + "prohibited", + "red light", + "refuse", + "reject", + "restricted", + "road sign", + "safe", + "security", + "select", + "stop", + "stop sign", + "tick", + "transportation", + "vehicle", + "warning", + "yes" + ], + "popularity": 1825 + }, + "NO_DRINKS": { + "tags": [ + "alcohol", + "alcoholic beverages", + "alert", + "bar", + "beverage", + "beverages", + "bottle", + "circle", + "cocktail", + "cup", + "diagonal line", + "drink", + "drinks", + "event", + "food", + "food and drink", + "forbidden", + "glass", + "liquid", + "liquor", + "no", + "no drinks", + "non-alcoholic beverages", + "not allowed", + "place", + "prohibited", + "prohibition", + "regulation", + "restaurant", + "restricted", + "restriction", + "rule", + "sign", + "slash", + "symbol", + "warning", + "wine" + ], + "popularity": 1488 + }, + "NO_ENCRYPTION": { + "tags": [ + "alert", + "blocked", + "cancel", + "data breach", + "data security", + "disabled", + "enabled", + "encryption", + "error", + "forbidden", + "insecure", + "internet security", + "lock", + "network security", + "no", + "no encryption", + "not allowed", + "off", + "on", + "open lock", + "padlock", + "password", + "privacy", + "private", + "protection", + "remove", + "safety", + "security", + "security breach", + "slash", + "stop", + "unauthorized access", + "unlock", + "unlocked", + "unprotected", + "unsecure", + "vulnerability", + "vulnerable", + "warning" + ], + "popularity": 3104 + }, + "NO_ENCRYPTION_GMAILERRORRED": { + "tags": [ + "alert", + "blocked", + "cancel", + "data breach", + "data security", + "disabled", + "enabled", + "encryption", + "error", + "forbidden", + "gmail", + "insecure", + "internet security", + "lock", + "locked", + "network security", + "no", + "no encryption", + "not allowed", + "off", + "on", + "open lock", + "padlock", + "privacy", + "private", + "protection", + "remove", + "security", + "security breach", + "slash", + "stop", + "unauthorized access", + "unlock", + "unlocked", + "unprotected", + "unsecure", + "vulnerability", + "vulnerable", + "warning" + ], + "popularity": 1973 + }, + "NO_FLASH": { + "tags": [ + "alert", + "blocked", + "bolt", + "camera", + "camera settings", + "crossed out", + "denied", + "diagonal line", + "disabled", + "electric", + "enabled", + "energy", + "error", + "flash", + "flash disabled", + "flash off", + "forbidden", + "image", + "instant", + "light", + "light off", + "lightning", + "lightning bolt", + "negative", + "no", + "no flash", + "no light", + "notification", + "off", + "on", + "photo", + "photo settings", + "photography", + "picture", + "prohibited", + "restriction", + "slash", + "thunderbolt", + "triangle", + "unavailable", + "warning" + ], + "popularity": 986 + }, + "NO_FOOD": { + "tags": [ + "alert", + "allergy", + "blocked", + "caution", + "circle", + "diet", + "dining", + "disabled", + "drink", + "eating restriction", + "enabled", + "exclusion", + "fastfood", + "food", + "food restricted", + "forbidden", + "forbidden symbol", + "hamburger", + "icon", + "kitchen", + "limitation", + "meal", + "no", + "no food", + "no symbol", + "not allowed", + "off", + "off limits", + "on", + "prohibited", + "restaurant", + "restricted", + "restriction", + "slash", + "snack", + "symbol", + "unavailable", + "unavailable food", + "warning" + ], + "popularity": 2435 + }, + "NO_LUGGAGE": { + "tags": [ + "access denied", + "airport", + "alert", + "bag", + "baggage", + "baggage check", + "ban", + "box", + "carry", + "cart", + "caution", + "circle", + "diagonal line", + "disabled", + "enabled", + "exclusion", + "forbidden", + "handle", + "luggage", + "no", + "no luggage", + "not allowed", + "off", + "on", + "packing", + "prohibited", + "restricted", + "restriction", + "sign", + "slash", + "suitcase", + "symbol", + "travel", + "travel restriction", + "warning", + "wheels" + ], + "popularity": 1324 + }, + "NO_MEALS": { + "tags": [ + "ban", + "catering", + "circle", + "crossed out", + "diet", + "dining", + "disabled", + "eat", + "eating", + "enabled", + "exclusion", + "food", + "forbidden", + "fork", + "kitchen", + "knife", + "line", + "meal", + "meals", + "no", + "no access", + "no eating", + "no food", + "no meals", + "not allowed", + "off", + "on", + "prohibited", + "restaurant", + "restricted", + "restriction", + "slash", + "spoon", + "sustenance", + "unavailable", + "utensils" + ], + "popularity": 1753 + }, + "NO_MEETING_ROOM": { + "tags": [ + "booking", + "building", + "calendar", + "conference room", + "crossed out", + "disabled", + "door", + "doorway", + "enabled", + "entrance", + "event", + "furniture", + "geometry", + "home", + "house", + "interior", + "location", + "meeting", + "meeting room", + "no", + "not available", + "off", + "office", + "on", + "open", + "outline", + "place", + "places", + "prohibited", + "rectangle", + "reservation", + "restricted", + "room", + "schedule", + "slash", + "square", + "unavailable", + "unavailable meeting room", + "unavailable room" + ], + "popularity": 1754 + }, + "NO_PHOTOGRAPHY": { + "tags": [ + "access denied", + "blocked", + "camera", + "capture", + "circle", + "crossed out", + "diagonal line", + "disabled", + "disallowed", + "do not record", + "enabled", + "filming prohibited", + "forbidden", + "image", + "lens", + "media", + "multimedia", + "no", + "no camera", + "no photo", + "no photography", + "not allowed", + "off", + "on", + "photo", + "photography", + "photography forbidden", + "picture", + "private", + "prohibition", + "record", + "red circle", + "restricted", + "shutter", + "slash", + "visual media" + ], + "popularity": 4539 + }, + "NO_SIM": { + "tags": [ + "absent", + "alert", + "bar", + "bars", + "camera", + "card", + "cellular", + "chip", + "communication", + "connection", + "cross", + "device", + "diagonal line", + "eject", + "empty", + "error", + "insert", + "line", + "lines", + "memory", + "missing", + "mobile", + "network", + "no", + "no service", + "no signal", + "no sim", + "not inserted", + "phone", + "signal", + "sim", + "sim card", + "slash", + "slot", + "storage", + "triangle", + "unavailable", + "warning" + ], + "popularity": 1391 + }, + "NO_STROLLER": { + "tags": [ + "access denied", + "area", + "baby", + "baby carriage", + "banned", + "care", + "carriage", + "caution", + "child", + "children", + "circle", + "diagonal line", + "disabled", + "enabled", + "facility", + "forbidden", + "infant", + "infant transport", + "kid", + "limitation", + "newborn", + "no", + "no children", + "no stroller", + "not allowed", + "off", + "on", + "parents", + "perambulator", + "pram", + "prohibited", + "public area", + "regulation", + "restricted", + "rule", + "section", + "signage", + "slash", + "stroller", + "symbol", + "toddler", + "warning", + "young", + "zone" + ], + "popularity": 824 + }, + "NO_TRANSFER": { + "tags": [ + "alert", + "automobile", + "bus", + "cancelled", + "car", + "cars", + "circle", + "cross out", + "declined", + "diagonal line", + "direction", + "disabled", + "enabled", + "error", + "failed", + "forbidden", + "graphic", + "hold", + "icon", + "maps", + "no", + "no movement", + "no progress", + "no transfer", + "not allowed", + "off", + "on", + "paused", + "pending", + "prohibition", + "public", + "restricted", + "slash", + "status", + "stopped", + "symbol", + "transfer", + "transfer blocked", + "transfer disabled", + "transportation", + "vehicle", + "warning" + ], + "popularity": 1303 + }, + "NOISE_AWARE": { + "tags": [ + "access", + "accessibility", + "acoustic", + "alert", + "ambient", + "arc", + "audio", + "aware", + "cancellation", + "circle", + "detection", + "environment", + "frequency", + "hearing", + "indicator", + "level", + "listening", + "measure", + "meter", + "monitoring", + "music", + "noise", + "note", + "notification", + "perception", + "sensing", + "sensor", + "settings", + "signal", + "sonic", + "sound", + "vibration", + "volume", + "wave" + ], + "popularity": 2391 + }, + "NOISE_CONTROL_OFF": { + "tags": [ + "ambient sound off", + "audio", + "audio off", + "aware", + "blocked", + "cancel", + "cancellation", + "circle", + "circle and slash", + "circle with slash", + "control", + "crossed out", + "disabled", + "enabled", + "lines", + "music", + "mute", + "noise", + "noise cancellation off", + "noise control off", + "noise off", + "not active", + "not enabled", + "note", + "off", + "offline", + "on", + "quiet mode", + "silent mode", + "slash", + "slashed", + "sound", + "sound off", + "three waves", + "waves" + ], + "popularity": 6186 + }, + "NORDIC_WALKING": { + "tags": [ + "active", + "activity", + "athlete", + "athletic", + "body", + "entertainment", + "equipment", + "exercise", + "figure", + "fitness", + "health", + "hike", + "hiking", + "hobby", + "human", + "movement", + "nature", + "nordic", + "nordic walking", + "outdoor", + "pedestrian", + "people", + "person", + "poles", + "recreation", + "silhouette", + "social", + "sports", + "sticks", + "trail", + "travel", + "trek", + "two poles", + "walker", + "walking", + "walking stick", + "wellness", + "workout" + ], + "popularity": 2840 + }, + "NORTH": { + "tags": [ + "arrow", + "arrow up", + "compass", + "destination", + "direction", + "direction indicator", + "directional", + "geomagnetic", + "geospatial", + "guide", + "guidepost", + "heading", + "journey", + "location", + "magnetic north", + "map", + "maps", + "navigate", + "navigation", + "north", + "orientation", + "orientation marker", + "point", + "pointer", + "routing", + "sign", + "top", + "travel", + "true north", + "up", + "upwards" + ], + "popularity": 17882 + }, + "NORTH_EAST": { + "tags": [ + "arrow", + "corner", + "diagonal", + "direction", + "direction indicator", + "east", + "external", + "external link", + "follow link", + "go to", + "internet", + "link", + "link arrow", + "location", + "map", + "maps", + "move", + "navigate", + "navigation", + "new tab", + "north east", + "noth", + "open", + "outbound", + "path", + "point", + "redirect", + "right", + "share link", + "up", + "url", + "visit", + "website", + "window" + ], + "popularity": 18326 + }, + "NORTH_WEST": { + "tags": [ + "angle", + "arrow", + "basic", + "corner", + "diagonal", + "direction", + "directional", + "indicator", + "left", + "line", + "locate", + "maps", + "move", + "navigation", + "north", + "northwest", + "point", + "pointer", + "position", + "shift", + "simple", + "thin", + "top", + "up", + "west" + ], + "popularity": 5481 + }, + "NOT_ACCESSIBLE": { + "tags": [ + "access denied", + "accessibility", + "accessible", + "alert", + "blocked", + "body", + "circle", + "closed", + "denied", + "diagonal line", + "error", + "figure", + "forbidden", + "handicap", + "help", + "human", + "inaccessible", + "limitation", + "locked", + "no entry", + "not", + "not accessible", + "off limits", + "outline", + "person", + "privacy", + "private", + "prohibition", + "restricted", + "restriction", + "security", + "silhouette", + "slash", + "strike", + "unavailable", + "user", + "warning", + "wheelchair" + ], + "popularity": 2253 + }, + "NOT_INTERESTED": { + "tags": [ + "alert", + "ban", + "block", + "cancel", + "circle", + "clear", + "close", + "control", + "diagonal", + "disable", + "dislike", + "do not disturb", + "exclude", + "exit", + "forbidden", + "interested", + "interrupt", + "limit", + "line", + "mute", + "no", + "not", + "notification", + "off", + "preference", + "prohibited", + "quiet", + "quit", + "remove", + "restricted", + "setting", + "silent", + "slash", + "state", + "status", + "stop", + "unavailable", + "x" + ], + "popularity": 14208 + }, + "NOT_LISTED_LOCATION": { + "tags": [ + "?", + "address", + "ask", + "assistance", + "clarity", + "destination", + "direction", + "directory", + "find", + "geographic", + "gps", + "guide", + "help", + "info", + "information", + "inquire", + "listed", + "location", + "map", + "maps", + "marker", + "missing", + "navigation", + "not", + "not found", + "pin", + "place", + "point", + "position", + "punctuation", + "query", + "question", + "question mark", + "search", + "spot", + "stop", + "support", + "symbol", + "unavailable", + "unknown", + "unlisted", + "where" + ], + "popularity": 6774 + }, + "NOT_STARTED": { + "tags": [ + "0", + "beginning", + "circle", + "circular", + "empty", + "geometric", + "incomplete", + "initial", + "media", + "not", + "not started", + "null", + "outline", + "pause", + "pending", + "play", + "process", + "progress", + "ring", + "round", + "shape", + "start", + "started", + "status", + "video", + "zero" + ], + "popularity": 10020 + }, + "NOTE": { + "tags": [ + "add", + "archive", + "blank", + "bookmark", + "cloud", + "content", + "create", + "data", + "doc", + "document", + "draft", + "drive", + "edit", + "file", + "folder", + "folders", + "form", + "insert", + "item", + "material", + "memo", + "message", + "new", + "note", + "office", + "page", + "paper", + "plus", + "record", + "report", + "sheet", + "slide", + "storage", + "symbol", + "text", + "upload", + "view", + "write", + "writing" + ], + "popularity": 8474 + }, + "NOTE_ADD": { + "tags": [ + "+", + "add", + "add document", + "add note", + "create", + "create document", + "data", + "doc", + "document", + "document add", + "drive", + "entry", + "file", + "folder", + "folders", + "form", + "form add", + "insert", + "list", + "memo", + "message", + "new", + "new file", + "new note", + "note", + "notepad", + "page", + "paper", + "plus", + "plus document", + "plus note", + "sheet", + "slide", + "symbol", + "text", + "to do", + "writing" + ], + "popularity": 49711 + }, + "NOTE_ALT": { + "tags": [ + "alt", + "article", + "clipboard", + "compose", + "content", + "copy", + "create", + "cut", + "diagonal line", + "document", + "draft", + "edit", + "editor", + "file", + "line", + "mark", + "memo", + "message", + "modify", + "note", + "page", + "paper", + "paste", + "pen", + "pencil", + "record", + "rectangle", + "square", + "text", + "write", + "writing" + ], + "popularity": 14129 + }, + "NOTES": { + "tags": [ + "add", + "article", + "checklist", + "comment", + "content", + "create", + "diary", + "doc", + "document", + "draft", + "edit", + "entry", + "file", + "journal", + "lines", + "list", + "manage", + "memo", + "message", + "note", + "notes", + "page", + "paper", + "paragraph", + "record", + "reminder", + "report", + "scratchpad", + "sheet", + "text", + "write", + "writing", + "written" + ], + "popularity": 16898 + }, + "NOTIFICATION_ADD": { + "tags": [ + "+", + "active", + "add", + "addition", + "alarm", + "alert", + "bell", + "button", + "calendar", + "chat", + "chime", + "control", + "create", + "email", + "event", + "follow", + "future", + "icon", + "message", + "new", + "notification", + "notifications", + "notify", + "plus", + "reminder", + "ring", + "schedule", + "shape", + "social media", + "sound", + "subscribe", + "subscription", + "symbol", + "ui", + "upcoming", + "update" + ], + "popularity": 7644 + }, + "NOTIFICATION_IMPORTANT": { + "tags": [ + "!", + "active", + "alarm", + "alert", + "app icon", + "attention", + "bell", + "caution", + "chime", + "communication", + "critical", + "danger", + "error", + "exclamation", + "icon", + "important", + "inbox", + "information", + "mark", + "message", + "new", + "notification", + "notification bell", + "notifications", + "notify", + "reminder", + "ring", + "sound", + "status", + "status update", + "symbol", + "system", + "timely", + "ui element", + "ui icon", + "update", + "urgent", + "urgent message", + "warning" + ], + "popularity": 21152 + }, + "NOTIFICATIONS": { + "tags": [ + "active", + "alarm", + "alert", + "announcement", + "app", + "bell", + "chime", + "communication", + "control", + "ding", + "follow", + "hear", + "icon", + "inbox", + "listen", + "mail", + "message", + "none", + "notification", + "notifications", + "notify", + "outline", + "preferences", + "reminder", + "ring", + "setting", + "shape", + "sound", + "subscribe", + "symbol", + "system", + "toggle", + "unread", + "update" + ], + "popularity": 208320 + }, + "NOTIFICATIONS_ACTIVE": { + "tags": [ + "active", + "alarm", + "alert", + "attention", + "bell", + "broadcast", + "chime", + "communication", + "current", + "enabled", + "engaged", + "incoming", + "indicator", + "live", + "message", + "new", + "notification", + "notifications", + "notify", + "priority", + "reminder", + "ring", + "ringing", + "ringing bell", + "signal", + "sound", + "status", + "symbol", + "ui element", + "update", + "urgent" + ], + "popularity": 52540 + }, + "NOTIFICATIONS_NONE": { + "tags": [ + "alarm", + "alert", + "announcement", + "app", + "bell", + "communication", + "control", + "ding", + "follow", + "hear", + "icon", + "inbox", + "listen", + "mail", + "message", + "none", + "notification", + "notifications", + "notify", + "outline", + "preferences", + "reminder", + "ring", + "setting", + "shape", + "sound", + "subscribe", + "symbol", + "system", + "toggle", + "unread", + "update" + ], + "popularity": 34740 + }, + "NOTIFICATIONS_OFF": { + "tags": [ + "active", + "alarm", + "alarm off", + "alert", + "alert off", + "bell", + "bell off", + "blocked", + "cease", + "chime", + "chime off", + "deactivate", + "disabled", + "disarm", + "enabled", + "halt", + "mute", + "no alerts", + "no notifications", + "no sound", + "none", + "notifications", + "notifications off", + "notify", + "off", + "offline", + "on", + "pause", + "quiet", + "reminder", + "ring", + "silence", + "silent", + "slash", + "sound", + "sound off", + "still", + "stop", + "suspend", + "turned off" + ], + "popularity": 11553 + }, + "NOTIFICATIONS_PAUSED": { + "tags": [ + "active", + "alarm", + "alert", + "attention", + "bell", + "caution", + "chime", + "cross", + "diagonal", + "disable", + "disabled", + "do not disturb", + "ignore", + "line", + "mute", + "muted", + "notification", + "notifications", + "notify", + "off", + "pause", + "paused", + "quiet", + "remind later", + "reminder", + "ring --- pause", + "silence", + "slash", + "sleep", + "snooze", + "sound", + "stop", + "suspend", + "suspended", + "triangle", + "warning", + "z", + "zzz" + ], + "popularity": 3565 + }, + "NUMBERS": { + "tags": [ + "active", + "bullet", + "busy", + "button", + "choice", + "circle", + "complete", + "control", + "digit", + "dot", + "empty", + "filled", + "full", + "geometry", + "inactive", + "incomplete", + "indicator", + "loading", + "marker", + "numbers", + "off", + "option", + "point", + "radio button", + "round", + "selected", + "selection", + "shape", + "solid", + "status", + "symbol", + "toggle", + "unchecked" + ], + "popularity": 4813 + }, + "OFFLINE_BOLT": { + "tags": [ + "adapter", + "alert", + "batteries", + "bolt", + "charger", + "circle", + "device", + "disconnected", + "electric", + "electricity", + "energy", + "error", + "fast", + "flash", + "icon", + "indicator", + "instant", + "internet down", + "lightning", + "line", + "mark", + "nest", + "network error", + "no internet", + "no signal", + "not connected", + "offline", + "out of service", + "power", + "shape", + "status", + "symbol", + "thunderbolt", + "triangular", + "unavailable", + "warning", + "zig-zag" + ], + "popularity": 14488 + }, + "OFFLINE_PIN": { + "tags": [ + "approve", + "available offline", + "cache", + "check", + "checkmark", + "circle", + "complete", + "destination", + "done", + "download", + "dropped pin", + "favorite", + "local", + "location", + "map", + "map pin", + "mark", + "marked", + "marker", + "navigation", + "offline", + "offline access", + "offline map", + "offline mode", + "ok", + "pin", + "pinned", + "placed", + "point", + "position", + "save", + "saved location", + "saved pin", + "select", + "stored", + "tick", + "validate", + "verified", + "yes" + ], + "popularity": 6637 + }, + "OFFLINE_SHARE": { + "tags": [ + "android", + "arrow", + "bluetooth", + "cell", + "communication", + "connect", + "connected", + "connection", + "connectivity", + "data transfer", + "device", + "direction", + "distribute", + "download", + "file transfer", + "hardware", + "ios", + "link", + "linked", + "local share", + "mobile", + "mobile share", + "multiple", + "nearby sharing", + "network share", + "offline", + "offline share", + "os", + "p2p", + "peer to peer", + "phone", + "right", + "share", + "sharing", + "sharing content", + "sharing data", + "sharing files", + "tablet", + "technology", + "upload", + "wireless" + ], + "popularity": 3121 + }, + "OIL_BARREL": { + "tags": [ + "barrel", + "black gold", + "commodity", + "container", + "crude oil", + "diesel", + "droplet", + "drum", + "economic", + "energy", + "fuel", + "gas", + "gasoline", + "industrial", + "industry", + "logistics", + "nest", + "oil", + "oil barrel", + "oil drum", + "petrol", + "petroleum", + "power", + "production", + "refinery", + "reserve", + "resource", + "shipping", + "storage", + "supply", + "tank", + "transportation", + "water" + ], + "popularity": 2523 + }, + "ON_DEVICE_TRAINING": { + "tags": [ + "ai", + "analytics", + "arrow", + "artificial intelligence", + "bar", + "brain", + "bulb", + "call", + "cell", + "chart", + "computation", + "computer", + "contact", + "data", + "development", + "device", + "education", + "graph", + "growth", + "hardware", + "idea", + "improvement", + "information", + "inprogress", + "intelligence", + "learning", + "light", + "load", + "loading", + "machine", + "mind", + "mobile", + "model", + "monitor", + "neural network", + "phone", + "process", + "progress", + "refresh", + "renew", + "restore", + "reverse", + "rotate", + "screen", + "system", + "technology", + "telephone", + "training" + ], + "popularity": 1540 + }, + "ONDEMAND_VIDEO": { + "tags": [ + "android", + "antenna", + "broadcast", + "broadcasting", + "channel", + "chrome", + "content", + "demand", + "desktop", + "device", + "display", + "electronic", + "entertainment", + "film", + "hardware", + "ios", + "live tv", + "mac", + "media", + "monitor", + "movie", + "on demand", + "ondemand", + "ondemand video", + "os", + "play", + "playback", + "rectangle", + "screen", + "show", + "signal", + "stream", + "streaming", + "technology", + "television", + "tv", + "video", + "watch", + "web", + "window" + ], + "popularity": 17471 + }, + "ONLINE_PREDICTION": { + "tags": [ + "ai", + "analysis", + "analytics", + "artificial intelligence", + "bulb", + "business", + "chart", + "computer", + "connection", + "curve", + "data", + "diagram", + "forecast", + "future", + "graph", + "growth", + "idea", + "increase", + "information", + "light", + "line", + "machine learning", + "monitor", + "network", + "online", + "online prediction", + "prediction", + "report", + "screen", + "signal", + "statistics", + "technology", + "trend", + "up", + "wireless" + ], + "popularity": 8070 + }, + "OPACITY": { + "tags": [ + "adjustment", + "appearance", + "blend", + "box", + "color", + "control", + "dark", + "design", + "drop", + "droplet", + "editor", + "effect", + "fade", + "fill", + "gradient", + "graphic", + "horizontal", + "hue", + "invert", + "inverted", + "layers", + "light", + "lines", + "object", + "opacity", + "overlay", + "palette", + "property", + "rectangle", + "setting", + "shape", + "solid", + "square", + "tone", + "tool", + "transparency", + "visibility", + "visual", + "water" + ], + "popularity": 11278 + }, + "OPEN_IN_BROWSER": { + "tags": [ + "access", + "arrow", + "box", + "browser", + "browser window", + "diagonal arrow", + "direct link", + "expand", + "external", + "external link", + "external window", + "frame", + "full screen", + "hyperlink", + "hypertext", + "in", + "internet", + "launch", + "navigate", + "new tab", + "new window", + "online content", + "open", + "open in browser", + "open url", + "pointer", + "rectangle", + "site", + "square", + "up", + "url", + "view online", + "web", + "website", + "window" + ], + "popularity": 11342 + }, + "OPEN_IN_FULL": { + "tags": [ + "action", + "arrow", + "arrows", + "box", + "corners", + "dimensions", + "display", + "document", + "enlarge", + "expand", + "frame", + "full", + "full screen", + "fullscreen", + "grow", + "image", + "in", + "maximize", + "media", + "move", + "open", + "out", + "photo", + "player", + "presentation", + "resize", + "screen", + "size", + "square", + "video", + "view", + "visual", + "window", + "zoom" + ], + "popularity": 41317 + }, + "OPEN_IN_NEW": { + "tags": [ + "access", + "action", + "app", + "application", + "arrow", + "box", + "button", + "components", + "depart", + "destination", + "exit", + "expand", + "external", + "follow", + "forward", + "go", + "in", + "interface", + "launch", + "link", + "navigate", + "new", + "open", + "out", + "page", + "pop out", + "portal", + "redirect", + "reference", + "right", + "screen", + "share", + "site", + "square", + "tab", + "ui", + "up", + "url", + "ux", + "web", + "website", + "window" + ], + "popularity": 105424 + }, + "OPEN_IN_NEW_OFF": { + "tags": [ + "arrow", + "blocked", + "blocked link", + "box", + "broken arrow", + "browser", + "diagonal arrow", + "direction", + "disabled", + "enabled", + "export", + "external", + "external link", + "in", + "inactive", + "link", + "navigation", + "new", + "new tab", + "off", + "on", + "open", + "outward", + "outward arrow", + "redirect", + "restricted", + "restricted link", + "slash", + "square", + "unavailable", + "unavailable link", + "url", + "website", + "window" + ], + "popularity": 2892 + }, + "OPEN_WITH": { + "tags": [ + "application", + "arrow", + "arrows", + "arrows pointing out", + "box", + "corners", + "dimensions", + "direction", + "display", + "document", + "enlarge", + "enter", + "expand", + "file", + "four arrows", + "frame", + "full screen", + "fullscreen", + "maximize", + "media", + "mode", + "move", + "open", + "outward arrows", + "pan", + "resize", + "scale", + "size", + "square", + "stretch", + "view", + "visual", + "window", + "with", + "zoom" + ], + "popularity": 17306 + }, + "OTHER_HOUSES": { + "tags": [ + "abodes", + "architecture", + "area", + "buildings", + "collection of homes", + "community", + "cottage", + "district", + "dwelling", + "estate", + "group of houses", + "habitations", + "home", + "homes", + "house", + "houses", + "housing", + "housing development", + "maps", + "multiple houses", + "neighborhood", + "other", + "place", + "property", + "real", + "real estate", + "residence", + "residences", + "residential", + "residential area", + "stay", + "structure", + "suburban", + "town", + "traveling", + "urban", + "village" + ], + "popularity": 13190 + }, + "OUTBOUND": { + "tags": [ + "arrow", + "away", + "basic", + "box", + "circle", + "diagonal arrow", + "directional", + "element", + "exit", + "export", + "external", + "jump", + "leaving", + "line", + "link", + "move", + "navigation", + "new window", + "open", + "outbound", + "outline", + "outside", + "redirect", + "right", + "right arrow", + "share", + "simple", + "square", + "stroke", + "symbol", + "up", + "up arrow" + ], + "popularity": 5707 + }, + "OUTBOX": { + "tags": [ + "arrow", + "box", + "compartment", + "container", + "deliver", + "delivery", + "drafts", + "email", + "export", + "holding", + "mail", + "message", + "move", + "open", + "outbox", + "outgoing", + "pending", + "processing", + "queue", + "rectangle", + "send", + "sending", + "sent", + "square", + "storing", + "transfer", + "unsent", + "upload", + "upward" + ], + "popularity": 6801 + }, + "OUTDOOR_GRILL": { + "tags": [ + "appliance", + "backyard", + "barbecue", + "barbeque", + "bbq", + "charcoal", + "chimney", + "cook", + "cooking", + "cookout", + "dining", + "eating", + "entertainment", + "equipment", + "fire", + "food", + "grill", + "heat", + "home", + "house", + "kitchenware", + "legs", + "leisure", + "lid", + "meat", + "outdoor", + "outdoor grill", + "outdoor kitchen", + "outside", + "party", + "patio", + "picnic", + "rectangular", + "smoke", + "summer" + ], + "popularity": 5913 + }, + "OUTLET": { + "tags": [ + "adapter", + "charge", + "charging point", + "connect", + "connecter", + "connection", + "current", + "disconnect", + "electrical", + "electrical outlet", + "electricity", + "electricity symbol", + "energy", + "energy supply", + "outlet", + "plug", + "plug in", + "port", + "power", + "power connection", + "power cord", + "power source", + "power up", + "recharge", + "socket", + "voltage", + "wall socket" + ], + "popularity": 6269 + }, + "OUTLINED_FLAG": { + "tags": [ + "achievement", + "banner", + "bookmark", + "border", + "country", + "empty", + "flag", + "goal", + "highlight", + "indicator", + "label", + "location", + "mark", + "marker", + "milestone", + "nation", + "national", + "notice", + "outline", + "outlined", + "pennant", + "pin", + "report", + "save", + "signal", + "standard", + "start", + "territory", + "unfilled" + ], + "popularity": 16518 + }, + "OUTPUT": { + "tags": [ + "action", + "area", + "arrows", + "box", + "control", + "corners", + "diagonal", + "display", + "element", + "enlarge", + "expand", + "expand control", + "full screen", + "function", + "geometry", + "grow", + "interface", + "lines", + "maximize", + "maximize button", + "rectangle", + "resize", + "screen control", + "shape", + "stretch", + "ui", + "ux", + "view" + ], + "popularity": 5134 + }, + "PADDING": { + "tags": [ + "adjust", + "alignment", + "arrangement", + "arrows", + "boundaries", + "box", + "composition", + "control", + "design", + "direction", + "document", + "dots", + "edges", + "edit", + "formatting", + "layout", + "lines", + "margin", + "margins", + "offset", + "options", + "padding", + "presentation", + "rectangle", + "settings", + "size", + "space", + "spacing", + "square", + "structure", + "text", + "visual" + ], + "popularity": 1450 + }, + "PAGES": { + "tags": [ + "archive", + "article", + "bundle", + "collection", + "content", + "copy", + "data", + "documents", + "duplicate", + "file manager", + "files", + "forms", + "gplus", + "group", + "information", + "layered", + "layering", + "library", + "list", + "multiple", + "new document", + "organization", + "pages", + "paper", + "parallel", + "post", + "records", + "rectangle", + "reports", + "sheets", + "squared", + "stacked", + "stacking", + "star" + ], + "popularity": 4132 + }, + "PAGEVIEW": { + "tags": [ + "add", + "book", + "browse", + "circle", + "content", + "create", + "data", + "details", + "doc", + "document", + "enlarge", + "entry", + "explore", + "file", + "find", + "form", + "glass", + "information", + "locate", + "magnify", + "magnifying", + "new", + "note", + "page", + "paper", + "plus", + "reading", + "rectangle", + "scan", + "search", + "text", + "view", + "zoom" + ], + "popularity": 16091 + }, + "PAID": { + "tags": [ + "amount", + "balance", + "banknote", + "bill", + "business", + "buy", + "card", + "cash", + "circle", + "coin", + "commerce", + "cost", + "credit", + "currency", + "debt", + "dollar", + "dollars", + "e-commerce", + "economic", + "expense", + "finance", + "income", + "monetization", + "money", + "on", + "online", + "paid", + "pay", + "payment", + "price", + "purchase", + "savings", + "shopping", + "symbol", + "transaction", + "value", + "wealth" + ], + "popularity": 116052 + }, + "PALETTE": { + "tags": [ + "appearance", + "art", + "artist", + "artistic", + "brush", + "color", + "colors", + "creative", + "customization", + "customize", + "design", + "designer", + "draw", + "drawing", + "editor", + "filters", + "graphic", + "hues", + "paint", + "painting", + "palette", + "shades", + "spectrum", + "style", + "swatch", + "theme", + "tint", + "tints", + "tone", + "tones", + "visual" + ], + "popularity": 35271 + }, + "PAN_TOOL": { + "tags": [ + "application", + "control", + "cursor", + "drag", + "editor", + "fingers", + "gesture", + "glove", + "grab", + "graphic", + "hand", + "hands", + "hold", + "human", + "icon", + "interface element", + "manipulation", + "map", + "move", + "navigation", + "pan", + "pointer", + "position", + "scan", + "select", + "software", + "stop", + "symbol", + "tool", + "view" + ], + "popularity": 31055 + }, + "PAN_TOOL_ALT": { + "tags": [ + "action", + "control", + "cursor", + "digital hand", + "drag", + "fingers", + "gesture", + "grab", + "grab hand", + "graphic", + "grasp", + "hand", + "hands", + "hold", + "human", + "icon", + "interaction", + "interactive", + "interface", + "interface hand", + "manipulation", + "map", + "move", + "move hand", + "movement", + "navigation", + "pan", + "point", + "pointer", + "scan", + "stop", + "symbol", + "tool", + "tool icon", + "ui element" + ], + "popularity": 6412 + }, + "PANORAMA": { + "tags": [ + "ad", + "advertisement", + "advertising", + "angle", + "banner", + "display", + "elongated", + "graphic", + "horizontal", + "image", + "landscape", + "layout", + "marketing", + "mountain", + "mountains", + "panorama", + "perspective", + "photo", + "photography", + "picture", + "planning", + "promotion", + "rectangular", + "scenic", + "stretched", + "view", + "vista", + "wide" + ], + "popularity": 4611 + }, + "PANORAMA_FISH_EYE": { + "tags": [ + "angle", + "basic", + "basic shape", + "button", + "circle", + "circular", + "design element", + "donut", + "empty circle", + "eye", + "fish", + "full", + "geometry", + "glyph", + "graphic", + "hollow circle", + "hollow shape", + "icon", + "image", + "indicator", + "lens", + "line circle", + "marker", + "minimal", + "moon", + "outline", + "outline shape", + "panorama", + "photo", + "photography", + "picture", + "placeholder", + "ring", + "round", + "shape", + "simple", + "stroke", + "symbol", + "ui control", + "visual element", + "wide" + ], + "popularity": 10186 + }, + "PANORAMA_HORIZONTAL": { + "tags": [ + "angle", + "aspect ratio", + "camera", + "composition", + "display", + "expand", + "format", + "fullscreen", + "geometric", + "horizontal", + "image", + "landscape", + "layout", + "media", + "panorama", + "panoramic", + "perspective", + "photo", + "photography", + "picture", + "rectangle", + "scene", + "scenic", + "screen", + "shape", + "stretch", + "view", + "visual", + "wide", + "wide shot" + ], + "popularity": 1172 + }, + "PANORAMA_HORIZONTAL_SELECT": { + "tags": [ + "angle", + "horizontal", + "image", + "panorama", + "photo", + "photography", + "picture", + "select", + "wide" + ], + "popularity": 887 + }, + "PANORAMA_PHOTOSPHERE": { + "tags": [ + "360", + "angle", + "ar", + "augmented reality", + "camera", + "environment", + "experience", + "explore", + "globe", + "horizontal", + "image", + "immersive", + "landscape", + "map", + "panorama", + "perspective", + "photo", + "photography", + "photosphere", + "picture", + "scene", + "sphere", + "surround", + "travel", + "view", + "virtual reality", + "visual", + "vr", + "wide", + "wide angle", + "world" + ], + "popularity": 1373 + }, + "PANORAMA_PHOTOSPHERE_SELECT": { + "tags": [ + "angle", + "horizontal", + "image", + "panorama", + "photo", + "photography", + "photosphere", + "picture", + "select", + "wide" + ], + "popularity": 873 + }, + "PANORAMA_VERTICAL": { + "tags": [ + "angle", + "aspect ratio", + "building", + "camera", + "capture", + "compose", + "field of view", + "framing", + "geometry", + "image", + "landscape", + "lines", + "nature", + "orientation", + "outdoor", + "panorama", + "panorama vertical", + "perspective", + "photo", + "photography", + "picture", + "rectangle", + "scene", + "shape", + "shoot", + "stitch", + "travel", + "urban", + "vertical", + "view", + "wide", + "wide angle" + ], + "popularity": 790 + }, + "PANORAMA_VERTICAL_SELECT": { + "tags": [ + "angle", + "image", + "panorama", + "photo", + "photography", + "picture", + "select", + "vertical", + "wide" + ], + "popularity": 855 + }, + "PANORAMA_WIDE_ANGLE": { + "tags": [ + "adjust", + "album", + "angle", + "aperture", + "broad", + "camera", + "capture", + "crop", + "edit", + "expansive", + "film", + "focal length", + "frame", + "gallery", + "horizontal", + "image", + "landscape", + "lens", + "media", + "panorama", + "perspective", + "photo", + "photography", + "picture", + "scenic", + "view", + "vision", + "visual", + "wide", + "wide angle" + ], + "popularity": 888 + }, + "PANORAMA_WIDE_ANGLE_SELECT": { + "tags": [ + "angle", + "image", + "panorama", + "photo", + "photography", + "picture", + "select", + "wide" + ], + "popularity": 1054 + }, + "PARAGLIDING": { + "tags": [ + "activity", + "adventure", + "aerial", + "air", + "altitude", + "athlete", + "athletic", + "body", + "entertainment", + "exercise", + "exploration", + "extreme", + "flight", + "fly", + "flying", + "freedom", + "fun", + "gliding", + "hobby", + "human", + "journey", + "landscape", + "leisure", + "nature", + "outdoor", + "parachute", + "paragliding", + "people", + "person", + "recreation", + "sail", + "sky", + "skydiving", + "social", + "sport", + "sports", + "thrilling", + "tourism", + "travel", + "vacation", + "wind", + "wing" + ], + "popularity": 2659 + }, + "PARK": { + "tags": [ + "area", + "attraction", + "destination", + "environment", + "fresh", + "garden", + "green space", + "land", + "landscape", + "leisure", + "local", + "location", + "map", + "monument", + "nature", + "outdoor", + "outside", + "park", + "pin", + "plant", + "preserve", + "public space", + "recreation", + "relaxation", + "tree", + "trees" + ], + "popularity": 19235 + }, + "PARTY_MODE": { + "tags": [ + "bright", + "camera", + "camera mode", + "celebration", + "celebration mode", + "cheerful", + "energetic", + "enjoy", + "event", + "festive", + "festive mode", + "fun", + "fun picture", + "group", + "happy", + "joy", + "lens", + "mode", + "night", + "nightlife", + "party", + "party night", + "party picture", + "party setting", + "photo", + "photography", + "picture", + "social", + "social event", + "special", + "special event", + "vibrant" + ], + "popularity": 2540 + }, + "PASSWORD": { + "tags": [ + "access", + "access code", + "account", + "authentication", + "authorization", + "code", + "credentials", + "data protection", + "encrypted", + "key", + "key symbol", + "keyhole", + "lock", + "lock and key", + "login", + "padlock", + "password", + "password protection", + "pin", + "privacy", + "private", + "protection", + "restricted", + "secret", + "secure", + "secure access", + "secure connection", + "security", + "sign in", + "sign up", + "star", + "unlock" + ], + "popularity": 39398 + }, + "PATTERN": { + "tags": [ + "abstract", + "appearance", + "arrangement", + "background", + "background design", + "composition", + "decoration", + "decorative element", + "design", + "element", + "fill", + "fill pattern", + "geometric", + "graphic", + "graphic element", + "grid", + "key", + "login", + "look", + "look and feel", + "motif", + "password", + "pattern", + "pin", + "repeat", + "repeat pattern", + "security", + "shape", + "square", + "star", + "style", + "texture", + "tiling", + "unlock", + "visual", + "visual appearance", + "visual style" + ], + "popularity": 3653 + }, + "PAUSE": { + "tags": [ + "action", + "audio", + "break", + "button", + "command", + "control", + "controls", + "function", + "halt", + "hold", + "inactivity", + "interlude", + "media", + "media control", + "music", + "parallel lines", + "pause", + "pending", + "playback control", + "player", + "rectangle", + "standby", + "stop", + "suspend", + "temporary", + "two lines", + "vertical lines", + "video", + "waiting" + ], + "popularity": 55849 + }, + "PAUSE_CIRCLE": { + "tags": [ + "audio", + "bars", + "break", + "button", + "circle", + "circular", + "control", + "controls", + "filled", + "hold", + "interface", + "media", + "media controls", + "music", + "outline", + "pause", + "play", + "playback", + "player", + "resume", + "rounded", + "shape", + "stop", + "suspend", + "symbol", + "two lines", + "vertical", + "video", + "wait" + ], + "popularity": 16037 + }, + "PAUSE_CIRCLE_FILLED": { + "tags": [ + "audio", + "bars", + "break", + "button", + "circle", + "circular", + "control", + "controls", + "filled", + "hold", + "interface", + "media", + "media controls", + "music", + "outline", + "pause", + "play", + "playback", + "player", + "resume", + "rounded", + "shape", + "stop", + "suspend", + "symbol", + "two lines", + "vertical", + "video", + "wait" + ], + "popularity": 8607 + }, + "PAUSE_CIRCLE_OUTLINE": { + "tags": [ + "audio", + "bars", + "break", + "button", + "circle", + "circular", + "control", + "controls", + "filled", + "hold", + "interface", + "media", + "media controls", + "music", + "outline", + "pause", + "play", + "playback", + "player", + "resume", + "rounded", + "shape", + "stop", + "suspend", + "symbol", + "two lines", + "vertical", + "video", + "wait" + ], + "popularity": 8671 + }, + "PAUSE_PRESENTATION": { + "tags": [ + "action", + "app", + "application desktop", + "audio player", + "break", + "control", + "device", + "display", + "halt", + "media", + "media control", + "media player", + "parallel lines", + "pause", + "pause button", + "playback", + "playback control", + "present", + "presentation", + "presentation software", + "screen", + "share", + "site", + "slides", + "slideshow", + "stop", + "suspend", + "two bars", + "two vertical lines", + "ui control", + "vertical bars", + "video player", + "web", + "website", + "window", + "www" + ], + "popularity": 2116 + }, + "PAYMENT": { + "tags": [ + "account", + "account information", + "amex", + "balance", + "bank", + "banking", + "bill", + "buy", + "card", + "cash", + "checkout", + "chip", + "coin", + "commerce", + "cost", + "credit", + "credit card", + "currency", + "discover", + "dollars", + "e-commerce", + "finance", + "financial", + "funding", + "mastercard", + "money", + "online", + "pay", + "payment", + "plastic", + "price", + "purchase", + "rectangle", + "secure", + "shopping", + "spend", + "stripe", + "symbol", + "transaction", + "visa", + "wallet" + ], + "popularity": 46645 + }, + "PAYMENTS": { + "tags": [ + "bank", + "banking", + "bill", + "bills", + "buy", + "card", + "cash", + "coin", + "commerce", + "cost", + "credit", + "credit card", + "currency", + "debit card", + "dollar", + "dollars", + "expense", + "finance", + "financial", + "income", + "layer", + "money", + "multiple", + "online", + "pay", + "payment", + "payments", + "price", + "purchase", + "rectangle", + "shop", + "shopping", + "store", + "symbol", + "transaction", + "wallet" + ], + "popularity": 74736 + }, + "PEDAL_BIKE": { + "tags": [ + "active", + "automobile", + "bicycle", + "bike", + "car", + "cars", + "chain", + "commute", + "cycle", + "cycling", + "direction", + "exercise", + "fitness", + "frame", + "handlebars", + "human", + "maps", + "movement", + "outdoor", + "park", + "path", + "pedal", + "pedaling", + "public", + "recreation", + "ride", + "riding", + "road", + "route", + "scooter", + "seat", + "sport", + "trail", + "transportation", + "travel", + "two wheels", + "vehicle", + "vespa", + "wheels" + ], + "popularity": 9585 + }, + "PENDING": { + "tags": [ + "accordion", + "arrow down", + "bottom", + "choose", + "circle", + "close", + "collapse", + "details", + "direction", + "dots", + "down arrow", + "dropdown", + "dropdown menu", + "expand", + "hide", + "indicator", + "list", + "loading", + "menu", + "more", + "navigation", + "open", + "pending", + "point", + "pointer", + "progress", + "reveal", + "scroll down", + "section", + "select", + "south", + "triangle", + "view more", + "wait", + "waiting" + ], + "popularity": 44737 + }, + "PENDING_ACTIONS": { + "tags": [ + "actions", + "agenda", + "alert", + "backlog", + "calendar", + "clipboard", + "clock", + "date", + "delay", + "doc", + "document", + "future", + "history", + "incomplete", + "list", + "log", + "notification", + "paper", + "pending", + "pending actions", + "processing", + "progress", + "queue", + "remember", + "reminder", + "schedule", + "tasks", + "time", + "to do", + "upcoming", + "waiting", + "workflow" + ], + "popularity": 48768 + }, + "PENTAGON": { + "tags": [ + "abstract", + "angled", + "basic", + "clean", + "concept", + "element", + "facet", + "filled", + "five point", + "five sides", + "five-sided", + "form", + "geometric", + "graphic", + "icon", + "illustration", + "line art", + "minimal", + "modern", + "object", + "outline", + "pentagon", + "polygon", + "shape", + "sharp", + "simple", + "solid", + "structure", + "symbol", + "symmetrical", + "vector" + ], + "popularity": 1953 + }, + "PEOPLE": { + "tags": [ + "accounts", + "administration", + "audience", + "basic", + "committee", + "community", + "contacts", + "crowd", + "directory", + "employees", + "face", + "family", + "figures", + "friends", + "group", + "heads", + "humans", + "list", + "management", + "members", + "network", + "outline", + "people", + "persons", + "profile", + "profiles", + "roster", + "shape", + "silhouettes", + "simple", + "social", + "staff", + "team", + "users" + ], + "popularity": 137712 + }, + "PEOPLE_ALT": { + "tags": [ + "accounts", + "administration", + "audience", + "basic", + "committee", + "community", + "contacts", + "crowd", + "directory", + "employees", + "face", + "family", + "figures", + "friends", + "group", + "heads", + "humans", + "list", + "management", + "members", + "network", + "outline", + "people", + "persons", + "profile", + "profiles", + "roster", + "shape", + "silhouettes", + "simple", + "social", + "staff", + "team", + "users" + ], + "popularity": 46559 + }, + "PEOPLE_OUTLINE": { + "tags": [ + "accounts", + "administration", + "audience", + "basic", + "committee", + "community", + "contacts", + "crowd", + "directory", + "employees", + "face", + "family", + "figures", + "friends", + "group", + "heads", + "humans", + "list", + "management", + "members", + "network", + "outline", + "people", + "persons", + "profile", + "profiles", + "roster", + "shape", + "silhouettes", + "simple", + "social", + "staff", + "team", + "users" + ], + "popularity": 15590 + }, + "PERCENT": { + "tags": [ + "analysis", + "arithmetic", + "calculation", + "chart", + "circle", + "completion", + "data", + "diagonal line", + "discount", + "dot", + "geometry", + "graph", + "interest", + "math", + "metric", + "number", + "numbers", + "numerical", + "percent", + "percentage", + "progress", + "proportion", + "rate", + "ratio", + "representation", + "savings", + "sign", + "slash", + "statistics", + "symbol", + "value" + ], + "popularity": 16280 + }, + "PERM_CAMERA_MIC": { + "tags": [ + "access", + "audio", + "button", + "camera", + "capture", + "communication", + "controls", + "device", + "glyph", + "icon", + "image", + "input", + "linear", + "media", + "mic", + "microphone", + "min", + "outline", + "perm", + "permission", + "photo", + "photography", + "picture", + "privacy", + "recording", + "security", + "settings", + "sound", + "speaker", + "square", + "stream", + "streaming", + "symbol", + "video", + "videography" + ], + "popularity": 2104 + }, + "PERM_CONTACT_CALENDAR": { + "tags": [ + "account", + "address book", + "appointment", + "button", + "calendar", + "contact", + "date", + "day", + "details", + "directory", + "element", + "event", + "face", + "graphic", + "human", + "icon", + "information", + "interface", + "meeting", + "month", + "organizer", + "people", + "perm", + "permanent", + "persistent", + "person", + "pictogram", + "profile", + "saved", + "schedule", + "symbol", + "time", + "ui element", + "user", + "year" + ], + "popularity": 17751 + }, + "PERM_DATA_SETTING": { + "tags": [ + "access", + "adjustments", + "administration", + "cloud", + "cog", + "configuration", + "connection", + "control", + "data", + "data setting", + "database", + "disk", + "drive", + "files", + "gear", + "info", + "information", + "management", + "network", + "options", + "organized", + "perm", + "permanent", + "persistent", + "preferences", + "server", + "settings", + "setup", + "storage", + "stored", + "system" + ], + "popularity": 3999 + }, + "PERM_DEVICE_INFORMATION": { + "tags": [ + "about", + "alert", + "android", + "announcement", + "build", + "cell", + "cellular", + "configuration", + "connection", + "connectivity", + "data", + "details", + "device", + "hardware", + "history", + "i", + "imei", + "info", + "information", + "ios", + "mobile", + "network", + "number", + "options", + "os", + "perm", + "permanent", + "phone", + "settings", + "smartphone", + "software", + "specifications", + "specs", + "status", + "tablet", + "version" + ], + "popularity": 3689 + }, + "PERM_IDENTITY": { + "tags": [ + "account", + "avatar", + "avatar filled", + "avatar outline", + "body", + "circle", + "contact", + "face", + "figure", + "filled", + "head", + "human", + "identity", + "individual", + "login", + "member", + "my account", + "my profile", + "outline", + "people", + "perm", + "perm identity", + "person", + "profile", + "register", + "shoulders", + "silhouette", + "thumbnail", + "user", + "user account", + "user identity", + "user profile" + ], + "popularity": 94520 + }, + "PERM_MEDIA": { + "tags": [ + "archive", + "arrangement", + "collection", + "content", + "copy", + "data", + "digital library", + "doc", + "document", + "documents", + "duplicate", + "file", + "files", + "folder", + "folders", + "grouping", + "image", + "landscape", + "layers", + "layers of files", + "library", + "media", + "media library", + "mountain", + "mountains", + "multimedia", + "multiple", + "order", + "organization", + "organized files", + "paper documents", + "papers", + "perm", + "perm media", + "photo", + "photography", + "picture", + "records", + "sheets", + "sheets of paper", + "stack", + "stacked documents", + "storage" + ], + "popularity": 18709 + }, + "PERM_PHONE_MSG": { + "tags": [ + "always", + "avatar", + "bubble", + "business", + "call", + "cell", + "chat", + "chat support", + "comment", + "communicate", + "communication", + "connected", + "contact", + "conversation", + "device", + "feedback", + "glyph", + "icon", + "message", + "mobile", + "msg", + "outline", + "perm", + "permanent", + "person", + "personal", + "phone", + "portrait", + "profile", + "recording", + "smartphone", + "speech", + "speech bubble", + "support", + "symbol", + "telephone", + "user", + "voice" + ], + "popularity": 16867 + }, + "PERM_SCAN_WIFI": { + "tags": [ + "access", + "alert", + "always on", + "announcement", + "antenna", + "broadcast", + "communication", + "configuration", + "connect", + "connection", + "connectivity", + "detect", + "device", + "find", + "info", + "information", + "internet", + "mobile", + "network", + "options", + "perm", + "permanent", + "persistent", + "radiating lines", + "router", + "scan", + "search", + "service", + "setting", + "signal", + "symbol", + "technology", + "three lines", + "waves", + "wifi", + "wireless" + ], + "popularity": 3844 + }, + "PERSON": { + "tags": [ + "account", + "avatar", + "avatar filled", + "avatar outline", + "body", + "circle", + "contact", + "face", + "figure", + "filled", + "head", + "human", + "identity", + "individual", + "login", + "member", + "my account", + "my profile", + "outline", + "people", + "perm identity", + "person", + "profile", + "register", + "shoulders", + "silhouette", + "user", + "user account", + "user identity", + "user profile" + ], + "popularity": 379137 + }, + "PERSON_2": { + "tags": [ + "abstract", + "account", + "avatar", + "basic", + "body", + "circle", + "default", + "face", + "figure", + "generic", + "head", + "human", + "identification", + "individual", + "login", + "member", + "minimal", + "one", + "outline", + "people", + "person", + "profile", + "shape", + "shoulders", + "silhouette", + "simple", + "single", + "social", + "user" + ], + "popularity": 2357 + }, + "PERSON_3": { + "tags": [ + "account", + "association", + "audience", + "avatar", + "collaboration", + "collective", + "community", + "company", + "crowd", + "face", + "figures", + "group", + "group chat", + "human", + "identity", + "individuals", + "members", + "multiple", + "network", + "organization", + "people", + "person", + "profile", + "silhouette", + "social", + "staff", + "team", + "team building", + "team members", + "three", + "user", + "user accounts", + "users" + ], + "popularity": 1597 + }, + "PERSON_4": { + "tags": [ + "account", + "account settings", + "anonymous", + "avatar", + "contact", + "default", + "face", + "figure", + "generic", + "geometric", + "human", + "identity", + "image", + "individual", + "login", + "member", + "outline", + "people", + "person", + "persona", + "personal", + "placeholder", + "private", + "profile", + "shape", + "silhouette", + "simple", + "single user", + "user", + "user profile" + ], + "popularity": 1595 + }, + "PERSON_ADD": { + "tags": [ + "+", + "account", + "account outline", + "add", + "add contact", + "add friend", + "add person", + "add user", + "avatar", + "contact", + "contact outline", + "create", + "face", + "friend", + "friend request", + "head and shoulders", + "human", + "invite", + "invite friend", + "invite user", + "man", + "new", + "new person", + "new user", + "people", + "person", + "person outline", + "plus", + "plus sign", + "profile", + "profile outline", + "symbol", + "user", + "user outline" + ], + "popularity": 90164 + }, + "PERSON_ADD_ALT": { + "tags": [ + "+", + "account", + "account outline", + "add", + "add contact", + "add friend", + "add person", + "add user", + "contact", + "contact outline", + "create", + "face", + "friend", + "friend request", + "head and shoulders", + "human", + "invite", + "invite friend", + "invite user", + "man", + "new person", + "new user", + "people", + "person", + "person outline", + "plus", + "plus sign", + "profile", + "profile outline", + "user", + "user outline" + ], + "popularity": 27121 + }, + "PERSON_ADD_ALT_1": { + "tags": [], + "popularity": 12978 + }, + "PERSON_ADD_DISABLED": { + "tags": [ + "+", + "account", + "add", + "blocked", + "cancelled", + "contact", + "crossed out", + "declined", + "delete", + "denied", + "disabled", + "enabled", + "face", + "forbidden", + "human", + "invalid", + "member", + "new", + "off", + "offline", + "on", + "people", + "person", + "plus", + "profile", + "remove", + "restricted", + "slash", + "subtract", + "symbol", + "unavailable", + "user" + ], + "popularity": 2637 + }, + "PERSON_OFF": { + "tags": [ + "access denied", + "account", + "avatar", + "block", + "circle", + "deactivate", + "disable", + "disabled", + "enabled", + "exclude", + "face", + "figure", + "forbidden", + "human", + "line", + "log out", + "no entry", + "not allowed", + "off", + "offline", + "on", + "people", + "person", + "pictogram", + "private", + "profile", + "removed", + "restricted", + "shape", + "sign out", + "silhouette", + "slash", + "symbol", + "unavailable", + "user" + ], + "popularity": 14669 + }, + "PERSON_OUTLINE": { + "tags": [ + "account", + "avatar", + "avatar filled", + "avatar outline", + "body", + "circle", + "contact", + "face", + "figure", + "filled", + "head", + "human", + "identity", + "individual", + "login", + "member", + "my account", + "my profile", + "outline", + "people", + "perm identity", + "person", + "profile", + "register", + "shoulders", + "silhouette", + "user", + "user account", + "user identity", + "user profile" + ], + "popularity": 97180 + }, + "PERSON_PIN": { + "tags": [ + "account", + "address", + "avatar", + "circle", + "colleague", + "contact", + "destination", + "direction", + "drop pin", + "face", + "figure", + "find", + "find person", + "find user", + "friend", + "geotag", + "human", + "identify location", + "identify user", + "location", + "map", + "maps", + "marker", + "my location", + "navigate", + "people", + "person", + "pin", + "place", + "point of interest", + "position", + "profile", + "silhouette", + "stop", + "team member", + "user", + "whereabouts" + ], + "popularity": 17863 + }, + "PERSON_PIN_CIRCLE": { + "tags": [ + "account", + "address", + "avatar", + "circle", + "client", + "contact", + "current location", + "customer", + "destination", + "direction", + "employee", + "face", + "find", + "gps", + "human", + "identify", + "location", + "map", + "maps", + "marker", + "meeting", + "navigation", + "nearby", + "people", + "person", + "pin", + "pinpoint", + "place", + "position", + "profile", + "round", + "search", + "spot", + "stop", + "track", + "user" + ], + "popularity": 12273 + }, + "PERSON_REMOVE": { + "tags": [ + "account", + "avatar", + "ban", + "blacklist", + "block", + "cancellation", + "circle", + "contact", + "delete", + "depart", + "diagonal line", + "exclude", + "exit", + "face", + "friend", + "human", + "line", + "minus", + "negative", + "people", + "person", + "profile", + "prohibition", + "refusal", + "rejection", + "remove", + "slash", + "unfollow", + "unfriend", + "unsubscribe", + "user", + "withdrawal" + ], + "popularity": 18614 + }, + "PERSON_REMOVE_ALT_1": { + "tags": [], + "popularity": 3398 + }, + "PERSON_SEARCH": { + "tags": [ + "account", + "avatar", + "body", + "circle", + "contact", + "contact search", + "diagonal line", + "discover", + "face", + "find", + "find contact", + "find friend", + "find person", + "find profile", + "find user", + "friend", + "friend search", + "glass", + "handle", + "head", + "human", + "investigate", + "locate contact", + "locate person", + "locate profile", + "locate user", + "look", + "lookup", + "loupe", + "magnify", + "magnifying", + "magnifying glass", + "people", + "person", + "person search", + "profile", + "profile search", + "search", + "silhouette", + "torso", + "user", + "user search", + "zoom" + ], + "popularity": 31080 + }, + "PERSONAL_INJURY": { + "tags": [ + "accident", + "accident claim", + "aid", + "anatomy", + "arm", + "bandage", + "body", + "bone", + "broke", + "broken bone", + "broken leg", + "cast", + "crutches", + "disability", + "emergency", + "foot", + "fracture", + "fractured leg", + "health", + "healthcare", + "human", + "injury", + "insurance", + "leg", + "legal", + "lower limb", + "medical", + "orthopedics", + "pain", + "patient", + "people", + "person", + "personal", + "personal injury", + "shin", + "skeletal", + "sling", + "social", + "support", + "trauma", + "walking aid" + ], + "popularity": 6242 + }, + "PERSONAL_VIDEO": { + "tags": [ + "android", + "cam", + "chrome", + "desktop", + "device", + "display", + "entertainment", + "entertainment center", + "glyph", + "hardware", + "home", + "house", + "ios", + "living room", + "mac", + "media", + "monitor", + "os", + "outline", + "personal", + "rectangle", + "screen", + "solid fill", + "squared corners", + "streaming", + "television", + "tv", + "video", + "web", + "window" + ], + "popularity": 4715 + }, + "PEST_CONTROL": { + "tags": [ + "alert", + "animal", + "block", + "bug", + "circle", + "control", + "cross", + "diagonal line", + "exterminator", + "fly", + "forbidden", + "forbidden sign", + "insect", + "insects", + "line", + "mosquito", + "nature", + "no entry", + "pest", + "prevention", + "problem", + "prohibition", + "protection", + "restriction", + "safety", + "sign", + "slash", + "solution", + "stop", + "warning", + "warning sign" + ], + "popularity": 4305 + }, + "PEST_CONTROL_RODENT": { + "tags": [ + "animal", + "animal control", + "control", + "creature", + "extermination", + "exterminator", + "health", + "home", + "house", + "infestation", + "inspection", + "issue", + "mammal", + "mice", + "mouse", + "pest", + "pest control", + "poisoning", + "prevention", + "problem", + "property", + "rat", + "removal", + "rodent", + "rodent control", + "sanitation", + "service", + "trapping", + "treatment", + "vermin", + "wildlife control" + ], + "popularity": 1565 + }, + "PETS": { + "tags": [ + "adoption", + "animal", + "animal foot", + "animal icon", + "animal print", + "animal shelter", + "animal symbol", + "animal tracks", + "animals", + "cat", + "dog", + "footprint", + "hand", + "mark", + "paw", + "paw mark", + "paw print", + "pet", + "pet care", + "pet friendly", + "pet icon", + "pet symbol", + "pets", + "print", + "rescue", + "shape", + "tracking", + "trail", + "vet", + "veterinary", + "walk" + ], + "popularity": 54545 + }, + "PHISHING": { + "tags": [ + "alert", + "attack", + "block", + "caution", + "crime", + "cyber security", + "cybercrime", + "danger", + "digital", + "email", + "exclamation", + "fish", + "fishing", + "flag", + "fraud", + "hook", + "internet security", + "malware", + "network", + "online safety", + "phishing", + "protection", + "report", + "scam", + "security", + "shield", + "spam", + "threat", + "triangle", + "virus", + "vulnerability", + "warning", + "web security" + ], + "popularity": 1917 + }, + "PHONE": { + "tags": [ + "audio", + "business", + "call", + "cell", + "communication", + "connect", + "connection", + "contact", + "contact us", + "customer service", + "device", + "dial", + "directory", + "emergency", + "handset", + "hardware", + "help", + "incoming", + "local phone", + "mobile", + "office", + "outgoing", + "phone", + "phone alt", + "receiver", + "ring", + "speak", + "support", + "talk", + "telecommunication", + "telephone", + "voice" + ], + "popularity": 120552 + }, + "PHONE_ANDROID": { + "tags": [ + "android", + "button", + "call", + "cell", + "cellphone", + "cellular", + "communication", + "connect", + "contact", + "device", + "digital", + "display", + "electronic", + "gadget", + "handheld", + "hardware", + "ios", + "message", + "mobile", + "modern", + "os", + "phone", + "portable", + "power", + "rectangle", + "ring", + "rounded", + "screen", + "smartphone", + "tablet", + "technology", + "telephone", + "volume", + "wireless" + ], + "popularity": 23416 + }, + "PHONE_BLUETOOTH_SPEAKER": { + "tags": [ + "audio", + "audio connection", + "audio device", + "bluetooth", + "bluetooth device", + "bluetooth icon", + "call", + "cell", + "communication", + "connect", + "connection", + "connectivity", + "contact", + "device", + "hardware", + "mobile", + "pairing", + "pairing device", + "phone", + "phone icon", + "signal", + "sound", + "speaker", + "speaker icon", + "speakerphone", + "symbol", + "technology", + "telephone", + "transfer", + "wireless", + "wireless connection", + "wireless speaker" + ], + "popularity": 1207 + }, + "PHONE_CALLBACK": { + "tags": [ + "arrow", + "audio", + "call", + "callback", + "cell", + "cellular", + "communication", + "connection", + "contact", + "conversation", + "device", + "dial", + "down", + "graphic", + "handset", + "hardware", + "incoming", + "line", + "mobile", + "number", + "outgoing", + "outline", + "phone", + "receiver", + "ring", + "shape", + "symbol", + "talk", + "technology", + "telephone" + ], + "popularity": 5366 + }, + "PHONE_DISABLED": { + "tags": [ + "blocked", + "call", + "cancel", + "cell", + "communication", + "contact", + "device", + "diagonal line", + "disabled", + "disconnect", + "enabled", + "end", + "forbidden", + "hang up", + "hardware", + "line", + "mobile", + "mute", + "no call", + "not allowed", + "not reachable", + "off", + "offline", + "on", + "pause", + "phone", + "prohibited", + "silent", + "slash", + "stop", + "technology", + "telephone", + "unavailable", + "unreachable" + ], + "popularity": 4253 + }, + "PHONE_ENABLED": { + "tags": [ + "active", + "answer", + "audio", + "available", + "call", + "cell", + "communication", + "connect", + "contact", + "conversation", + "device", + "dial", + "enabled", + "handset", + "hardware", + "mobile", + "on", + "phone", + "pickup", + "receiver", + "ringing", + "talk", + "telephone", + "voice" + ], + "popularity": 8954 + }, + "PHONE_FORWARDED": { + "tags": [ + "angle", + "arrow", + "audio", + "call", + "cell", + "cell phone", + "communication", + "connection", + "contact", + "device", + "diagonal line", + "direction", + "forward", + "forwarded", + "handset", + "hardware", + "incoming", + "line", + "mobile", + "move", + "phone", + "pictogram", + "pointing", + "receive", + "redirect", + "right", + "right arrow", + "symbol", + "technology", + "telephone", + "transfer", + "voice" + ], + "popularity": 4948 + }, + "PHONE_IPHONE": { + "tags": [ + "android", + "app", + "application", + "call", + "cell", + "cellphone", + "cellular", + "communication", + "communication device", + "connection", + "contact", + "device", + "digital", + "display", + "electronics", + "gadget", + "gadgetry", + "handheld", + "hardware", + "ios", + "iphone", + "message", + "mobile", + "network", + "os", + "personal", + "phone", + "portable", + "rectangular", + "rounded corners", + "screen", + "smart", + "smartphone", + "tablet", + "technology", + "telephone", + "telephony" + ], + "popularity": 68469 + }, + "PHONE_LOCKED": { + "tags": [ + "access", + "authentication", + "authorization", + "block", + "call", + "cell", + "cellphone", + "communication", + "contact", + "device", + "gadget", + "hardware", + "lock", + "locked", + "mobile", + "password", + "phone", + "privacy", + "private", + "prohibited", + "protected", + "protection", + "restricted", + "safety", + "secure", + "secure device", + "security", + "shield", + "smartphone", + "technology", + "telephone" + ], + "popularity": 1455 + }, + "PHONE_MISSED": { + "tags": [ + "alert", + "arrow", + "call", + "cell", + "communication", + "contact", + "device", + "diagonal", + "hardware", + "history", + "incoming call", + "line", + "log", + "missed", + "missed call", + "missed communication", + "mobile", + "notification", + "outbound call", + "phone", + "phone call", + "recent calls", + "smartphone", + "telecommunication", + "telephone", + "telephone communication", + "tilted", + "unanswered call", + "voice call" + ], + "popularity": 3023 + }, + "PHONE_PAUSED": { + "tags": [ + "break", + "call", + "cell", + "communication", + "contact", + "delay", + "device", + "handheld", + "handset", + "hardware", + "hold", + "idle", + "inactive", + "interrupted", + "mobile", + "mute", + "not active", + "on hold", + "pause", + "paused", + "phone", + "quiet", + "rectangular", + "silent", + "speaking", + "square", + "stop", + "suspend", + "talking", + "technology", + "telephone", + "unavailable", + "vertical", + "waiting" + ], + "popularity": 1647 + }, + "PHONELINK": { + "tags": [ + "android", + "cast", + "chrome", + "communication", + "computer", + "connect", + "connection", + "connectivity", + "data transfer", + "desktop", + "device", + "devices", + "display", + "hardware", + "ios", + "link", + "mac", + "mobile", + "monitor", + "multiple devices", + "network", + "os", + "phone", + "phonelink", + "remote control", + "screen", + "screen mirroring", + "sharing", + "smartphone", + "streaming", + "sync", + "synchronize", + "tablet", + "technology", + "transfer", + "web", + "windows" + ], + "popularity": 5658 + }, + "PHONELINK_ERASE": { + "tags": [ + "action", + "android", + "button", + "cancel", + "cell", + "clear", + "close", + "connection", + "control", + "cross", + "delete", + "device", + "diagonal line", + "disconnect", + "erase", + "exit", + "forbidden", + "hardware", + "ios", + "line", + "mobile", + "negative", + "no", + "os", + "outline", + "phone", + "phonelink", + "pictogram", + "prohibited", + "rectangle", + "remove", + "screen", + "shape", + "smartphone", + "stop", + "symbol", + "tablet", + "unavailable", + "x" + ], + "popularity": 2918 + }, + "PHONELINK_LOCK": { + "tags": [ + "access", + "access control", + "android", + "authentication", + "cell", + "cell phone", + "connection", + "control", + "device", + "erase", + "hardware", + "ios", + "lock", + "locked", + "mobile", + "os", + "password", + "phone", + "phonelink", + "pin", + "portrait", + "privacy", + "private", + "protect", + "protection", + "restricted", + "restriction", + "safety", + "screen", + "screen lock", + "secure", + "secure device", + "security", + "smartphone", + "tablet", + "unlock" + ], + "popularity": 4408 + }, + "PHONELINK_OFF": { + "tags": [ + "android", + "broken link", + "cancelled", + "computer", + "connection off", + "cross out", + "desktop", + "device", + "devices off", + "diagonal line", + "disabled", + "disconnected", + "enabled", + "hardware", + "ios", + "laptop", + "link", + "link off", + "mobile", + "monitor", + "no connection", + "no signal", + "not available", + "off", + "offline", + "on", + "os", + "pairing off", + "phone", + "phonelink", + "phonelink off", + "screen", + "slash", + "tablet", + "unavailable", + "unlink", + "unpair", + "watch", + "wearable", + "web" + ], + "popularity": 1359 + }, + "PHONELINK_RING": { + "tags": [ + "alarm", + "alert", + "android", + "audio", + "call", + "calling", + "cell", + "cellular", + "communication", + "communications", + "connection", + "data", + "device", + "hardware", + "incoming", + "ios", + "line", + "lines", + "listen", + "listening", + "mobile", + "network", + "notification", + "os", + "outbound", + "phone", + "phonelink", + "ring", + "ringing", + "service", + "signal", + "smartphone", + "sound", + "tablet", + "technology", + "telecommunication", + "telecommunications", + "telephone", + "vibrate", + "vibration", + "volume", + "waves", + "wireless" + ], + "popularity": 5035 + }, + "PHONELINK_SETUP": { + "tags": [ + "adjust", + "administration", + "android", + "call", + "chat", + "cog", + "configuration", + "control", + "customization", + "device", + "gear", + "hardware", + "icon", + "info", + "ios", + "manage", + "mobile", + "options", + "os", + "parameters", + "phone", + "phonelink", + "preferences", + "settings", + "setup", + "smartphone", + "symbol", + "system", + "tablet", + "technology", + "text" + ], + "popularity": 3943 + }, + "PHOTO": { + "tags": [ + "album", + "basic", + "camera roll", + "digital", + "file", + "gallery", + "geometric", + "graphic", + "icon", + "image", + "landscape", + "media", + "mountain", + "mountains", + "nature", + "outline", + "photo", + "photo library", + "photography", + "picture", + "picture library", + "rectangle", + "representation", + "shape", + "simple", + "square", + "sun", + "sunrise", + "sunset", + "symbol", + "visual" + ], + "popularity": 6353 + }, + "PHOTO_ALBUM": { + "tags": [ + "album", + "archive", + "bookmark", + "browsing", + "collection", + "collection of photos", + "digital album", + "gallery", + "image", + "image gallery", + "images", + "label", + "library", + "media", + "memories", + "memories album", + "mountain", + "mountains", + "multimedia", + "organization", + "photo", + "photo album", + "photo collection", + "photo storage", + "photography", + "photos", + "picture", + "pictures", + "portfolio", + "rectangle", + "ribbon", + "save", + "scrapbook", + "snapshots", + "square", + "stacked rectangles", + "stacked squares", + "tag", + "viewing", + "visual archive", + "visual content", + "visual library" + ], + "popularity": 2871 + }, + "PHOTO_CAMERA": { + "tags": [ + "analog", + "button", + "camera", + "capture", + "circle", + "device", + "digital", + "film", + "icon", + "image", + "input", + "lens", + "media", + "movie", + "multimedia", + "multimedia input", + "photo", + "photograph", + "photography", + "picture", + "record", + "shoot", + "shutter", + "square", + "symbol", + "technology", + "video", + "videography", + "visual" + ], + "popularity": 104172 + }, + "PHOTO_CAMERA_BACK": { + "tags": [ + "back", + "back camera", + "camera", + "capture", + "circle", + "device", + "flash", + "focus", + "gadget", + "image", + "landscape", + "lens", + "mountain", + "mountains", + "photo", + "photography", + "picture", + "rear", + "rear camera", + "record", + "shoot", + "shutter", + "square", + "technology", + "video" + ], + "popularity": 1590 + }, + "PHOTO_CAMERA_FRONT": { + "tags": [ + "account", + "border", + "camera", + "capture", + "circle", + "create", + "create media", + "face", + "file", + "file creation", + "front", + "front camera", + "human", + "image", + "image capture", + "lens", + "media", + "media capture", + "multimedia", + "outline", + "people", + "person", + "photo", + "photo tool", + "photography", + "photography tool", + "picture", + "portrait", + "profile", + "record", + "selfie", + "shutter", + "square", + "upload", + "upload media", + "user", + "video", + "video capture", + "video tool" + ], + "popularity": 3416 + }, + "PHOTO_FILTER": { + "tags": [ + "adjust", + "adjust image", + "adjust photo", + "ai", + "artificial", + "automatic", + "automation", + "brightness", + "color correction", + "contrast", + "custom", + "edit", + "edit image", + "edit photo", + "effects", + "enhance image", + "enhance photo", + "enhancement", + "exposure", + "filter", + "filters", + "genai", + "gradient", + "graphic design", + "image", + "image filter", + "intelligence", + "levels", + "magic", + "options", + "photo", + "photo filter", + "photography", + "picture", + "saturation", + "settings", + "smart", + "spark", + "sparkle", + "star", + "vignette", + "visual effects" + ], + "popularity": 2682 + }, + "PHOTO_LIBRARY": { + "tags": [ + "album", + "archive", + "assets", + "browse", + "catalog", + "collection", + "compilation", + "data.", + "directory", + "display", + "files", + "image", + "image gallery", + "layers", + "library", + "management", + "media", + "mountain", + "mountains", + "multimedia", + "organization", + "organize", + "overlay", + "photo", + "photo library", + "photography", + "photos", + "picture", + "pictures", + "rectangles", + "repository", + "squares", + "stack", + "storage", + "view", + "visual" + ], + "popularity": 14392 + }, + "PHOTO_SIZE_SELECT_ACTUAL": { + "tags": [ + "actual", + "album", + "basic", + "camera roll", + "dash", + "dashed", + "digital", + "file", + "gallery", + "geometric", + "graphic", + "icon", + "image", + "landscape", + "media", + "mountain", + "mountains", + "nature", + "outline", + "photo", + "photo library", + "photography", + "picture", + "picture library", + "rectangle", + "representation", + "select", + "shape", + "simple", + "size", + "square", + "sun", + "sunrise", + "sunset", + "symbol", + "visual" + ], + "popularity": 3754 + }, + "PHOTO_SIZE_SELECT_LARGE": { + "tags": [ + "adjust", + "adjustments", + "album", + "bigger", + "dash", + "dashed", + "edit", + "editing", + "expand", + "file", + "formatting", + "frame", + "full screen", + "gallery", + "image", + "landscape", + "large", + "library", + "maximize", + "media", + "mountain", + "mountains", + "options", + "photo", + "photography", + "picture", + "preview", + "rectangle", + "resize", + "scale", + "scenery", + "select", + "selection", + "size", + "sun", + "view" + ], + "popularity": 2319 + }, + "PHOTO_SIZE_SELECT_SMALL": { + "tags": [ + "adjust", + "album", + "arrangement", + "compact", + "condense", + "dimensions", + "display", + "edit", + "editing", + "format", + "grid", + "image", + "large", + "layout", + "library", + "matrix", + "minimize", + "mountain", + "mountains", + "options", + "photo", + "photography", + "picture", + "rectangle", + "reduce", + "select", + "shrink", + "size", + "small", + "square", + "thumbnails", + "tiles", + "view", + "zoom out" + ], + "popularity": 2419 + }, + "PHP": { + "tags": [ + "abstract", + "alphabet", + "backend", + "badge", + "brackets", + "character", + "code", + "coding", + "css", + "dev", + "develop", + "developer", + "development", + "emblem", + "engineer", + "engineering", + "font", + "html", + "hypertext preprocessor", + "hypertext.", + "internet", + "language", + "letters", + "logo", + "online", + "php", + "platform", + "programming", + "programming language", + "script", + "scripting", + "server", + "server-side", + "symbol", + "technology", + "text", + "type", + "web development", + "web language", + "web programming" + ], + "popularity": 1748 + }, + "PIANO": { + "tags": [ + "art", + "audio", + "band", + "black keys", + "classical music", + "concert", + "entertainment", + "harmony", + "instrument", + "keyboard", + "keys", + "learn", + "leisure", + "media", + "melody", + "music", + "musical", + "performance", + "piano", + "play", + "practice", + "recording", + "rhythm", + "social", + "song", + "sound", + "studio", + "white keys" + ], + "popularity": 5082 + }, + "PIANO_OFF": { + "tags": [ + "audio", + "audio settings", + "control", + "crossed out", + "deactivated", + "diagonal line", + "disabled", + "enabled", + "instrument", + "keyboard", + "keys", + "lines", + "music", + "music app", + "musical", + "musical instrument", + "mute", + "no sound", + "not playing", + "notes", + "off", + "on", + "piano", + "rectangle", + "silent", + "slash", + "social", + "sound", + "stop", + "strike through", + "toggle", + "turn off" + ], + "popularity": 1109 + }, + "PICTURE_AS_PDF": { + "tags": [ + "adobe", + "adobe acrobat", + "alphabet", + "as", + "character", + "copy", + "digital document", + "digital file", + "document", + "document icon", + "document preview", + "document representation", + "document symbol", + "document viewer", + "duplicate", + "electronic document", + "electronic file", + "electronic file icon", + "file", + "file format", + "file symbol", + "file type", + "font", + "format", + "image", + "letters", + "multiple", + "pages", + "paper", + "paper icon", + "pdf", + "pdf file", + "pdf icon", + "pdf symbol", + "photo", + "photography", + "picture", + "portable document format", + "show document", + "show file", + "stack", + "symbol", + "text", + "type", + "view document", + "view file" + ], + "popularity": 65524 + }, + "PICTURE_IN_PICTURE": { + "tags": [ + "chat", + "crop", + "cropped", + "display", + "display within display", + "displays", + "dual view", + "embedded video", + "entertainment", + "floating window", + "layout", + "media", + "media controls", + "miniature", + "miniaturize", + "minimize", + "multiple screens", + "multitasking", + "overlap", + "overlay", + "photo", + "picture", + "picture in picture", + "pip", + "pop out", + "position", + "reduce size", + "scale down", + "screen", + "secondary display", + "shape", + "sizes", + "small screen", + "split screen", + "talktrack", + "video", + "video box", + "video player", + "video viewing", + "video window", + "view", + "window" + ], + "popularity": 4891 + }, + "PICTURE_IN_PICTURE_ALT": { + "tags": [ + "alternate", + "box", + "chat", + "crop", + "cropped", + "display", + "displays", + "floating window", + "image", + "layout", + "media", + "media controls", + "media player", + "multi window", + "multitasking", + "overlap", + "overlay", + "photo", + "picture", + "picture in picture", + "pip", + "playback", + "player", + "position", + "rectangle", + "screen", + "shape", + "sizes", + "square", + "streaming", + "talktrack", + "video", + "video player", + "view", + "viewing mode", + "watching", + "window" + ], + "popularity": 3748 + }, + "PIE_CHART": { + "tags": [ + "analysis", + "analytics", + "bar", + "bars", + "business", + "chart", + "circle", + "comparison", + "data", + "diagram", + "division", + "economics", + "finance", + "graph", + "growth", + "infographic", + "information", + "insights", + "marketing", + "measure", + "metrics", + "overview", + "percentage", + "pie", + "pie chart", + "progress", + "reports", + "results", + "sales", + "segment", + "slice", + "statistics", + "summary", + "tracking", + "visualization" + ], + "popularity": 19132 + }, + "PIE_CHART_OUTLINE": { + "tags": [ + "analysis", + "analytics", + "bar", + "bars", + "business", + "chart", + "circle", + "comparison", + "data", + "diagram", + "division", + "economics", + "finance", + "graph", + "growth", + "infographic", + "information", + "insights", + "marketing", + "measure", + "metrics", + "outline", + "overview", + "percentage", + "pie", + "pie chart", + "progress", + "reports", + "results", + "sales", + "segment", + "slice", + "statistics", + "summary", + "tracking", + "visualization" + ], + "popularity": 3876 + }, + "PIN": { + "tags": [ + "1", + "2", + "3", + "address", + "cartography", + "destination", + "digit", + "directional", + "drop pin", + "favorite location", + "find", + "geo", + "geography", + "geotag", + "gps", + "here", + "key", + "location", + "login", + "logout", + "map marker", + "mapping", + "marker", + "navigation", + "numbers", + "password", + "pattern", + "pin", + "place", + "point of interest", + "pointer", + "position", + "pushpin", + "saved location", + "security", + "spatial", + "star", + "symbol", + "tracking", + "travel", + "unlock", + "where" + ], + "popularity": 18703 + }, + "PIN_DROP": { + "tags": [ + "address", + "area", + "coordinate", + "current location", + "destination", + "direction", + "drop", + "explore", + "find", + "geography", + "geotag", + "gps", + "locate", + "location", + "map pin", + "maps", + "mark", + "marker", + "navigate", + "navigation", + "pin", + "pinpoint", + "place", + "point", + "position", + "pushpin", + "region", + "save location", + "search", + "spot", + "stop", + "track", + "travel" + ], + "popularity": 19647 + }, + "PIN_END": { + "tags": [ + "action", + "arrow", + "destination", + "direction", + "dot", + "end", + "end point", + "find", + "geographic location", + "geotag", + "gps", + "locate", + "location marker", + "location pin", + "map marker", + "map pin", + "mark", + "marker", + "navigation", + "pin", + "pin end", + "pin location", + "pin mark", + "pinpoint", + "place", + "point of interest", + "pointer", + "position", + "target", + "track" + ], + "popularity": 1996 + }, + "PIN_INVOKE": { + "tags": [ + "action", + "add location", + "arrow", + "destination", + "direction", + "dot", + "drop", + "geotag", + "gps", + "guide", + "indicator", + "invoke", + "location", + "map", + "mark", + "marker", + "navigation", + "new location", + "object", + "pin", + "pinpoint", + "place", + "point", + "pointer", + "position", + "pushpin", + "select location", + "set location", + "sharp", + "tack", + "tool", + "travel" + ], + "popularity": 2215 + }, + "PINCH": { + "tags": [ + "adjust", + "arrow", + "arrows", + "compress", + "control", + "direction", + "document", + "enlarge", + "expand", + "finger", + "fingers", + "gesture", + "grasp", + "grow", + "hand", + "image", + "interaction", + "magnifier", + "magnify", + "map", + "maximize", + "minimize", + "mobile", + "navigation", + "nip", + "photo", + "pinch", + "reduce", + "resize", + "scale", + "screen", + "shrink", + "size", + "squeeze", + "tablet", + "touch", + "tweak", + "two fingers", + "zoom" + ], + "popularity": 2258 + }, + "PIVOT_TABLE_CHART": { + "tags": [ + "accounting", + "analysis", + "analytics", + "arrow", + "arrows", + "bar", + "bars", + "business", + "chart", + "columns", + "dashboard", + "data", + "data visualization", + "diagram", + "direction", + "drive", + "edit", + "editing", + "finance", + "graph", + "grid", + "infographic", + "information", + "insight", + "key performance indicators", + "measure", + "metrics", + "organize", + "pivot", + "pivot table", + "presentation", + "report", + "reporting", + "rotate", + "rows", + "sheet", + "spreadsheet", + "statistics", + "summarize", + "table", + "tracking", + "visualize" + ], + "popularity": 4294 + }, + "PIX": { + "tags": [ + "bill", + "brazil", + "card", + "cash", + "commerce", + "credit", + "currency", + "finance", + "money", + "payment" + ], + "popularity": 5356 + }, + "PLACE": { + "tags": [ + "address", + "area", + "current location", + "destination", + "direction", + "drop", + "find", + "geography", + "geotag", + "gps", + "landmark", + "locate", + "location", + "map", + "maps", + "marker", + "navigation", + "nearby", + "pin", + "place", + "point", + "point of interest", + "pointer", + "position", + "proximity", + "region", + "route", + "site", + "spot", + "stop", + "teardrop", + "travel", + "venue" + ], + "popularity": 153869 + }, + "PLAGIARISM": { + "tags": [ + "academic", + "alert", + "caution", + "check", + "content", + "copy", + "detection", + "dishonest", + "doc", + "document", + "duplicate", + "emblem", + "essay", + "ethical", + "find", + "forbidden", + "glass", + "glyph", + "illegal", + "infringement", + "look", + "magnifying", + "page", + "paper", + "plagiarism", + "repeated", + "report", + "scan", + "search", + "see", + "symbol", + "text", + "unethical", + "unoriginal", + "violation", + "warning", + "writing" + ], + "popularity": 9897 + }, + "PLAY_ARROW": { + "tags": [ + "app", + "application", + "arrow", + "audio", + "back", + "begin", + "button", + "cinema", + "components", + "control", + "controls", + "direction", + "entertainment", + "episode", + "forward", + "icon", + "interface", + "media", + "movie", + "music", + "navigation", + "play", + "playback", + "player", + "resume", + "right", + "screen", + "show", + "site", + "sound", + "start", + "stream", + "triangle", + "ui", + "ux", + "video", + "web", + "website" + ], + "popularity": 158657 + }, + "PLAY_CIRCLE": { + "tags": [ + "arrow", + "audio", + "begin", + "broadcast", + "button", + "circle", + "content", + "continue", + "control", + "controls", + "entertainment", + "launch", + "listen", + "live", + "media", + "movie", + "music", + "play", + "playback", + "player", + "podcast", + "record", + "replay", + "resume", + "round", + "show", + "start", + "stream", + "triangle", + "video", + "watch" + ], + "popularity": 69041 + }, + "PLAY_CIRCLE_FILLED": { + "tags": [ + "arrow", + "circle", + "control", + "controls", + "media", + "music", + "play", + "video" + ], + "popularity": 79108 + }, + "PLAY_CIRCLE_OUTLINE": { + "tags": [ + "arrow", + "circle", + "control", + "controls", + "media", + "music", + "outline", + "play", + "video" + ], + "popularity": 45786 + }, + "PLAY_DISABLED": { + "tags": [ + "action", + "audio", + "blocked", + "button", + "cannot play", + "control", + "controls", + "disabled", + "enabled", + "forward", + "greyed out", + "inactive", + "initiate", + "interface element", + "media", + "movie", + "music", + "not playable", + "off", + "on", + "play", + "playback", + "player control", + "shape", + "slash", + "start", + "symbol", + "triangle", + "unavailable", + "video" + ], + "popularity": 1606 + }, + "PLAY_FOR_WORK": { + "tags": [ + "arrow", + "audio", + "bag", + "briefcase", + "business", + "career", + "circle", + "corporate", + "document", + "down", + "file", + "film", + "google", + "half", + "job", + "management", + "media", + "media work", + "movie", + "office", + "play", + "play file", + "play video", + "playback", + "player", + "portfolio", + "professional", + "progress", + "project", + "start", + "start work", + "stream", + "task", + "video", + "work" + ], + "popularity": 5847 + }, + "PLAY_LESSON": { + "tags": [ + "academic", + "audio", + "book", + "bookmark", + "button", + "class", + "continue", + "course", + "digital", + "ebook", + "education", + "guide", + "learning", + "lecture", + "lesson", + "lesson continue", + "lesson playback", + "lesson start", + "media", + "module", + "multimedia", + "play", + "play lesson", + "playback", + "read", + "reading", + "resume", + "ribbon", + "school", + "start", + "teaching", + "training", + "triangle", + "tutorial", + "video" + ], + "popularity": 3450 + }, + "PLAYLIST_ADD": { + "tags": [ + "+", + "add", + "add to playlist", + "audio", + "audio list", + "bar", + "bars", + "collection", + "create", + "create list", + "file", + "files", + "item", + "items", + "library", + "line", + "lines", + "list", + "media", + "media list", + "music", + "music list", + "new", + "new playlist", + "playlist", + "playlist add", + "plus", + "row", + "rows", + "song list", + "sound", + "symbol" + ], + "popularity": 24188 + }, + "PLAYLIST_ADD_CHECK": { + "tags": [ + "add", + "added", + "and", + "approve", + "arrangement", + "audio", + "check", + "checked", + "collection", + "complete", + "completed", + "confirmed", + "done", + "entries", + "items", + "library", + "list", + "mark", + "multimedia", + "music", + "ok", + "order", + "playlist", + "plus", + "queue", + "select", + "sequence", + "sorted", + "success", + "task", + "tick", + "validate", + "verified", + "video", + "yes" + ], + "popularity": 17948 + }, + "PLAYLIST_ADD_CHECK_CIRCLE": { + "tags": [ + "accepted", + "add", + "album", + "appended", + "artist", + "audio", + "build", + "cd", + "check", + "circle", + "collection", + "complete", + "confirmed", + "content", + "create", + "done", + "edit", + "grouping", + "included", + "integrated", + "items", + "library", + "list", + "manage", + "mark", + "media", + "music", + "order", + "organize", + "playlist", + "record", + "sequence", + "sound", + "success", + "track", + "verified", + "video" + ], + "popularity": 4730 + }, + "PLAYLIST_ADD_CIRCLE": { + "tags": [ + "add", + "album", + "and", + "artist", + "audio", + "cd", + "check", + "circle", + "collection", + "create", + "episode", + "library", + "list", + "mark", + "media", + "movie", + "music", + "new", + "playlist", + "plus", + "queue", + "record", + "series", + "song", + "sound", + "track", + "tv", + "video" + ], + "popularity": 2680 + }, + "PLAYLIST_PLAY": { + "tags": [ + "albums", + "arrow", + "audio", + "bars", + "collection", + "content", + "entertainment", + "episodes", + "horizontal", + "lines", + "list", + "media", + "media controls", + "media player", + "multimedia", + "music", + "play", + "play media", + "playback", + "player", + "playlist", + "queue", + "queue playback", + "series", + "start", + "stream", + "tracks", + "triangle", + "vertical", + "video" + ], + "popularity": 7749 + }, + "PLAYLIST_REMOVE": { + "tags": [ + "-", + "album", + "cancel", + "clear", + "close", + "collection", + "cross", + "delete", + "discard", + "eliminate", + "empty", + "erase", + "hamburger menu", + "horizontal lines", + "library", + "lines", + "list", + "media", + "minus", + "music", + "playlist", + "record", + "remove", + "song list", + "subtract", + "three lines", + "track list", + "unselect", + "untick", + "x mark" + ], + "popularity": 4580 + }, + "PLUMBING": { + "tags": [ + "build", + "commercial", + "connections", + "construction", + "diagram", + "domestic", + "drainage", + "engineering", + "fitting", + "fix", + "flow", + "fluid", + "grid", + "handyman", + "home", + "house", + "industrial", + "infrastructure", + "joint", + "lines", + "maintenance", + "network", + "pipe", + "pipes", + "plumbing", + "repair", + "schematic", + "service", + "system", + "tools", + "utility", + "valve", + "water", + "wrench" + ], + "popularity": 4729 + }, + "PLUS_ONE": { + "tags": [ + "1", + "add", + "adjustment", + "arithmetic", + "button", + "camera setting", + "count", + "counter", + "digit", + "exposure", + "exposure plus one", + "increase", + "increment", + "increment value", + "math", + "number", + "numbers", + "numerical", + "numerical increment", + "numerical value", + "one", + "plus", + "plus one", + "plus sign", + "setting", + "sign", + "symbol", + "ui control", + "value" + ], + "popularity": 5639 + }, + "PODCASTS": { + "tags": [ + "audio", + "audio player", + "bars", + "broadcast", + "casting", + "circle", + "communication", + "content", + "entertainment", + "episode", + "internet", + "lines", + "listen", + "listen now", + "media", + "media player", + "microphone", + "music", + "network", + "news", + "play", + "play button", + "podcast", + "podcasts", + "radio", + "record", + "signal", + "sound", + "speech", + "streaming", + "talk", + "technology", + "transmitting", + "voice", + "waves", + "wireless" + ], + "popularity": 11580 + }, + "POINT_OF_SALE": { + "tags": [ + "accounting", + "business", + "buy", + "buying", + "cash", + "cash register", + "checkout", + "commerce", + "cost", + "counter", + "machine", + "marketplace", + "merchant", + "money", + "of", + "pay", + "payment", + "payment terminal", + "point", + "point of purchase", + "point of sale", + "pos", + "purchase", + "register", + "retail", + "retail point of sale", + "sale", + "sales", + "sell", + "selling", + "shop", + "store", + "system", + "terminal", + "till", + "till machine", + "till register", + "transaction" + ], + "popularity": 17404 + }, + "POLICY": { + "tags": [ + "administration", + "agreement", + "certified", + "checklist", + "compliance", + "conditions", + "contract", + "data", + "declaration", + "document", + "ethics", + "file", + "find", + "glass", + "governance", + "guidelines", + "information", + "law", + "legal", + "list", + "look", + "magnify", + "magnifying", + "management", + "official", + "paper", + "policy", + "privacy", + "private", + "protect", + "protection", + "regulation", + "report", + "rules", + "search", + "security", + "see", + "shield", + "standards", + "statement", + "terms", + "text", + "verified" + ], + "popularity": 22791 + }, + "POLL": { + "tags": [ + "add", + "analysis", + "analytics", + "assessment", + "bar", + "bar chart", + "bars", + "business", + "chart", + "columns", + "create", + "data", + "diagram", + "finance", + "graph", + "growth", + "infographic", + "insert", + "manage", + "measure", + "metrics", + "options", + "performance", + "poll", + "progress", + "report", + "representation", + "results", + "statistics", + "survey", + "tracking", + "visualize", + "vote" + ], + "popularity": 17466 + }, + "POLYLINE": { + "tags": [ + "chart", + "compose", + "connect", + "connected", + "connection", + "create", + "data", + "design", + "diagram", + "draw", + "drawing", + "form", + "geometry", + "graph", + "graphic", + "illustration", + "line", + "lines", + "node", + "outline", + "path", + "plot", + "points", + "polyline", + "representation", + "segment", + "segments", + "shape", + "sketch", + "vector", + "visual", + "wireframe" + ], + "popularity": 3087 + }, + "POLYMER": { + "tags": [ + "abstract", + "arrangement", + "atoms", + "branching", + "chain", + "chemistry", + "connection", + "data structure", + "diagram", + "emblem", + "engineering", + "flow", + "graph", + "inorganic", + "interconnected", + "link", + "linked", + "logo", + "mark", + "molecular", + "molecules", + "network", + "nodes", + "nodes and links", + "order", + "organic", + "polymer", + "science", + "scientific", + "sequence", + "structure", + "visualization" + ], + "popularity": 4854 + }, + "POOL": { + "tags": [ + "activity", + "aquatic", + "athlete", + "athletic", + "bath", + "beach", + "body", + "dip", + "entertainment", + "exercise", + "facility", + "fitness", + "fitness center", + "fun", + "health", + "hobby", + "hot tub", + "hotel", + "human", + "indoors", + "leisure", + "ocean", + "outdoor", + "people", + "person", + "places", + "play", + "pool", + "recreation", + "relax", + "resort", + "sea", + "spa", + "sports", + "summer", + "swim", + "swimming", + "therapy", + "vacation", + "water" + ], + "popularity": 9846 + }, + "PORTABLE_WIFI_OFF": { + "tags": [ + "connection", + "connection disabled", + "connection off", + "crossed out", + "data", + "data off", + "disabled", + "disconnected", + "enabled", + "hotspot off", + "internet", + "internet off", + "line", + "mobile hotspot off", + "network", + "network disabled", + "network off", + "no connection", + "no internet", + "no network", + "no wifi", + "off", + "offline", + "on", + "portable", + "portable hotspot off", + "portable wifi off", + "service", + "sharing off", + "signal", + "signal disabled", + "signal off", + "slash", + "tethering disabled", + "tethering off", + "unavailable", + "wifi", + "wifi disabled", + "wifi off", + "wireless" + ], + "popularity": 1820 + }, + "PORTRAIT": { + "tags": [ + "account", + "account icon", + "accounts", + "avatar", + "bust", + "contact", + "contact icon", + "face", + "figure", + "head", + "human", + "identity", + "individual", + "login", + "man", + "member", + "outline", + "people", + "person", + "person outline", + "person symbol", + "photo", + "picture", + "portrait", + "profile", + "register", + "shape", + "shoulders", + "sign in", + "sign up", + "silhouette", + "user", + "user icon", + "user profile" + ], + "popularity": 13291 + }, + "POST_ADD": { + "tags": [ + "+", + "add", + "add new", + "add post", + "adding content", + "article", + "blog", + "compose", + "compose new", + "content", + "create", + "create new", + "create post", + "data", + "doc", + "document", + "drive", + "entry", + "file", + "folder", + "folders", + "message", + "new", + "new post", + "notes", + "page", + "paper", + "plus", + "post", + "post add", + "publish", + "publish new", + "publishing", + "sheet", + "slide", + "social media", + "text", + "write", + "writing" + ], + "popularity": 40817 + }, + "POWER": { + "tags": [ + "arc", + "button", + "charge", + "circle", + "control", + "cord", + "device", + "disable", + "electric", + "electrical", + "electricity", + "electronic", + "enable", + "energy", + "indicator", + "line", + "off", + "on", + "outlet", + "plug", + "power", + "reboot", + "restart", + "ring", + "shutdown", + "start", + "state", + "stop", + "switch", + "system", + "technology", + "toggle", + "turn off", + "turn on" + ], + "popularity": 10133 + }, + "POWER_INPUT": { + "tags": [ + "adapter", + "amperage", + "cable", + "charge", + "charging", + "connect", + "connector", + "current", + "device", + "electric", + "electrical", + "electricity", + "electronic", + "energy", + "input", + "interface", + "lines", + "plug", + "port", + "power", + "power connection", + "power cord", + "power input", + "power outlet", + "power source", + "socket", + "supply", + "technology", + "utility", + "voltage", + "wall plug", + "watts" + ], + "popularity": 1518 + }, + "POWER_OFF": { + "tags": [ + "button", + "charge", + "circle", + "close", + "command", + "control", + "cord", + "device", + "disabled", + "electric", + "electrical", + "enabled", + "end session", + "exit", + "geometric", + "hardware", + "line", + "log out", + "off", + "on", + "outlet", + "plug", + "power", + "power button", + "restart", + "shut down", + "slash", + "standby", + "suspend", + "switch", + "switch off", + "switch on", + "symbol", + "system", + "toggle", + "turn off", + "turn on", + "vertical line" + ], + "popularity": 4943 + }, + "POWER_SETTINGS_NEW": { + "tags": [ + "action", + "button", + "circle", + "command", + "control", + "device", + "electrical", + "electronics", + "energy", + "info", + "information", + "interface control", + "line", + "machine", + "off", + "on", + "power", + "rounded", + "save", + "settings", + "shutdown", + "start", + "stop", + "switch", + "symbol", + "system", + "toggle", + "utility" + ], + "popularity": 57275 + }, + "PRECISION_MANUFACTURING": { + "tags": [ + "accurate", + "advanced", + "arm", + "assembly", + "assembly line", + "automated", + "automatic", + "automation", + "automation arm", + "chain", + "conveyor", + "crane", + "create", + "engineering", + "fabrication", + "factory", + "industrial", + "industrial automation", + "industrial machinery", + "industrial robot", + "industry", + "machine", + "machinery", + "manufacturing", + "manufacturing process", + "mechanic", + "mechanical", + "precise", + "precision", + "precision manufacturing", + "produce", + "production", + "repairing", + "robot", + "robotic arm", + "robotics", + "supply", + "technology", + "warehouse" + ], + "popularity": 29392 + }, + "PREGNANT_WOMAN": { + "tags": [ + "abdomen", + "baby", + "birth", + "body", + "child", + "curved lines", + "expecting", + "family", + "female", + "figure", + "health", + "healthcare", + "human", + "lady", + "maternity", + "medical", + "medicine", + "mom", + "mother", + "outline", + "people", + "person", + "pregnancy", + "pregnant", + "pregnant woman", + "prenatal", + "profile", + "round belly", + "side view", + "silhouette", + "woman", + "women" + ], + "popularity": 7736 + }, + "PRESENT_TO_ALL": { + "tags": [ + "all", + "arrow", + "audience", + "broadcast", + "cast", + "classroom", + "communicate", + "conference", + "demonstrate", + "display", + "distribute", + "education", + "everyone", + "global", + "group", + "lectern", + "meeting", + "multi-screen", + "output", + "present", + "presentation", + "project", + "public", + "screen", + "share", + "show", + "site", + "slides", + "speaker", + "stream", + "team", + "to", + "training", + "web", + "webinar", + "website" + ], + "popularity": 5321 + }, + "PREVIEW": { + "tags": [ + "check", + "design", + "discern", + "disclosed", + "discover", + "display", + "examine", + "explore", + "exposed", + "eye", + "glimpse", + "inspect", + "layout", + "look", + "monitor", + "notice", + "observe", + "optic", + "peek", + "preview", + "reveal", + "revealed", + "screen", + "scrutinize", + "see", + "show", + "sight", + "site", + "spot", + "spy", + "view", + "visible", + "vision", + "watch", + "web", + "website", + "window", + "www" + ], + "popularity": 39470 + }, + "PRICE_CHANGE": { + "tags": [ + "analysis", + "arrow", + "arrows", + "bill", + "card", + "cash", + "change", + "chart", + "coin", + "commerce", + "cost", + "credit", + "currency", + "data", + "decline", + "decrease", + "diagram", + "dollars", + "down", + "down arrow", + "fall", + "finance", + "financial", + "graph", + "growth", + "increase", + "market", + "money", + "online", + "pay", + "payment", + "price", + "price change", + "report", + "rise", + "shopping", + "statistics", + "stats", + "stock", + "stocks", + "symbol", + "trend", + "trending", + "up", + "up arrow", + "value" + ], + "popularity": 16273 + }, + "PRICE_CHECK": { + "tags": [ + "approve", + "barcode scanner", + "bill", + "card", + "cash", + "check", + "check price", + "coin", + "commerce", + "compare price", + "complete", + "cost", + "credit", + "currency", + "deal", + "discount", + "dollars", + "done", + "finance", + "inquiry", + "label", + "lookup", + "mark", + "money", + "offer", + "ok", + "online", + "pay", + "payment", + "price", + "price check", + "purchase", + "retail", + "sale", + "savings", + "scan", + "scan price", + "scanner", + "search price", + "select", + "shopping", + "symbol", + "tag", + "tick", + "transaction", + "validate", + "value", + "verified", + "yes" + ], + "popularity": 19856 + }, + "PRINT": { + "tags": [ + "copier", + "copy", + "device", + "document", + "draft", + "fax", + "hardware", + "ink", + "local", + "machine", + "office", + "output", + "paper", + "press", + "print", + "printer", + "printing", + "printing press", + "printshop", + "publication", + "publish", + "scanner", + "send" + ], + "popularity": 70390 + }, + "PRINT_DISABLED": { + "tags": [ + "access denied", + "action denied", + "blocked", + "cancelled", + "cannot print", + "denied", + "device", + "disabled", + "document", + "enabled", + "forbidden", + "graphic", + "no action", + "no print", + "not printable", + "off", + "on", + "output", + "paper", + "print", + "print disabled", + "print icon", + "printer", + "printer disabled", + "printer icon", + "printing forbidden", + "printing restricted", + "restricted", + "restricted action", + "slash", + "symbol", + "unavailable", + "unavailable action", + "vector" + ], + "popularity": 2284 + }, + "PRIORITY_HIGH": { + "tags": [ + "!", + "alarm", + "alert", + "attention", + "caution", + "critical", + "danger", + "error", + "exclamation", + "exclamation mark", + "exclamation point", + "flag", + "high", + "high priority", + "important", + "indicator", + "mark", + "message", + "note", + "notification", + "outline", + "point", + "priority", + "reminder", + "signal", + "symbol", + "triangle", + "triangular", + "urgent", + "warning" + ], + "popularity": 43934 + }, + "PRIVACY_TIP": { + "tags": [ + "account", + "advice", + "alert", + "announcement", + "assist", + "assistance", + "certified", + "confidentiality", + "control", + "data", + "details", + "encrypted", + "guide", + "help", + "hint", + "i", + "info", + "information", + "notification", + "personal", + "policy", + "privacy", + "private", + "protect", + "protection", + "safe", + "safeguard", + "secret", + "secure", + "security", + "sensitive", + "service", + "settings", + "shield", + "suggestion", + "support", + "tip", + "user", + "verified", + "warning" + ], + "popularity": 20334 + }, + "PRIVATE_CONNECTIVITY": { + "tags": [ + "access", + "anonymize", + "connection", + "connectivity", + "data", + "digital privacy", + "encrypted", + "internet", + "internet security", + "lock", + "locked", + "network", + "network security", + "online", + "online security", + "password", + "privacy", + "private", + "private access", + "protected", + "protected access", + "protection", + "safe browsing", + "safety", + "secure", + "secure browsing", + "secure connection", + "secure data", + "secure network", + "security", + "shield", + "tunnel", + "virtual private network", + "vpn" + ], + "popularity": 3376 + }, + "PRODUCTION_QUANTITY_LIMITS": { + "tags": [ + "!", + "alert", + "amount", + "attention", + "bill", + "boundary", + "box", + "capacity", + "card", + "cart", + "carton", + "cash", + "caution", + "coin", + "commerce", + "constraint", + "control", + "count", + "credit", + "currency", + "danger", + "dollars", + "ecommerce", + "error", + "exclamation", + "full", + "important", + "inventory", + "limit", + "limited", + "limits", + "management", + "manufacturing", + "mark", + "maximum", + "money", + "notification", + "number", + "online", + "overflow", + "package", + "pay", + "payment", + "product", + "production", + "quantity", + "restriction", + "shopping", + "sold out", + "stock", + "symbol", + "unavailable", + "warning" + ], + "popularity": 14304 + }, + "PROPANE": { + "tags": [ + "barbecue", + "bottle", + "cap", + "container", + "cooking", + "cylinder", + "energy", + "flammable", + "fuel", + "gas", + "gauge", + "grill", + "heating", + "home", + "indicator", + "industrial", + "level", + "line", + "nest", + "outdoor", + "portable", + "power", + "propane", + "rounded rectangle", + "storage", + "supply", + "tank", + "utility", + "valve", + "volume" + ], + "popularity": 907 + }, + "PROPANE_TANK": { + "tags": [ + "barbecue", + "bbq", + "bottle", + "camping", + "container", + "cooking", + "cylinder", + "empty", + "energy", + "fire", + "fuel", + "full", + "gas", + "gauge", + "grill", + "heat", + "industrial", + "level", + "measurement", + "nest", + "outdoor", + "portable", + "propane", + "refill", + "reserve", + "residential", + "resource", + "storage", + "supply", + "tank", + "utility" + ], + "popularity": 1486 + }, + "PSYCHOLOGY": { + "tags": [ + "awareness", + "behavior", + "body", + "brain", + "brainstorm", + "clever", + "cognitive", + "concept", + "education", + "function", + "gear", + "head", + "health", + "human", + "idea", + "insight", + "intellectual", + "intelligence", + "knowledge", + "learning", + "memory", + "mental", + "mind", + "neurological", + "people", + "person", + "preferences", + "psychiatric", + "psychiatrist", + "psychoanalysis", + "psychology", + "research", + "science", + "settings", + "smart", + "social", + "therapy", + "thinking", + "thought", + "thoughts", + "understanding", + "wise" + ], + "popularity": 39393 + }, + "PSYCHOLOGY_ALT": { + "tags": [ + "?", + "abstract", + "alternate", + "analysis", + "assistance", + "awareness", + "behavior", + "body", + "brain", + "cognitive", + "concept", + "consciousness", + "expertise", + "function", + "gear", + "head", + "health", + "healthcare", + "help", + "human", + "human body", + "idea", + "info", + "information", + "intellectual", + "intelligence", + "knowledge", + "learning", + "medical", + "mental", + "mental health", + "mind", + "people", + "person", + "preferences", + "profile", + "psychiatric", + "psychiatry", + "psychology", + "punctuation", + "question mark", + "science", + "settings", + "skill", + "social", + "solution", + "study", + "support", + "symbol", + "therapy", + "thinking", + "thought", + "thoughts", + "understanding" + ], + "popularity": 5342 + }, + "PUBLIC": { + "tags": [ + "access", + "accessibility", + "circle", + "community", + "connection", + "country", + "earth", + "everybody", + "geography", + "global", + "globe", + "international", + "internet", + "location", + "map", + "network", + "open", + "planet", + "public", + "round", + "share", + "social", + "space", + "sphere", + "unlocked", + "visible", + "web", + "world", + "worldwide" + ], + "popularity": 88798 + }, + "PUBLIC_OFF": { + "tags": [ + "access", + "circle", + "connection", + "continents", + "disabled", + "earth", + "enabled", + "geography", + "global", + "globe", + "international", + "limited", + "location", + "map", + "mapping", + "network", + "off", + "on", + "planet", + "privacy", + "private", + "public", + "restricted", + "security", + "slash", + "social", + "space", + "sphere", + "unavailable", + "web", + "world" + ], + "popularity": 3724 + }, + "PUBLISH": { + "tags": [ + "arrow", + "arrow up", + "cloud", + "cloud upload", + "data", + "data transfer", + "disseminate", + "distribute", + "document", + "document upload", + "export", + "file", + "file transfer", + "import", + "internet", + "network", + "online", + "post", + "public", + "publish", + "release", + "send", + "send to cloud", + "share", + "transfer", + "up", + "upload", + "upload arrow", + "upload file", + "upload to cloud" + ], + "popularity": 14895 + }, + "PUBLISHED_WITH_CHANGES": { + "tags": [ + "approve", + "approved", + "arrow", + "arrows", + "article", + "blog", + "changes", + "check", + "commit", + "complete", + "content", + "document", + "done", + "draft", + "edit", + "file", + "finalize", + "inprogress", + "lines", + "load", + "loading", + "mark", + "modify", + "ok", + "page", + "paper", + "post", + "publish", + "published", + "rectangle", + "refresh", + "renew", + "replace", + "revision", + "rotate", + "save", + "select", + "share", + "sheet", + "square", + "text", + "tick", + "update", + "upload", + "validate", + "verified", + "version", + "with", + "writing", + "yes" + ], + "popularity": 39079 + }, + "PUNCH_CLOCK": { + "tags": [ + "attendance", + "attendance tracking", + "business", + "clock", + "clock in", + "clock out", + "date", + "employee tracking", + "hours", + "labor", + "labor tracking", + "office", + "punch", + "punch clock", + "punch in", + "punch out", + "punching", + "record time", + "records", + "schedule", + "time", + "time clock", + "time record", + "time sheet", + "time tracking", + "timekeeping", + "timer", + "timesheet", + "timestamp", + "tracking", + "work hours", + "work log", + "workplace" + ], + "popularity": 2364 + }, + "PUSH_PIN": { + "tags": [ + "anchor", + "attach", + "board", + "bookmark", + "bulletin", + "fasten", + "favorite", + "fix", + "highlight", + "hold", + "important", + "keep", + "location", + "lock", + "mark", + "marker", + "memo", + "note", + "pin", + "place", + "pointer", + "position", + "priority", + "push", + "push pin", + "remember", + "reminder", + "save", + "secure", + "stick", + "tack", + "thumbtack", + "top" + ], + "popularity": 44331 + }, + "QR_CODE": { + "tags": [ + "2d barcode", + "access", + "barcode", + "camera", + "code", + "computer", + "connect", + "contactless", + "data matrix", + "decode", + "device", + "digital code", + "identification", + "information", + "link", + "machine readable", + "media", + "mobile", + "modern", + "pattern", + "payment", + "product", + "qr", + "qr code", + "quick", + "quick response code", + "read", + "response", + "scan", + "scannable", + "share", + "smartphone", + "square", + "technology", + "transaction", + "url", + "urls", + "verification", + "website" + ], + "popularity": 30654 + }, + "QR_CODE_2": { + "tags": [ + "2d barcode", + "barcode", + "business", + "camera", + "code", + "connection", + "contact", + "data", + "digital", + "encoding", + "identification", + "information", + "link", + "machine readable", + "marketing", + "matrix code", + "media", + "mobile", + "pattern", + "payment", + "product", + "qr", + "qr code", + "quick", + "quick response code", + "reading", + "response", + "scan", + "scanner", + "sharing", + "smartphone", + "square", + "square code", + "technology", + "url", + "urls", + "website" + ], + "popularity": 29050 + }, + "QR_CODE_SCANNER": { + "tags": [ + "access", + "app", + "application", + "authentication", + "barcode", + "bars", + "camera", + "code", + "corners", + "data matrix", + "digital", + "information", + "lines", + "link", + "matrix code", + "media", + "mobile", + "optical code", + "pattern", + "payment", + "phone", + "product", + "qr", + "qr code", + "quick", + "quick response code", + "reader", + "rectangular", + "response", + "scan", + "scanner", + "smartphone", + "square", + "technology", + "url", + "urls", + "website" + ], + "popularity": 51302 + }, + "QUERY_BUILDER": { + "tags": [ + "alarm", + "appointment", + "builder", + "calendar", + "chronometer", + "clock", + "countdown", + "date", + "deadline", + "delay", + "duration", + "event", + "future", + "history", + "hour", + "minute", + "organize", + "past", + "pending", + "period", + "plan", + "present", + "query", + "reminder", + "schedule", + "second", + "stopwatch", + "time", + "timer", + "upcoming", + "waiting", + "watch" + ], + "popularity": 18833 + }, + "QUERY_STATS": { + "tags": [ + "analysis", + "analytics", + "chart", + "circle", + "dashboard", + "data", + "diagram", + "examine", + "explore", + "find", + "glass", + "graph", + "infographic", + "information", + "insights", + "investigate", + "line", + "look", + "magnify", + "magnifying", + "magnifying glass", + "measure", + "measurement", + "metrics", + "monitoring", + "performance", + "query", + "reporting", + "research", + "results", + "review", + "search", + "see", + "statistics", + "stats", + "tracking", + "trends" + ], + "popularity": 25008 + }, + "QUESTION_ANSWER": { + "tags": [ + "answer", + "answers", + "bubble", + "chat", + "comment", + "comments", + "communicate", + "communication", + "communication bubble", + "conversation", + "debate", + "dialogue", + "discussion", + "empty", + "feedback", + "forum", + "help", + "message", + "online chat", + "outline", + "qa", + "question", + "question_answer", + "questions", + "rectangle", + "speaking", + "speech", + "speech balloon", + "speech bubble", + "support", + "tail", + "talk", + "talk bubble", + "talking", + "thinking", + "thought" + ], + "popularity": 112562 + }, + "QUESTION_MARK": { + "tags": [ + "?", + "ask", + "assistance", + "circle", + "clue", + "curious", + "curve", + "dot", + "doubt", + "education", + "faq", + "glyph", + "guidance", + "help", + "hint", + "info", + "information", + "inquire", + "interrogation", + "learning", + "mark", + "problem", + "punctuation", + "puzzle", + "query", + "question mark", + "stroke", + "support", + "symbol", + "unknown", + "unsure" + ], + "popularity": 31844 + }, + "QUEUE": { + "tags": [ + "add", + "archive", + "book", + "catalog", + "collection", + "content", + "create", + "data", + "document", + "entry", + "file", + "index", + "insert", + "item", + "layers", + "library", + "list", + "media", + "multiple", + "music", + "new", + "organize", + "page", + "playlist", + "plus", + "queue", + "record", + "register", + "save", + "stack", + "store", + "stream", + "video" + ], + "popularity": 7528 + }, + "QUEUE_MUSIC": { + "tags": [ + "audio", + "burger menu", + "collection", + "entertainment", + "lines", + "list", + "media", + "media player", + "menu", + "music", + "musical note", + "note", + "order", + "organization", + "playback", + "player", + "playlist", + "queue", + "queue list", + "sequence", + "songs", + "sound", + "stack", + "stacked lines", + "staff", + "three lines", + "tracks" + ], + "popularity": 8874 + }, + "QUEUE_PLAY_NEXT": { + "tags": [ + "+", + "add", + "add to playlist", + "add to queue", + "arrow", + "audio", + "control", + "desktop", + "device", + "display", + "enqueue", + "future", + "hardware", + "list", + "manage", + "media", + "media player", + "monitor", + "music", + "music player", + "new", + "next", + "order", + "organize", + "play", + "playback", + "player", + "playlist", + "plus", + "queue", + "queued", + "rearrange", + "reorder", + "screen", + "sequence", + "sound", + "stream", + "streaming", + "symbol", + "tv", + "upcoming", + "video", + "video player" + ], + "popularity": 2543 + }, + "QUICKREPLY": { + "tags": [ + "bolt", + "bubble", + "chat", + "comment", + "comment bubble", + "communicate", + "communication", + "communication bubble", + "conversation", + "dialogue", + "electric", + "energy", + "engaging", + "express", + "fast", + "fast reply", + "feedback", + "input", + "instant", + "instant reply", + "interaction", + "lightning", + "message", + "quick", + "quick reply", + "quickreply", + "reply", + "reply icon", + "respond", + "response", + "short reply", + "speech", + "speech bubble", + "talk", + "talk bubble", + "text", + "text bubble", + "thought bubble", + "thunderbolt" + ], + "popularity": 5275 + }, + "QUIZ": { + "tags": [ + "?", + "academic", + "answer", + "assessment", + "assistance", + "certification", + "challenge", + "clipboard", + "comprehension", + "document", + "e-learning", + "education", + "evaluate", + "evaluation", + "exam", + "faq", + "feedback", + "game", + "grade", + "help", + "info", + "information", + "knowledge", + "learning", + "paper", + "poll", + "punctuation", + "question mark", + "questions", + "quiz", + "report", + "results", + "review", + "score", + "study", + "support", + "survey", + "symbol", + "test", + "trivia" + ], + "popularity": 31016 + }, + "R_MOBILEDATA": { + "tags": [ + "alphabet", + "bars", + "cell", + "cellular", + "cellular data", + "character", + "communication", + "connection", + "connectivity", + "data", + "device", + "font", + "geometric", + "icon", + "internet", + "letters", + "line", + "mobile", + "mobile data", + "network", + "phone", + "r", + "reception", + "signal", + "strength", + "symbol", + "text", + "three lines", + "type", + "ui element", + "user interface", + "wifi bars", + "wireless" + ], + "popularity": 815 + }, + "RADAR": { + "tags": [ + "area", + "broadcast", + "circle", + "cone", + "detect", + "detection", + "discovery", + "expanding", + "lines", + "location", + "military", + "monitor", + "near", + "network", + "ping", + "position", + "proximity", + "pulse", + "radar", + "radiating", + "radius", + "range", + "reach", + "scan", + "scope", + "search", + "sensor", + "signal", + "surveillance", + "sweep", + "target", + "tracking", + "transmission", + "wave" + ], + "popularity": 8153 + }, + "RADIO": { + "tags": [ + "airwaves", + "antenna", + "audio", + "broadcast", + "channel", + "communication", + "device", + "digital", + "entertainment", + "frequency", + "hardware", + "internet", + "listen", + "live", + "media", + "music", + "player", + "podcast", + "radio", + "receiver", + "signal", + "sound", + "streaming", + "technology", + "transmission", + "tune", + "waves", + "wireless" + ], + "popularity": 7451 + }, + "RADIO_BUTTON_CHECKED": { + "tags": [ + "active", + "app", + "application", + "bullet", + "button", + "checked", + "checked circle", + "checked state", + "choice", + "circle", + "components", + "control", + "design", + "dot", + "enabled", + "filled circle", + "form", + "form element", + "input", + "interactive", + "interface", + "mutually exclusive", + "off", + "on", + "option", + "picker", + "picker control", + "point", + "radio", + "radio button", + "record", + "round", + "screen", + "select", + "selected", + "selected state", + "single choice", + "site", + "toggle", + "ui", + "ui control", + "ux", + "web", + "website" + ], + "popularity": 68675 + }, + "RADIO_BUTTON_UNCHECKED": { + "tags": [ + "blank radio button", + "bullet", + "button", + "choice", + "choose", + "circle", + "control", + "deselect", + "deselected", + "empty radio button", + "form", + "input", + "multiple choice", + "off", + "on", + "option", + "outlined circle", + "point", + "preferences", + "radio", + "radio button", + "record", + "ring", + "select", + "selection", + "settings", + "survey", + "switch", + "toggle", + "ui control", + "unchecked", + "unselected" + ], + "popularity": 86610 + }, + "RAILWAY_ALERT": { + "tags": [ + "!", + "alert", + "attention", + "automobile", + "bike", + "car", + "cars", + "caution", + "critical", + "danger", + "delay", + "direction", + "error", + "exclamation", + "exclamation point", + "important", + "issue", + "line", + "maps", + "mark", + "notification", + "outage", + "path", + "problem", + "public", + "railroad", + "railway", + "route", + "scooter", + "service", + "sign", + "signal", + "subway", + "symbol", + "track", + "tracks", + "train", + "transportation", + "travel", + "triangle", + "vehicle", + "vespa", + "warning" + ], + "popularity": 1699 + }, + "RAMEN_DINING": { + "tags": [ + "asian food", + "bowl", + "chinese food", + "chopsticks", + "chopsticks in bowl", + "cuisine", + "delivery", + "dining", + "eating", + "eating out", + "food", + "food icon", + "food service", + "hot meal", + "japan", + "japanese", + "japanese food", + "korean food", + "meal", + "mealtime", + "noodle dish", + "noodle soup", + "noodles", + "ramen", + "ramen bowl", + "restaurant", + "soup", + "steaming food", + "take out" + ], + "popularity": 7451 + }, + "RAMP_LEFT": { + "tags": [ + "arrow", + "arrows", + "curve", + "diagram", + "direction", + "directional", + "directions", + "exit", + "highway", + "lane", + "left", + "map", + "maps", + "merge", + "navigation", + "path", + "ramp", + "road", + "route", + "sign", + "signage", + "split", + "symbol", + "traffic", + "transportation", + "travel", + "turn", + "way" + ], + "popularity": 582 + }, + "RAMP_RIGHT": { + "tags": [ + "access", + "advance", + "angle", + "arrow", + "arrows", + "curve", + "diagonal", + "direction", + "directionality", + "directions", + "elevate", + "go", + "growth", + "incline", + "increase", + "maps", + "mobility", + "move", + "navigation", + "path", + "positive", + "progress", + "ramp", + "right", + "rise", + "road", + "route", + "sign", + "slope", + "traffic", + "transportation", + "trend", + "turn", + "upward" + ], + "popularity": 551 + }, + "RATE_REVIEW": { + "tags": [ + "assessment", + "box", + "bubble", + "chat bubble", + "comment", + "comment box", + "dialogue", + "enter", + "evaluation", + "feedback", + "fill", + "form", + "input", + "message", + "opinion", + "pen", + "pencil", + "rate", + "rating", + "rectangle", + "review", + "score", + "shape", + "speak", + "speech bubble", + "star", + "stars", + "talk", + "text", + "thought bubble", + "write" + ], + "popularity": 17282 + }, + "RAW_OFF": { + "tags": [ + "alphabet", + "button", + "camera", + "cancel", + "character", + "close", + "code", + "data", + "deactivate", + "digital", + "disabled", + "enabled", + "file format", + "file type", + "font", + "image", + "image file", + "image format", + "letters", + "off", + "on", + "original", + "photo", + "photo format", + "photography", + "photography setting", + "raw", + "raw image", + "remove", + "slash", + "source", + "stop", + "switch", + "symbol", + "text", + "toggle", + "turn off", + "type", + "unprocessed" + ], + "popularity": 679 + }, + "RAW_ON": { + "tags": [ + "abstract", + "activate", + "active", + "alphabet", + "button", + "character", + "control", + "device", + "disabled", + "electric", + "electronic", + "enable", + "enabled", + "engage", + "font", + "graphic", + "image", + "interface", + "letters", + "light", + "line", + "machine", + "manipulate", + "mechanism", + "minimalist", + "off", + "on", + "operational", + "option", + "original", + "photo", + "photography", + "power", + "raw", + "setting", + "shape", + "slash", + "state", + "switch", + "symbol", + "text", + "toggle", + "type", + "ui" + ], + "popularity": 1258 + }, + "READ_MORE": { + "tags": [ + "add", + "additional", + "additional info", + "arrow", + "article", + "augment", + "button", + "content", + "control", + "cross", + "crosshairs", + "details", + "enlarge", + "expand", + "expand content", + "extend", + "extra info", + "info", + "information", + "link", + "more", + "plus", + "plus sign", + "read", + "read more", + "show more", + "text", + "toggle", + "view more" + ], + "popularity": 12979 + }, + "REAL_ESTATE_AGENT": { + "tags": [ + "advice", + "agent", + "agreement", + "architecture", + "associate", + "broker", + "building", + "business", + "buy", + "commercial", + "contract", + "counsel", + "deal", + "estate", + "for sale", + "hand", + "handshake", + "home", + "house", + "investment", + "key", + "loan", + "mortgage", + "partnership", + "professional", + "property", + "real", + "real estate", + "realtor", + "representation", + "residence", + "residential", + "sales", + "sell", + "service", + "social" + ], + "popularity": 11929 + }, + "RECEIPT": { + "tags": [ + "accounting", + "bill", + "cash", + "check", + "checkout", + "commerce", + "cost", + "document", + "expense", + "finance", + "financial", + "invoice", + "list", + "money", + "order", + "paper", + "payment", + "price", + "purchase", + "receipt", + "record", + "report", + "retail", + "sale", + "shop", + "shopping", + "statement", + "store", + "summary", + "transaction" + ], + "popularity": 58133 + }, + "RECEIPT_LONG": { + "tags": [ + "accounting", + "bill", + "bill icon", + "business", + "check", + "checkout", + "details", + "document", + "document icon", + "expense", + "expense icon", + "financial", + "financial icon", + "history", + "invoice", + "list", + "long", + "long receipt", + "long receipt icon", + "order", + "paper", + "paper icon", + "paperwork", + "payment", + "payment icon", + "purchase", + "receipt", + "receipt icon", + "record", + "register", + "shopping", + "store", + "transaction", + "transaction icon" + ], + "popularity": 62940 + }, + "RECENT_ACTORS": { + "tags": [ + "account", + "accounts", + "actors", + "address book", + "avatar", + "avatars", + "card", + "cards", + "carousel", + "colleagues", + "community", + "connections", + "contacts", + "directory", + "face", + "friends", + "group", + "human", + "id", + "identification", + "identity", + "layers", + "list", + "members", + "network", + "networking", + "organization", + "people", + "person", + "profile", + "profiles", + "recent", + "recent actors", + "rolodex", + "roster", + "social", + "staff", + "team", + "thumbnail", + "user", + "users" + ], + "popularity": 9772 + }, + "RECOMMEND": { + "tags": [ + "affirm", + "agree", + "agreement", + "approval", + "approved", + "assess", + "choice", + "circle", + "confirm", + "endorse", + "evaluate", + "favorite", + "feedback", + "gesture", + "good", + "hand", + "like", + "opinion", + "positive", + "preference", + "rating", + "reaction", + "recommend", + "selection", + "social", + "social media", + "support", + "thumbs", + "thumbs up", + "up", + "upvote", + "validation", + "vote", + "well" + ], + "popularity": 15793 + }, + "RECORD_VOICE_OVER": { + "tags": [ + "account", + "announce", + "audio", + "avatar", + "broadcast", + "character", + "circle", + "commentary", + "communicate", + "dictation", + "face", + "geometric", + "human", + "lines", + "microphone", + "narrate", + "narration", + "outline", + "over", + "people", + "person", + "person speaking", + "person talking", + "profile", + "record", + "recording", + "silhouette", + "sound", + "speak", + "speaking", + "speech", + "studio", + "talk", + "transcript", + "user", + "voice", + "voice over" + ], + "popularity": 28255 + }, + "RECTANGLE": { + "tags": [ + "basic shape", + "blank", + "border", + "box", + "container", + "contour", + "diagram", + "drawing", + "element", + "empty", + "enclosed space", + "form", + "four sides", + "frame", + "fundamental form", + "fundamental shape", + "geometric shape", + "geometry", + "illustration", + "outline", + "outline shape", + "parallelograms", + "placeholder", + "polygons", + "quadrilaterals", + "recangle", + "rectangle", + "shape", + "simple", + "solid line", + "square", + "stroke", + "two dimensional", + "visual aid", + "visual element" + ], + "popularity": 3389 + }, + "RECYCLING": { + "tags": [ + "arrows", + "arrows in a loop", + "bio", + "circle", + "conservation", + "cycle", + "eco", + "ecological", + "ecology", + "emblem", + "environment", + "environmental", + "garbage", + "green", + "loop", + "material", + "materials", + "process", + "recyclable", + "recycle", + "recycling", + "reduce", + "remake", + "remanufacture", + "renewable", + "renewal", + "reuse", + "rotate", + "sustainability", + "sustainable", + "symbol", + "three arrows", + "transform", + "trash", + "waste" + ], + "popularity": 15152 + }, + "REDEEM": { + "tags": [ + "bill", + "bonus", + "bonus points", + "bow", + "buy", + "card", + "cart", + "cash", + "celebration", + "certificate", + "coin", + "commerce", + "coupon", + "credit", + "currency", + "discount", + "dollars", + "event", + "gift", + "gift card", + "giftcard", + "giving", + "holiday", + "loyalty", + "loyalty program", + "money", + "online", + "pay", + "payment", + "present", + "prize", + "purchase", + "rectangle", + "redeem", + "reward", + "reward system", + "ribbon", + "shopping", + "special offer", + "transaction", + "voucher" + ], + "popularity": 24071 + }, + "REDO": { + "tags": [ + "action", + "advancement", + "again", + "arrow", + "backward", + "clockwise", + "command", + "control", + "curved", + "document", + "edit", + "forward", + "future", + "history", + "iteration", + "move", + "next", + "next action", + "previous action", + "progress", + "redo", + "repeat", + "repeat action", + "restore", + "restore state", + "return", + "reverse undo", + "revision", + "right", + "rotate", + "sequence", + "step", + "undo", + "workflow" + ], + "popularity": 18409 + }, + "REDUCE_CAPACITY": { + "tags": [ + "arrow", + "body", + "capacity", + "capacity reduction", + "compact", + "compress", + "constrain", + "contract", + "covid", + "de-emphasize", + "decrease", + "decrease capacity", + "down", + "fewer items", + "human", + "less space", + "lessen", + "lessen amount", + "lessen quantity", + "limit", + "lower", + "minimize", + "narrow", + "optimize", + "people", + "person", + "reduce", + "reduce count", + "reduce load", + "reduce quantity", + "reduce size", + "reduce volume", + "restrict", + "save space", + "scale back", + "scale down", + "shrink", + "social" + ], + "popularity": 6700 + }, + "REFRESH": { + "tags": [ + "application", + "around", + "arrow", + "arrows", + "browser", + "circular", + "content", + "current", + "curved", + "cycle", + "data", + "direction", + "feed", + "inprogress", + "latest", + "load", + "loading", + "loading refresh", + "loop", + "navigation", + "page", + "process", + "redo", + "refresh", + "reload", + "renew", + "repeat", + "reprocess", + "reset", + "restart", + "revert", + "right", + "rotate", + "round", + "spin", + "sync", + "synchronize", + "turn", + "update" + ], + "popularity": 99573 + }, + "REMEMBER_ME": { + "tags": [ + "account", + "android", + "authentication", + "avatar", + "boolean", + "checkbox", + "checked", + "checkmark", + "device", + "form", + "hardware", + "human", + "identity", + "ios", + "keep me signed in", + "login", + "me", + "mobile", + "option", + "os", + "people", + "persistent login", + "person", + "phone", + "preferences", + "profile", + "remember", + "remember login", + "remember me", + "remember password", + "remember settings", + "remember user", + "select", + "selection", + "session", + "settings", + "stay logged in", + "tablet", + "toggle", + "user", + "user account" + ], + "popularity": 3753 + }, + "REMOVE": { + "tags": [ + "bar", + "basic", + "can", + "cancel", + "clean", + "clear", + "close", + "cut", + "delete", + "detach", + "dissociate", + "division", + "eliminate", + "erase", + "essential", + "exclude", + "exit", + "garbage", + "horizontal line", + "line", + "minimal", + "minus", + "negative", + "remove", + "segment", + "sever", + "simple", + "substract", + "subtract", + "trash", + "unlink" + ], + "popularity": 79262 + }, + "REMOVE_CIRCLE": { + "tags": [ + "action", + "alert", + "ban", + "block", + "can", + "cancel", + "caution", + "circle", + "clear", + "control", + "dash", + "delete", + "deny", + "disable", + "do not disturb", + "error", + "exclude", + "forbidden", + "horizontal line", + "minus", + "negative", + "off", + "pause", + "prohibit", + "remove", + "restrict", + "revoke", + "round", + "stop", + "substract", + "subtract", + "trash", + "warning" + ], + "popularity": 43605 + }, + "REMOVE_CIRCLE_OUTLINE": { + "tags": [ + "action", + "alert", + "ban", + "block", + "can", + "cancel", + "caution", + "circle", + "clear", + "control", + "dash", + "delete", + "deny", + "disable", + "do not disturb", + "error", + "exclude", + "forbidden", + "horizontal line", + "minus", + "negative", + "off", + "outline", + "pause", + "prohibit", + "remove", + "restrict", + "revoke", + "round", + "stop", + "substract", + "subtract", + "trash", + "warning" + ], + "popularity": 54760 + }, + "REMOVE_DONE": { + "tags": [ + "abolish", + "accept", + "approval", + "approve", + "bin", + "cancel", + "check", + "checkmark", + "clear", + "complete", + "completion", + "confirmation", + "delete", + "destroy", + "disabled", + "discard", + "done", + "eliminate", + "enabled", + "erase", + "finished", + "get rid of", + "invalidate", + "mark", + "multiple", + "obliterate", + "off", + "ok", + "on", + "positive", + "remove", + "rubbish", + "scrap", + "select", + "slash", + "tick", + "trash", + "verification", + "wipe out", + "yes" + ], + "popularity": 7185 + }, + "REMOVE_FROM_QUEUE": { + "tags": [ + "action", + "cancel", + "clear", + "close", + "control", + "cross", + "delete", + "desktop", + "device", + "display", + "from", + "hardware", + "interface", + "line", + "list", + "management", + "mark", + "media", + "monitor", + "music", + "order", + "playback", + "playlist", + "podcast", + "queue", + "remove", + "remove from queue", + "screen", + "shape", + "stream", + "symbol", + "video", + "x" + ], + "popularity": 1647 + }, + "REMOVE_MODERATOR": { + "tags": [ + "access", + "account", + "admin", + "administrator", + "ban", + "block", + "cancel", + "certified", + "close", + "community", + "cross", + "delete", + "demote", + "disabled", + "enabled", + "exit", + "group", + "human", + "minus", + "moderation", + "moderator", + "off", + "on", + "permissions", + "person", + "privacy", + "private", + "priviledge", + "profile", + "profile management", + "protect", + "protection", + "remove", + "revoke", + "security", + "shield", + "silhouette", + "slash", + "social", + "subtract", + "user", + "verified", + "x" + ], + "popularity": 3664 + }, + "REMOVE_RED_EYE": { + "tags": [ + "display", + "eye", + "glance", + "hidden", + "hidden text", + "insight", + "iris", + "look", + "looking", + "observe", + "optic", + "password visibility", + "peek", + "perspective", + "preview", + "private", + "public", + "red", + "remove", + "reveal", + "security", + "see", + "show", + "sight", + "sighted", + "spy", + "stare", + "toggle visibility", + "unhide", + "view", + "visibility", + "visible", + "vision", + "visual", + "watch" + ], + "popularity": 34385 + }, + "REMOVE_ROAD": { + "tags": [ + "-", + "cancel", + "clear", + "close", + "delete", + "destination", + "diagonal line", + "direction", + "discard", + "eliminate", + "erase", + "exclude", + "exit", + "filter", + "forbidden", + "highway", + "line", + "location", + "map", + "maps", + "marker", + "minus", + "navigation", + "new", + "no", + "path", + "point of interest", + "prohibition", + "remove", + "road", + "route", + "slash", + "stop", + "street", + "strike through", + "symbol", + "traffic", + "transportation", + "travel", + "unlink", + "unpin", + "unset", + "x" + ], + "popularity": 1041 + }, + "REMOVE_SHOPPING_CART": { + "tags": [ + "basket", + "card", + "cart", + "cash", + "checkout", + "clear", + "clear cart", + "coin", + "commerce", + "credit", + "currency", + "delete", + "dollars", + "e-commerce", + "empty", + "empty cart", + "erase", + "item", + "minus", + "online", + "online shopping", + "online store", + "pay", + "payment", + "product", + "purchase", + "quantity", + "remember", + "remove", + "remove from cart", + "remove item", + "retail", + "ribbon", + "save", + "shop", + "shopping", + "shopping cart", + "store", + "subtract" + ], + "popularity": 8671 + }, + "REORDER": { + "tags": [ + "adjust", + "arrows", + "bars", + "burger", + "dots", + "down", + "drag", + "drag and drop", + "drop", + "ellipses", + "format", + "grid", + "grip", + "handle", + "horizontal", + "layout", + "lines", + "list", + "menu", + "move", + "navigation", + "order", + "organize", + "parallel", + "rearrange", + "reorder", + "sort", + "stacked", + "structure", + "up", + "vertical" + ], + "popularity": 48415 + }, + "REPARTITION": { + "tags": [ + "allocation", + "analysis", + "area", + "arrow", + "arrows", + "breakdown", + "categories", + "chart", + "circle", + "configuration", + "dashboard", + "dashboard item", + "data", + "diagram", + "distribution", + "division", + "graph", + "hierarchy", + "management", + "module", + "organization", + "partition", + "pie chart", + "refresh", + "renew", + "repartition", + "restore", + "sections", + "segments", + "settings", + "setup", + "slice", + "split", + "statistics", + "structure", + "table" + ], + "popularity": 1140 + }, + "REPEAT": { + "tags": [ + "arrow", + "arrow icon", + "arrows", + "audio", + "circular arrows", + "continuous", + "control", + "controls", + "cycle", + "direction", + "loop", + "media", + "media control", + "multimedia", + "multimedia icon", + "music", + "play again", + "playback", + "refresh", + "repeat", + "replay", + "video", + "video player" + ], + "popularity": 15000 + }, + "REPEAT_ON": { + "tags": [ + "active", + "album", + "arrow", + "arrows", + "audio", + "button", + "circular arrows", + "continuous", + "control", + "controls", + "curving arrows", + "cycle", + "enabled", + "episode", + "geometry", + "loop", + "media", + "media controls", + "movie", + "music", + "never ending", + "on", + "playback", + "playlist", + "repeat", + "series", + "shape", + "song", + "symbol", + "toggle", + "two arrows", + "video" + ], + "popularity": 3274 + }, + "REPEAT_ONE": { + "tags": [ + "1", + "arrow", + "arrow with number", + "arrows", + "audio", + "control", + "controls", + "curved arrow", + "digit", + "loop", + "loop button", + "loop one", + "loop playback", + "loop single", + "loop track", + "media", + "media controls", + "media player", + "music", + "number one", + "numbers", + "one", + "playback", + "repeat", + "repeat button", + "repeat forever", + "repeat one", + "repeat single", + "repeat track", + "single item", + "single song", + "single video", + "symbol", + "video" + ], + "popularity": 3739 + }, + "REPEAT_ONE_ON": { + "tags": [ + "again", + "album", + "arrow", + "arrows", + "audio", + "circle", + "continuous", + "control", + "controls", + "cycle", + "digit", + "endless", + "list", + "loop", + "loop one", + "media", + "music", + "number", + "numbers", + "numeric", + "on", + "one", + "playback", + "player", + "playlist", + "repeat", + "repeat one", + "single", + "song", + "symbol", + "track", + "ui", + "ux", + "video" + ], + "popularity": 1785 + }, + "REPLAY": { + "tags": [ + "again", + "arrow", + "arrows", + "audio", + "back", + "back arrow", + "circular", + "circular arrow", + "continuous", + "control", + "controls", + "curve", + "curving arrow", + "cycle", + "loop", + "media", + "media control", + "music", + "navigation", + "playback", + "playback control", + "player", + "redo", + "refresh", + "renew", + "repeat", + "replay", + "restart", + "return", + "rewind", + "rewind arrow", + "start over", + "video" + ], + "popularity": 34957 + }, + "REPLAY_10": { + "tags": [ + "10", + "arrow", + "arrows", + "audio", + "back", + "backward", + "circle", + "clock", + "content", + "control", + "controls", + "digit", + "duration", + "goback", + "history", + "jump", + "listen", + "loop", + "media", + "music", + "numbers", + "playback", + "player", + "previous", + "refresh", + "renew", + "repeat", + "replay", + "reverse", + "rewind", + "seconds", + "segment", + "skip", + "stream", + "symbol", + "ten", + "time", + "video", + "watch" + ], + "popularity": 6524 + }, + "REPLAY_30": { + "tags": [ + "30", + "arrow", + "arrows", + "audio player", + "back 30", + "backward", + "circular arrow", + "control", + "controls", + "curved arrow", + "digit", + "duration", + "go back 30 seconds", + "left arrow", + "media", + "media control", + "music", + "numbers", + "playback control", + "player", + "refresh", + "renew", + "repeat", + "replay", + "replay 30", + "replay button", + "restart 30", + "rewind", + "rewind 30", + "rewind button", + "seconds", + "skip backward 30", + "symbol", + "thirty", + "thirty seconds", + "time", + "video", + "video player" + ], + "popularity": 3272 + }, + "REPLAY_5": { + "tags": [ + "5", + "arrow", + "arrows", + "audio player", + "backward", + "circular", + "control", + "controls", + "digit", + "digits", + "five", + "jump", + "jump back 5 seconds", + "loop", + "media", + "media control", + "media player icon", + "music", + "number", + "numbers", + "playback", + "player", + "refresh", + "renew", + "repeat", + "replay", + "replay 5 seconds", + "replay button", + "restart", + "rewind", + "rewind 5", + "rewind 5 seconds", + "rewind icon", + "skip", + "skip back", + "symbol", + "time control", + "video", + "video player" + ], + "popularity": 2531 + }, + "REPLAY_CIRCLE_FILLED": { + "tags": [ + "arrow", + "arrows", + "audio player", + "circle", + "circular arrow", + "circular shape", + "control", + "controls", + "counterclockwise arrow", + "filled", + "filled circle", + "full circle", + "loop", + "loop button", + "media controls", + "multimedia", + "music", + "play again", + "play again button", + "playback", + "refresh", + "reload", + "renew", + "repeat", + "repeat button", + "replay", + "replay button", + "restart", + "restart button", + "rewind", + "rewind button", + "rounded", + "video", + "video player" + ], + "popularity": 7477 + }, + "REPLY": { + "tags": [ + "arrow", + "backward", + "bubble", + "chat", + "chat box", + "chat bubble", + "comment", + "communicate", + "communication", + "conversation", + "dialogue", + "direct message", + "email", + "feedback", + "forward", + "interaction", + "left", + "mail", + "message", + "message bubble", + "messenger", + "receive", + "reply", + "respond", + "response", + "send", + "share", + "social media", + "speak", + "speech", + "square", + "talk", + "talk bubble", + "text" + ], + "popularity": 45612 + }, + "REPLY_ALL": { + "tags": [ + "all", + "answer", + "arrow", + "backward", + "boomerang", + "broadcast", + "chat", + "communication", + "connect", + "conversation", + "correspondence", + "curved arrow", + "direction", + "email", + "everyone", + "feedback", + "forward", + "group", + "inbox", + "inform", + "interact", + "left", + "left arrow", + "loop", + "mail", + "message", + "multiple", + "notify", + "outbound", + "reply", + "reply all", + "response", + "return", + "send", + "share" + ], + "popularity": 8218 + }, + "REPORT": { + "tags": [ + "!", + "abuse", + "alert", + "attention", + "caution", + "complaint", + "danger", + "error", + "exclamation", + "feedback", + "flag", + "important", + "issue", + "mark", + "notification", + "octagon", + "outline", + "problem", + "report", + "send", + "shape", + "spam", + "stroke", + "submit", + "symbol", + "triangle", + "warning" + ], + "popularity": 31631 + }, + "REPORT_GMAILERRORRED": { + "tags": [ + "!", + "abuse", + "alert", + "attention", + "caution", + "complaint", + "danger", + "error", + "exclamation", + "feedback", + "flag", + "gmail", + "gmailerrorred", + "important", + "issue", + "mark", + "notification", + "octagon", + "outline", + "problem", + "report", + "send", + "shape", + "spam", + "stroke", + "submit", + "symbol", + "triangle", + "warning" + ], + "popularity": 14218 + }, + "REPORT_OFF": { + "tags": [ + "!", + "alert", + "attention", + "block", + "blocked", + "cancel", + "cancelled", + "caution", + "danger", + "deactivate", + "deactivated", + "disable", + "disable report", + "disabled", + "enabled", + "error", + "exclamation", + "important", + "mark", + "notification", + "octagon", + "off", + "offline", + "on", + "remove", + "removed", + "report", + "report blocked", + "report deactivated", + "report disabled", + "report off", + "report restricted", + "reporting blocked", + "reporting deactivated", + "reporting disabled", + "reporting off", + "reporting restricted", + "restrict", + "restricted", + "slash", + "stop", + "stopped", + "symbol", + "turn off", + "turn off report", + "warning" + ], + "popularity": 2392 + }, + "REPORT_PROBLEM": { + "tags": [ + "!", + "alert", + "app", + "attention", + "caution", + "danger", + "error", + "exclamation", + "feedback", + "flag", + "hazard", + "important", + "interface", + "issue", + "mark", + "message", + "notification", + "problem", + "report", + "risk", + "security", + "shield", + "sign", + "signal", + "status", + "symbol", + "system", + "triangle", + "ui", + "urgent", + "ux", + "warning", + "website" + ], + "popularity": 85229 + }, + "REQUEST_PAGE": { + "tags": [ + "add", + "add document", + "add file", + "application", + "ask", + "content", + "create", + "data", + "doc", + "document", + "drive", + "file", + "folder", + "folders", + "form", + "form field", + "form submission", + "memo", + "needs", + "new", + "new document", + "new file", + "note", + "page", + "paper", + "plus", + "plus sign", + "query", + "request", + "request form", + "request page", + "require", + "sheet", + "slide", + "submission", + "text", + "writing" + ], + "popularity": 7681 + }, + "REQUEST_QUOTE": { + "tags": [ + "ask for a quote", + "asking", + "bill", + "bubble", + "business", + "card", + "cash", + "chat", + "coin", + "comment", + "commerce", + "communication", + "conversation", + "cost", + "credit", + "currency", + "dialog", + "dialogue", + "dollars", + "estimate", + "finance", + "inquiry", + "message", + "money", + "online", + "pay", + "payment", + "price", + "pricing", + "quotation", + "quote", + "rectangle", + "request", + "request a quote", + "shape", + "shopping", + "speech", + "speech bubble", + "square", + "symbol", + "talk", + "text", + "transaction" + ], + "popularity": 32526 + }, + "RESET_TV": { + "tags": [ + "arrow", + "arrows", + "back", + "button", + "circle", + "circular arrow", + "control", + "cycle", + "device", + "display", + "electronics", + "entertainment", + "hardware", + "loop", + "media", + "monitor", + "option", + "rectangle", + "refresh", + "reload", + "reset", + "restart", + "restore", + "reverse", + "rounded rectangle", + "screen", + "setting", + "square", + "technology", + "television", + "tv", + "undo", + "video" + ], + "popularity": 2064 + }, + "RESTART_ALT": { + "tags": [ + "alt", + "around", + "arrow", + "begin again", + "circular", + "curved", + "cycle", + "inprogress", + "load", + "loading refresh", + "loop", + "play again", + "playback", + "process", + "reboot", + "refresh", + "refresh content", + "refresh data", + "reload", + "renew", + "repeat", + "rerun", + "reset", + "reset data", + "reset form", + "restart", + "restart app", + "restore", + "retry", + "rotation", + "start over", + "sync", + "synchronize", + "turn", + "undo", + "update" + ], + "popularity": 55413 + }, + "RESTAURANT": { + "tags": [ + "bar", + "breakfast", + "breakfast place", + "building", + "cafe", + "cafeteria", + "culinary", + "cutlery", + "dine", + "diner", + "dining", + "dining establishment", + "dinner", + "dinner place", + "eat", + "eatery", + "eating", + "establishment", + "fast food", + "food", + "food court", + "food place", + "food service", + "fork", + "gastronomy", + "knife", + "local", + "lunch", + "lunch place", + "meal", + "place", + "restaurant", + "spoon", + "utensils" + ], + "popularity": 46105 + }, + "RESTAURANT_MENU": { + "tags": [ + "bistro", + "breakfast", + "cafe", + "catering", + "cuisine", + "cutlery", + "dining", + "dining experience", + "dining out", + "dinner", + "dish", + "eat", + "eatery", + "eating utensils", + "food", + "food and drink", + "food service", + "fork", + "gastronomy", + "knife", + "local", + "lunch", + "meal", + "menu", + "plate", + "restaurant", + "restaurant finder", + "setting", + "silverware", + "spoon", + "table setting" + ], + "popularity": 24808 + }, + "RESTORE": { + "tags": [ + "activity", + "arrow", + "back", + "backup", + "backwards", + "circular", + "clear", + "clock", + "cycle", + "data", + "date", + "defaults", + "device", + "factory", + "history", + "home", + "initialize", + "log", + "nest", + "previous", + "reboot", + "recover", + "refresh", + "renew", + "repair", + "reset", + "restart", + "restore", + "retrieve", + "reverse", + "revert", + "rollback", + "rotate", + "save", + "schedule", + "settings", + "system", + "time", + "timeline", + "turn", + "undo", + "update" + ], + "popularity": 23381 + }, + "RESTORE_FROM_TRASH": { + "tags": [ + "action", + "archive", + "archive management", + "arrow", + "back", + "backwards", + "bin", + "bring back", + "circle", + "clock", + "curve", + "data", + "data recovery", + "date", + "delete", + "direction", + "documents", + "files", + "garbage", + "history", + "items", + "management", + "pointing up", + "recover", + "recycle", + "refresh", + "renew", + "restore", + "restore from trash", + "retrieve", + "reverse", + "rotate", + "schedule", + "time", + "trash", + "turn", + "un-delete", + "undo" + ], + "popularity": 7805 + }, + "RESTORE_PAGE": { + "tags": [ + "arrow", + "arrows", + "back", + "browser", + "button", + "circular arrow", + "control", + "data", + "doc", + "document", + "document icon", + "file", + "file icon", + "history", + "page", + "paper", + "previous state", + "refresh", + "reload", + "renew", + "reset", + "restart", + "restore", + "restore page", + "revert", + "rotate", + "sheet", + "storage", + "synchronize", + "ui", + "undo", + "update", + "web page" + ], + "popularity": 6088 + }, + "REVIEWS": { + "tags": [ + "approve", + "attempt", + "best", + "bubble", + "chat", + "comment", + "communicate", + "evaluation", + "excellence", + "favorite", + "feedback", + "gold star", + "grade", + "highlighted", + "important", + "marked", + "message", + "preferred", + "premium", + "quality", + "rank", + "ranking", + "rate", + "rating", + "recommendation", + "recommended", + "review", + "reviews", + "score", + "special", + "speech", + "star", + "top", + "try", + "trying", + "valued" + ], + "popularity": 15676 + }, + "RICE_BOWL": { + "tags": [ + "asian cuisine", + "asian food", + "bowl", + "breakfast", + "carbohydrate", + "ceramic bowl", + "cooking", + "cuisine", + "dining", + "dinner", + "dinnerware", + "dish", + "eating", + "food", + "grains", + "ingredients", + "kitchen", + "lunch", + "meal", + "nutrition", + "oriental food", + "restaurant", + "rice", + "rounded bowl", + "serving", + "serving dish", + "staple food" + ], + "popularity": 2593 + }, + "RING_VOLUME": { + "tags": [ + "adjust", + "alert", + "audio", + "bell", + "call", + "calling", + "cell", + "communication", + "contact", + "control", + "decrease", + "device", + "filled", + "glyph", + "hardware", + "incoming", + "increase", + "level", + "loud", + "mobile", + "mute", + "notification", + "phone", + "ring", + "ringer", + "setting", + "shape", + "silent", + "solid", + "sound", + "speaker", + "symbol", + "telephone", + "ui", + "vibrate", + "volume" + ], + "popularity": 4172 + }, + "ROCKET": { + "tags": [ + "adventure", + "ascent", + "astronaut", + "astronomy", + "boost", + "cosmos", + "discovery", + "engine", + "exploration", + "fast", + "flight", + "futuristic", + "ignition", + "journey", + "launch", + "mission", + "progress", + "projectile", + "propulsion", + "quick", + "rocket", + "science", + "sky", + "space", + "spacecraft", + "spaceship", + "speed", + "start", + "travel", + "universe", + "velocity", + "zoom" + ], + "popularity": 9386 + }, + "ROCKET_LAUNCH": { + "tags": [ + "accelerate", + "ascent", + "astronaut", + "boost", + "cosmic", + "exploration", + "fast", + "flight", + "forward", + "ignition", + "journey", + "launch", + "lift off", + "mission", + "momentum", + "new", + "progress", + "projectile", + "quick", + "rocket", + "science fiction", + "space", + "spaceship", + "speed", + "start", + "startup", + "successful", + "takeoff", + "thrust", + "transport", + "upward", + "vehicle" + ], + "popularity": 32344 + }, + "ROLLER_SHADES": { + "tags": [ + "adjust", + "automation", + "basic", + "blinds", + "close", + "closed", + "control", + "cover", + "coverings", + "curtains", + "decor", + "elevate", + "home", + "horizontal line", + "house", + "interior", + "light", + "lines", + "nest", + "open", + "outline", + "privacy", + "pull down", + "rectangle", + "retractable", + "roller", + "roller shades", + "rolling", + "shade", + "shades", + "shutter", + "simple", + "smart home", + "sunlight", + "sunshade", + "vertical lines", + "window", + "window covering" + ], + "popularity": 1051 + }, + "ROLLER_SHADES_CLOSED": { + "tags": [ + "blinds", + "blinds closed", + "building control", + "closed", + "cover", + "curtains", + "curtains closed", + "down", + "fully closed", + "home automation", + "horizontal lines", + "house", + "indoor", + "interior", + "light blocking", + "lowered", + "nest", + "open", + "privacy", + "rectangle", + "roller", + "roller blinds closed", + "roller shades closed", + "room", + "shade", + "shades closed", + "shutter", + "smart home", + "sun protection", + "sunshade", + "window blinds closed", + "window covering closed", + "window treatment closed" + ], + "popularity": 795 + }, + "ROLLER_SKATING": { + "tags": [ + "active", + "activity", + "athlete", + "athletic", + "blade", + "boot", + "entertainment", + "exercise", + "figure", + "fitness", + "footwear", + "fun", + "hobby", + "human", + "indoor", + "inline skating", + "leisure", + "movement", + "outdoor", + "person", + "recreation", + "roller", + "roller skating", + "rollerblading", + "shoe", + "silhouette", + "skate", + "skates", + "skating", + "social", + "speed", + "sport", + "sports", + "transportation", + "travel", + "wheels" + ], + "popularity": 1038 + }, + "ROOFING": { + "tags": [ + "angle", + "apex", + "architecture", + "builder", + "building", + "chimney", + "commercial", + "construction", + "contractor", + "estate", + "gable", + "home", + "house", + "maintenance", + "peak", + "property", + "protection", + "real", + "real estate", + "repair", + "residence", + "residential", + "roof", + "roof structure", + "roofing", + "roofline", + "service", + "shelter", + "shingle", + "structure", + "tile", + "triangle" + ], + "popularity": 8107 + }, + "ROOM": { + "tags": [ + "address", + "area", + "current location", + "destination", + "direction", + "drop", + "find", + "geography", + "geotag", + "gps", + "landmark", + "locate", + "location", + "map", + "maps", + "marker", + "navigation", + "nearby", + "pin", + "place", + "point of interest", + "pointer", + "position", + "proximity", + "region", + "room", + "route", + "site", + "spot", + "stop", + "teardrop", + "travel", + "venue" + ], + "popularity": 60084 + }, + "ROOM_PREFERENCES": { + "tags": [ + "adjust", + "apartment", + "blueprint", + "building", + "configuration", + "control", + "customise", + "diagram", + "door", + "doorway", + "dwelling", + "edit", + "entrance", + "environment", + "floor plan", + "gear", + "home", + "house", + "interior", + "layout", + "manage", + "map", + "modify", + "office", + "open", + "options", + "personalize", + "plan", + "preferences", + "property", + "real estate", + "room", + "settings", + "space", + "structure", + "user settings" + ], + "popularity": 7587 + }, + "ROOM_SERVICE": { + "tags": [ + "alert", + "amenity", + "bell", + "breakfast", + "call", + "catering", + "cloche", + "cover", + "delivery", + "dining", + "dinner", + "dish", + "dome", + "eat", + "food delivery", + "hospitality", + "hotel", + "lunch", + "luxury", + "meal", + "metal", + "notify", + "order", + "plate", + "restaurant", + "room", + "room service", + "service", + "serving", + "silver", + "travel", + "tray" + ], + "popularity": 8271 + }, + "ROTATE_90_DEGREES_CCW": { + "tags": [ + "90", + "90 degrees", + "action", + "adjustment", + "angle", + "arrow", + "arrows", + "ccw", + "circle section", + "circular arrow", + "control", + "counter-clockwise", + "curve", + "curve arrow", + "degrees", + "direction", + "edit", + "editing", + "geometric", + "image", + "left", + "media", + "orientation", + "photo", + "pivot", + "quadrant", + "reorient", + "rotate", + "rotation", + "spin", + "symbol", + "transform", + "turn", + "visual" + ], + "popularity": 3482 + }, + "ROTATE_90_DEGREES_CW": { + "tags": [ + "90", + "90 degree turn", + "90 degrees", + "adjust", + "angle", + "arrow", + "arrows", + "ccw", + "circle", + "clockwise", + "curved arrow", + "degrees", + "direction", + "edit", + "editing", + "editor", + "image", + "image editor", + "manipulate", + "orientation", + "photo", + "photo editor", + "pivot", + "right turn", + "rotate", + "rotation", + "spinning", + "swiveling", + "tool", + "transformation", + "turn", + "turning" + ], + "popularity": 2436 + }, + "ROTATE_LEFT": { + "tags": [ + "action", + "adjust", + "around", + "arrow", + "back", + "change", + "circle", + "circular arrow", + "counter-clockwise", + "curved arrow", + "dash", + "dashed", + "direction", + "edit", + "history", + "inprogress", + "left", + "load", + "loading refresh", + "manipulation", + "orient", + "orientation", + "previous", + "redo", + "refresh", + "reload", + "renew", + "reverse", + "revert", + "rotate", + "rotate left", + "rotation", + "spin", + "step back", + "turn", + "turn back", + "undo" + ], + "popularity": 7716 + }, + "ROTATE_RIGHT": { + "tags": [ + "action", + "app", + "around", + "arrow", + "button", + "change direction", + "circular", + "circular arrow", + "control", + "counter-clockwise", + "curve", + "direction", + "element", + "history", + "icon", + "inprogress", + "interface", + "load", + "loading refresh", + "loop", + "pointer", + "redo", + "refresh", + "reload", + "renew", + "repeat", + "restart", + "revert", + "right", + "rotate", + "rotate right", + "shape", + "spin right", + "symbol", + "turn", + "turn right", + "ui", + "undo", + "web" + ], + "popularity": 10980 + }, + "ROUNDABOUT_LEFT": { + "tags": [ + "arrow", + "arrows", + "circle", + "circular intersection", + "curved arrow", + "detour", + "direction", + "directions", + "driving", + "flow", + "gps", + "guidance", + "intersection", + "left", + "left turn", + "map", + "maps", + "movement", + "navigation", + "path", + "road", + "road sign", + "roundabout", + "route", + "sign", + "signage", + "street", + "traffic", + "traffic circle", + "transportation", + "travel", + "turn", + "u-turn", + "waypoint" + ], + "popularity": 736 + }, + "ROUNDABOUT_RIGHT": { + "tags": [ + "arrow", + "arrows", + "circular intersection", + "crossroads", + "curved arrow", + "direction", + "direction arrow", + "directions", + "driving", + "flow", + "gps", + "guidance", + "highway", + "infrastructure", + "junction", + "map", + "maps", + "mobility", + "motor vehicle", + "navigate", + "navigation", + "path", + "right", + "right turn", + "road", + "road sign", + "roundabout", + "route", + "sign", + "street", + "traffic", + "traffic circle", + "traffic management", + "transport", + "transport infrastructure", + "turn", + "wayfinding" + ], + "popularity": 974 + }, + "ROUNDED_CORNER": { + "tags": [ + "adjust", + "border", + "boundary", + "box", + "chamfer", + "corner", + "curve", + "customization", + "dash", + "dashed", + "design", + "edge", + "edit", + "element", + "fillet", + "format", + "geometry", + "graphic", + "outline", + "properties", + "radius", + "rectangle", + "rounded", + "rounded corner", + "settings", + "shape", + "shape editor", + "smooth", + "soft", + "square", + "style", + "transform", + "ui control", + "visual" + ], + "popularity": 2590 + }, + "ROUTE": { + "tags": [ + "connection", + "connection line", + "course", + "destination", + "direction line", + "directions", + "endpoint", + "itinerary", + "journey", + "line", + "map", + "map line", + "maps", + "navigation", + "navigation line", + "path", + "plotting", + "point a to point b", + "road", + "route", + "route line", + "sign", + "starting point", + "street", + "trace", + "track", + "traffic", + "trail", + "travel", + "travel path", + "travel plan", + "two points" + ], + "popularity": 11340 + }, + "ROUTER": { + "tags": [ + "access point", + "box", + "broadband", + "cable", + "communication", + "computer", + "computer network", + "connection", + "connectivity", + "curved lines", + "data", + "device", + "equipment", + "hardware", + "home network", + "internet", + "internet access", + "lines", + "modem", + "network", + "office network", + "rectangle", + "router", + "server", + "signal", + "square", + "technology", + "technology device", + "telecommunications", + "wifi", + "wireless", + "wireless network" + ], + "popularity": 9977 + }, + "ROWING": { + "tags": [ + "activity", + "athlete", + "boat", + "body", + "canoe", + "competitive", + "exercise", + "figure", + "fitness", + "human", + "journey", + "lake", + "leisure", + "line", + "oar", + "outline", + "paddle", + "people", + "person", + "race", + "recreation", + "river", + "row", + "rowboat", + "rowing", + "sea", + "shape", + "simple", + "sport", + "stream", + "transportation", + "vessel", + "water", + "workout" + ], + "popularity": 6331 + }, + "RSS_FEED": { + "tags": [ + "antenna", + "application", + "arc", + "atom", + "blog", + "broadcast", + "channel", + "circle", + "communication", + "connection", + "content", + "curve", + "data", + "distribution", + "dot", + "feed", + "information", + "internet", + "network", + "news", + "online", + "point", + "pulsate", + "radiate", + "rss", + "service", + "signal", + "streaming", + "subscribe", + "syndication", + "updates", + "waves", + "web", + "website", + "wifi", + "wireless" + ], + "popularity": 17015 + }, + "RSVP": { + "tags": [ + "accept", + "accepted", + "acknowledged", + "affirmed", + "agree", + "alphabet", + "attendance", + "attended", + "attending", + "box", + "character", + "check", + "checkbox", + "complete", + "confirm", + "confirmation", + "confirmed", + "done", + "event", + "font", + "invitation", + "invite", + "letters", + "mark", + "plaît", + "replied", + "reply", + "respond", + "response", + "rsvp", + "répondez", + "select", + "sil", + "success", + "symbol", + "text", + "true", + "type", + "validated", + "vous", + "yes" + ], + "popularity": 1237 + }, + "RTT": { + "tags": [ + "accessibility", + "aid", + "assistance", + "button", + "call", + "chat", + "closed captioning", + "communication", + "control", + "conversation", + "deaf", + "direct", + "feature", + "hard of hearing", + "hearing impaired", + "icon", + "keyboard", + "live captions", + "live text", + "message", + "option", + "phone", + "real", + "real time", + "relay", + "rrt", + "rtt", + "setting", + "speech to text", + "symbol", + "telephone", + "text", + "time", + "typing" + ], + "popularity": 1877 + }, + "RULE": { + "tags": [ + "approve", + "automation", + "check", + "command", + "commands", + "complete", + "condition", + "conditions", + "configuration", + "configurations", + "criteria", + "done", + "govern", + "guideline", + "guidelines", + "incomplete", + "instruction", + "instructions", + "law", + "laws", + "line", + "logic", + "mark", + "missing", + "no", + "ok", + "policies", + "policy", + "principle", + "principles", + "regulate", + "regulation", + "regulations", + "rule", + "rules", + "select", + "setting", + "settings", + "standard", + "standards", + "tick", + "validate", + "verified", + "workflow", + "wrong", + "x", + "yes" + ], + "popularity": 26637 + }, + "RULE_FOLDER": { + "tags": [ + "administration", + "approve", + "archive", + "archive folder", + "business", + "cancel", + "check", + "close", + "collection", + "complete", + "data", + "directory", + "doc", + "document", + "document folder", + "document management", + "done", + "drive", + "exit", + "file", + "file management", + "folder", + "guideline", + "library", + "management", + "mark", + "no", + "office", + "ok", + "organization", + "organization folder", + "policy", + "policy folder", + "regulations", + "remove", + "repository", + "rule", + "rules", + "select", + "sheet", + "slide", + "standards", + "storage", + "structure", + "system", + "tick", + "validate", + "verified", + "x", + "yes" + ], + "popularity": 5182 + }, + "RUN_CIRCLE": { + "tags": [ + "action", + "active", + "activity", + "athletics", + "begin", + "body", + "button", + "circle", + "continue", + "control", + "exercise", + "figure", + "glyph", + "human", + "jogging", + "media", + "movement", + "people", + "person", + "play", + "progress", + "race", + "rounded", + "run", + "running", + "silhouette", + "sport", + "sprint", + "start", + "symbol", + "track", + "workout" + ], + "popularity": 4164 + }, + "RUNNING_WITH_ERRORS": { + "tags": [ + "!", + "activity", + "alert", + "attention", + "blocked", + "busy", + "caution", + "danger", + "debugging", + "duration", + "error", + "errors", + "exclamation", + "execution", + "failed", + "failure", + "important", + "incomplete", + "interrupted", + "issue", + "loading", + "mark", + "notification", + "ongoing", + "operation", + "problem", + "process", + "processing", + "progress", + "running", + "running with errors", + "status", + "stop", + "symbol", + "task", + "time", + "triangle", + "troubleshooting", + "warning", + "with" + ], + "popularity": 6787 + }, + "RV_HOOKUP": { + "tags": [ + "arrow", + "attach", + "automobile", + "automotive", + "back", + "camper", + "camping", + "campsite", + "car", + "cars", + "connect", + "connection", + "destination", + "direction", + "electric hookup", + "hookup", + "left", + "lodging", + "maps", + "motorhome", + "outdoor", + "park", + "parking", + "parking space", + "power hookup", + "public", + "recreation", + "recreational vehicle", + "right", + "road trip", + "rv", + "sewage hookup", + "trailer", + "transportation", + "travel", + "truck", + "vacation", + "van", + "vehicle", + "water hookup" + ], + "popularity": 3193 + }, + "SAFETY_CHECK": { + "tags": [ + "approved", + "authentic", + "authentication", + "certified", + "check", + "clock", + "confirmed", + "confirmed status", + "coverage", + "guarantee", + "guarantee symbol", + "guard", + "health", + "insurance", + "privacy", + "private", + "protect", + "protection", + "protection shield", + "safe", + "safety", + "safety check", + "schedule", + "secure", + "secure check", + "secure transaction", + "security", + "shield", + "time", + "trust", + "validated", + "validation", + "verification", + "verified", + "verified identity", + "wellness" + ], + "popularity": 2847 + }, + "SAFETY_DIVIDER": { + "tags": [ + "apart", + "barrier", + "border", + "boundary", + "delineate", + "demarcation", + "distance", + "divide", + "divider", + "enclosed", + "fenced", + "guarded", + "horizontal line", + "horizontal rule", + "isolate", + "limit", + "line", + "line break", + "line segment", + "protect", + "rule", + "rule off", + "safety", + "section", + "secure", + "security", + "segment", + "separate", + "separation", + "social", + "space" + ], + "popularity": 3391 + }, + "SAILING": { + "tags": [ + "adventure", + "aquatic", + "boat", + "boating", + "cruise", + "entertainment", + "explore", + "fishing", + "hobby", + "hull", + "journey", + "leisure", + "lines", + "marine", + "maritime", + "mast", + "nautical", + "ocean", + "recreation", + "sail", + "sailboat", + "sailing", + "sea", + "ship", + "social sports", + "sport", + "transportation", + "travel", + "triangle", + "vessel", + "voyage", + "water", + "watercraft", + "yacht" + ], + "popularity": 8282 + }, + "SANITIZER": { + "tags": [ + "anti-bacterial", + "bacteria", + "bathroom", + "bottle", + "clean", + "clean hands", + "cleaning", + "covid", + "covid-19", + "disinfect", + "disinfectant", + "dispense", + "epidemic", + "gel", + "germ", + "germs", + "handwash", + "health", + "healthcare", + "hospital", + "hygiene", + "kill", + "liquid", + "lotion", + "medical", + "pandemic", + "personal care", + "protect", + "public health", + "pump", + "pump bottle", + "sanitizer", + "soap", + "virus" + ], + "popularity": 4985 + }, + "SATELLITE": { + "tags": [ + "antenna", + "astronomy", + "bluetooth", + "broadcast", + "communication", + "connect", + "connection", + "connectivity", + "data", + "device", + "dish", + "earth", + "future", + "global", + "gps", + "image", + "internet", + "landscape", + "location", + "mapping", + "maps", + "mountain", + "mountains", + "navigation", + "network", + "orbit", + "orbital", + "photo", + "photography", + "picture", + "planet", + "radar", + "receiving", + "satellite", + "scan", + "science", + "service", + "signal", + "space", + "symbol", + "technology", + "tracking", + "transmission", + "wifi", + "wireless", + "world" + ], + "popularity": 3515 + }, + "SATELLITE_ALT": { + "tags": [ + "alternative", + "antenna", + "artificial", + "astronomy", + "broadcast", + "celestial", + "communication", + "connection", + "cosmos", + "data", + "dish", + "earth", + "futuristic", + "global", + "gps", + "link", + "navigation", + "network", + "orbit", + "orbital", + "relay", + "remote", + "satellite", + "science", + "signal", + "solar panel", + "space", + "space station", + "technology", + "telecommunications", + "television", + "transmission" + ], + "popularity": 5525 + }, + "SAVE": { + "tags": [ + "action", + "backup", + "button", + "computer", + "control", + "data", + "disk", + "document", + "drive", + "file", + "flat", + "floppy", + "function", + "memory", + "multimedia", + "object", + "old technology", + "progress", + "recording", + "retro", + "save", + "save button", + "save icon", + "shape", + "solid", + "storage", + "store", + "tool", + "vintage" + ], + "popularity": 89343 + }, + "SAVE_ALT": { + "tags": [ + "acquire", + "action", + "alt", + "app", + "application", + "archive", + "arrow", + "bar", + "button", + "cloud", + "computer", + "control", + "data", + "disk", + "document", + "down", + "download", + "file", + "floppy", + "get", + "incoming", + "internet", + "line", + "move", + "multimedia", + "network", + "obtain", + "pointed", + "receive", + "save", + "storage", + "symbol", + "transfer", + "underscore" + ], + "popularity": 24885 + }, + "SAVE_AS": { + "tags": [ + "archive", + "backup", + "classic", + "compose", + "computer", + "copy", + "create", + "data", + "disk", + "diskette", + "document", + "download", + "draft", + "drive", + "duplicate", + "edit", + "editing", + "export", + "file", + "floppy", + "floppy disk", + "information", + "input", + "multimedia", + "new file", + "office", + "old", + "paper", + "pen", + "pencil", + "rectangle", + "rename", + "retro", + "save", + "save as", + "square", + "storage", + "vintage", + "write", + "writing" + ], + "popularity": 7578 + }, + "SAVED_SEARCH": { + "tags": [ + "archive", + "bookmark", + "collection", + "criteria", + "data", + "discover", + "explore", + "favorite", + "filter", + "find", + "glass", + "highlight", + "important", + "information", + "inquiry", + "keep", + "list", + "locate", + "look", + "lookup", + "magnify", + "magnifying", + "magnifying glass", + "mark", + "marked", + "monitor", + "query", + "records", + "remember", + "results", + "saved", + "saved search", + "scope", + "search", + "see", + "star", + "storage", + "track" + ], + "popularity": 9192 + }, + "SAVINGS": { + "tags": [ + "account", + "bank", + "banking", + "banking icon", + "bill", + "budget", + "card", + "cash", + "coin", + "commerce", + "cost", + "credit", + "currency", + "currency exchange", + "deposit", + "dollars", + "earnings", + "economy", + "finance", + "financial literacy", + "financial planning", + "fund", + "income", + "investment", + "money", + "online", + "pay", + "payment", + "pig", + "piggy", + "piggy bank", + "reserve", + "revenue", + "saving", + "savings", + "symbol", + "transaction", + "wealth", + "wealth creation", + "wealth management" + ], + "popularity": 60678 + }, + "SCALE": { + "tags": [ + "balance", + "balance scale", + "compare", + "compare measure", + "compare weight", + "comparing", + "comparison", + "courtroom", + "equilibrium", + "equity", + "judgment", + "justice", + "law", + "legal", + "legal system", + "measure", + "measurement", + "monitor", + "scale", + "scales of justice", + "weighing", + "weighing instrument", + "weight", + "weight measurement", + "⚖️", + "⚖️ icon", + "⚖️ symbol" + ], + "popularity": 6129 + }, + "SCANNER": { + "tags": [ + "authenticate", + "barcode", + "box", + "camera", + "code", + "copy", + "corner", + "cyber", + "data", + "detection", + "device", + "digital", + "document", + "electronic", + "hardware", + "identify", + "information", + "laser", + "lens", + "line", + "machine", + "mobile", + "optical", + "product", + "qrcode", + "read", + "reader", + "recognition", + "scan", + "scanner", + "search", + "square", + "technology", + "verify" + ], + "popularity": 2850 + }, + "SCATTER_PLOT": { + "tags": [ + "analysis", + "analysis icon", + "analytics", + "bar", + "bars", + "chart", + "chart icon", + "circles", + "comparison", + "coordinate system", + "correlation", + "data", + "data icon", + "diagram", + "distribution", + "dot", + "dots", + "graph", + "graph icon", + "infographic", + "mathematics", + "measure", + "metrics", + "pattern", + "plot", + "plotting", + "points", + "relationship", + "report", + "research", + "scatter", + "scatter plot", + "science", + "spread", + "statistics", + "statistics icon", + "tracking", + "trend", + "visualization", + "x-axis", + "y-axis" + ], + "popularity": 5962 + }, + "SCHEDULE": { + "tags": [ + "alarm", + "appointment", + "calendar", + "chronometer", + "clock", + "countdown", + "date", + "deadline", + "delay", + "duration", + "event", + "future", + "history", + "hour", + "minute", + "organize", + "past", + "pending", + "period", + "plan", + "present", + "recent", + "reminder", + "schedule", + "second", + "stopwatch", + "time", + "timer", + "upcoming", + "waiting", + "watch" + ], + "popularity": 208442 + }, + "SCHEDULE_SEND": { + "tags": [ + "agenda", + "appointment", + "arrow", + "calendar", + "circle", + "clock", + "date", + "delivery", + "dispatch", + "email", + "event", + "forward", + "forward message", + "future", + "letters", + "mail", + "message", + "notification", + "organize", + "pending", + "planner", + "planning", + "remember", + "reminder", + "right arrow", + "schedule", + "send", + "share", + "time", + "transfer", + "transmit" + ], + "popularity": 12828 + }, + "SCHEMA": { + "tags": [ + "analytics", + "architecture", + "blueprint", + "boxes", + "chart", + "conceptual", + "connections", + "data", + "database", + "diagram", + "flow", + "flowchart", + "graph", + "grid", + "hierarchy", + "infographic", + "layout", + "links", + "logic", + "map", + "mapping", + "measure", + "metrics", + "model", + "network", + "organization", + "plan", + "process", + "relationships", + "representation", + "schema", + "squares", + "statistics", + "structure", + "system", + "tracking", + "tree", + "visual" + ], + "popularity": 8096 + }, + "SCHOOL": { + "tags": [ + "academic", + "academics", + "academy", + "achievement", + "architecture", + "building", + "building facade", + "campus", + "cap", + "class", + "college", + "college building", + "columns", + "doorway", + "education", + "educational institution", + "entrance", + "entrance way", + "gateway", + "graduation", + "hat", + "institution", + "knowledge", + "learning", + "learning institution", + "pillars", + "portal", + "public building", + "school", + "steps", + "structure", + "student", + "studying", + "teaching", + "university", + "university building" + ], + "popularity": 100467 + }, + "SCIENCE": { + "tags": [ + "analysis", + "beaker", + "beaker icon", + "chemical", + "chemistry", + "chemistry icon", + "container", + "discovery", + "education", + "experiment", + "experiment icon", + "flask", + "fluid", + "glass", + "glassware", + "innovation", + "knowledge", + "lab", + "lab icon", + "laboratory", + "learning", + "liquid", + "reaction", + "research", + "research icon", + "science", + "scientific", + "solution", + "study", + "test tube", + "tube" + ], + "popularity": 27589 + }, + "SCORE": { + "tags": [ + "2k", + "achievement", + "alphabet", + "amount", + "analytics", + "bar", + "bars", + "character", + "chart", + "count", + "data", + "diagram", + "digit", + "education", + "evaluation", + "figure", + "finance", + "font", + "gaming", + "gauge", + "graph", + "indicator", + "infographic", + "letters", + "measure", + "measurement", + "metric", + "metrics", + "number", + "numbers", + "performance", + "points", + "quantity", + "ranking", + "record", + "result", + "score", + "sports", + "statistics", + "sum", + "symbol", + "tally", + "text", + "total", + "tracking", + "type", + "value" + ], + "popularity": 2838 + }, + "SCOREBOARD": { + "tags": [ + "board", + "competition", + "data", + "display", + "game", + "information", + "leader", + "lines", + "losing", + "match", + "monitor", + "numbers", + "performance", + "points", + "presentation", + "ranking", + "record", + "rectangular", + "report", + "results", + "score", + "scoreboard", + "screen", + "sport", + "sports", + "statistics", + "stats", + "tally", + "tracking", + "winners" + ], + "popularity": 2107 + }, + "SCREEN_LOCK_LANDSCAPE": { + "tags": [ + "access", + "android", + "device", + "device lock", + "display", + "hardware", + "horizontal", + "ios", + "landscape", + "lock", + "locked", + "mobile", + "mobile lock", + "orientation", + "orientation lock", + "os", + "padlock", + "phone", + "privacy", + "private", + "protection", + "rectangle", + "restricted", + "rotate", + "rotation", + "safety", + "screen", + "screen lock", + "secured", + "security", + "sign", + "symbol", + "tablet", + "technology", + "unlock" + ], + "popularity": 1151 + }, + "SCREEN_LOCK_PORTRAIT": { + "tags": [ + "access", + "access control", + "android", + "authentication", + "cell", + "cell phone", + "connection", + "control", + "device", + "erase", + "hardware", + "ios", + "lock", + "locked", + "mobile", + "os", + "password", + "phone", + "phonelink", + "pin", + "portrait", + "privacy", + "private", + "protect", + "protection", + "restricted", + "restriction", + "safety", + "screen", + "screen lock", + "secure", + "secure device", + "security", + "smartphone", + "tablet", + "unlock" + ], + "popularity": 1697 + }, + "SCREEN_LOCK_ROTATION": { + "tags": [ + "access", + "accessibility", + "android", + "arrow", + "circle", + "clockwise", + "control", + "counter-clockwise", + "curved", + "device", + "diagonal", + "display", + "hardware", + "ios", + "landscape", + "lock", + "locked", + "mobile", + "option", + "orientation", + "os", + "phone", + "portrait", + "privacy", + "protected", + "restricted", + "rotate", + "rotation", + "screen", + "security", + "setting", + "tablet", + "turn", + "unlocked" + ], + "popularity": 1154 + }, + "SCREEN_ROTATION": { + "tags": [ + "adjust", + "android", + "arrow", + "arrows", + "circle", + "circular", + "clockwise", + "control", + "counter clockwise", + "device", + "directional", + "display", + "hardware", + "ios", + "landscape", + "mobile", + "movement", + "orientation", + "os", + "phone", + "portrait", + "rotate", + "rotation", + "round", + "screen", + "settings", + "switch", + "tablet", + "toggle", + "turn", + "view" + ], + "popularity": 4449 + }, + "SCREEN_ROTATION_ALT": { + "tags": [ + "adjust", + "alter", + "alternate", + "alternative", + "android", + "arrow", + "change", + "circle", + "circular", + "control", + "counter clockwise", + "counterclockwise", + "device", + "direction", + "display", + "flip", + "hardware", + "ios", + "landscape", + "mobile", + "orientation", + "os", + "phone", + "portrait", + "refresh", + "reload", + "rotate", + "rotation", + "screen", + "screen rotation", + "setting", + "switch", + "tablet", + "turn" + ], + "popularity": 1101 + }, + "SCREEN_SEARCH_DESKTOP": { + "tags": [ + "android", + "application", + "arrow", + "browser", + "computer", + "desktop", + "device", + "digital", + "discover", + "display", + "electronic", + "explore", + "find", + "glass", + "hardware", + "information", + "ios", + "lens", + "lines", + "lock", + "look", + "magnify", + "magnifying glass", + "monitor", + "os", + "program", + "rectangle", + "rotate", + "screen", + "screen search desktop", + "search", + "square", + "technology", + "web", + "website", + "window", + "zoom" + ], + "popularity": 4587 + }, + "SCREEN_SHARE": { + "tags": [ + "android", + "arrow", + "broadcast", + "cast", + "casting", + "chrome", + "collaboration", + "computer", + "connect", + "connection", + "desktop", + "device", + "display", + "hardware", + "ios", + "laptop", + "mac", + "meeting", + "mirror", + "monitor", + "network", + "online", + "os", + "present", + "presentation", + "projection", + "projection screen", + "rectangular", + "remote", + "screen", + "screen share", + "share", + "sharing", + "showing", + "stream", + "streaming", + "upward", + "video", + "web", + "webinar", + "window" + ], + "popularity": 7304 + }, + "SCREENSHOT": { + "tags": [ + "android", + "app", + "application", + "art", + "camera", + "capture", + "cell", + "computer", + "crop", + "desktop", + "device", + "digital", + "display", + "electronic", + "flat", + "glyph", + "graphic", + "hardware", + "image", + "ios", + "laptop", + "media", + "mobile", + "monitor", + "os", + "outline", + "phone", + "photo", + "picture", + "screen", + "screenshot", + "shot", + "symbol", + "tablet", + "technology", + "window" + ], + "popularity": 3088 + }, + "SCREENSHOT_MONITOR": { + "tags": [ + "android", + "application", + "camera", + "capture", + "chrome", + "computer", + "desktop", + "device", + "digital", + "display", + "electronic", + "grab", + "hardware", + "image", + "ios", + "mac", + "media", + "monitor", + "os", + "photo", + "picture", + "print screen", + "program", + "record", + "rectangle", + "screen", + "screengrab", + "screenshot", + "snapshot", + "technology", + "ui", + "video", + "web", + "website", + "window" + ], + "popularity": 2009 + }, + "SCUBA_DIVING": { + "tags": [ + "activity", + "adventure", + "aquatic", + "deep sea", + "discovery", + "diver", + "diving", + "entertainment", + "equipment", + "exercise", + "expedition", + "explore", + "fins", + "flippers", + "gear", + "hobby", + "holiday", + "journey", + "leisure", + "marine", + "mask", + "ocean", + "recreation", + "scuba", + "scuba diving", + "sea", + "snorkel", + "social", + "sport", + "swim", + "swimming", + "tank", + "travel", + "underwater", + "vacation", + "water sport" + ], + "popularity": 1220 + }, + "SD": { + "tags": [ + "access", + "alphabet", + "authorized", + "camera", + "card", + "character", + "circle", + "circle lock", + "confidential", + "data", + "data security", + "data storage", + "device", + "digital", + "document", + "document with lock", + "drive", + "encrypted", + "file", + "flash", + "folder", + "font", + "image", + "information", + "key", + "letters", + "lock", + "memory", + "password", + "photo", + "private", + "protection", + "safebox", + "sd", + "secure", + "security", + "sensitive", + "storage", + "symbol", + "text", + "type" + ], + "popularity": 1440 + }, + "SD_CARD": { + "tags": [ + "angled corner", + "camera", + "card", + "computer", + "data", + "data storage", + "device", + "digital", + "digital media", + "documents", + "electronic", + "electronics", + "external storage", + "file management", + "file storage", + "information", + "loading", + "media", + "memory", + "memory card", + "micro sd", + "multimedia", + "music storage", + "photo storage", + "photos", + "portable storage", + "removable storage", + "saving", + "sd", + "sd card", + "secure", + "square", + "storage", + "technology", + "transfer", + "trapezoid", + "video storage" + ], + "popularity": 3087 + }, + "SD_CARD_ALERT": { + "tags": [ + "!", + "alert", + "attention", + "camera", + "card", + "caution", + "chip", + "communication", + "danger", + "data", + "device", + "digital", + "electronic", + "error", + "exclamation", + "exclamation point", + "fail", + "failed", + "hardware", + "important", + "indication", + "indicator", + "issue", + "mark", + "memory", + "mobile", + "network", + "notification", + "phone", + "photos", + "problem", + "sd", + "sd card", + "secure", + "sim card", + "slot", + "status", + "storage", + "symbol", + "triangle", + "warning" + ], + "popularity": 1796 + }, + "SD_STORAGE": { + "tags": [ + "angled corner", + "camera", + "card", + "computer", + "data", + "data storage", + "device", + "digital", + "digital media", + "documents", + "electronic", + "electronics", + "external storage", + "file management", + "file storage", + "information", + "loading", + "media", + "memory", + "memory card", + "micro sd", + "multimedia", + "music storage", + "photo storage", + "portable storage", + "removable storage", + "saving", + "sd", + "sd card", + "secure", + "square", + "storage", + "technology", + "transfer", + "trapezoid", + "video storage" + ], + "popularity": 2165 + }, + "SEARCH": { + "tags": [ + "browse", + "circle", + "discover", + "discover icon", + "explore", + "explore icon", + "filter", + "find", + "find icon", + "glass", + "handle", + "inspect", + "investigate", + "locate", + "locate icon", + "look", + "magnifier", + "magnify", + "magnifying", + "mode", + "options", + "query", + "query icon", + "scope", + "search", + "search bar", + "search button", + "see", + "stick", + "tool", + "view", + "zoom" + ], + "popularity": 862048 + }, + "SEARCH_OFF": { + "tags": [ + "access denied", + "blocked", + "blocked access", + "cancel", + "cancel search", + "circle", + "clear", + "clear search", + "close", + "close search", + "cross out", + "diagonal line", + "disabled", + "disallowed search", + "enabled", + "find", + "find blocked", + "find disabled", + "find off", + "forbidden search", + "glass", + "lens", + "look", + "magnify", + "magnify blocked", + "magnify disabled", + "magnify glass", + "magnify off", + "magnifying", + "no access", + "no results", + "not found", + "off", + "on", + "prohibited", + "remove", + "remove search", + "restricted", + "restricted search", + "search", + "search access denied", + "search blocked", + "search disabled", + "search off", + "search prevented", + "search stopped", + "search unavailable", + "see", + "slash", + "stop", + "unavailable", + "x" + ], + "popularity": 10261 + }, + "SECURITY": { + "tags": [ + "access", + "allowed", + "authentication", + "certified", + "data security", + "defense", + "encrypted", + "guard", + "mobile security", + "network security", + "permission", + "privacy", + "privacy policy", + "private", + "protect", + "protected", + "protection", + "safe", + "safety", + "secure", + "secure access", + "secure connection", + "secure data", + "security", + "shield", + "ssl", + "system security", + "trust", + "trusted", + "verified", + "vpn", + "web security" + ], + "popularity": 34029 + }, + "SECURITY_UPDATE": { + "tags": [ + "android", + "app", + "app install", + "app promo", + "arrow", + "device", + "down", + "down arrow", + "download", + "download app", + "hardware", + "install", + "install app", + "install mobile", + "ios", + "marketing", + "mobile", + "mobile download", + "os", + "phone", + "phone download", + "promotion", + "security", + "security update", + "software", + "software update", + "system", + "system update", + "system upgrade", + "tablet", + "update", + "upgrade" + ], + "popularity": 2224 + }, + "SECURITY_UPDATE_GOOD": { + "tags": [ + "android", + "approve", + "approved", + "cell", + "check", + "checkmark", + "complete", + "device", + "display", + "done", + "friendly", + "good", + "hardware", + "icon", + "ios", + "mark", + "mobile", + "mobile check", + "mobile phone", + "ok", + "os", + "phone", + "protection", + "safe", + "screen", + "secure", + "security", + "security update", + "select", + "smartphone", + "success", + "symbol", + "system", + "system update", + "tablet", + "technology", + "tick", + "ui", + "update", + "validate", + "validated", + "verified", + "yes" + ], + "popularity": 2911 + }, + "SECURITY_UPDATE_WARNING": { + "tags": [ + "!", + "alert", + "android", + "attention", + "bug", + "caution", + "critical", + "danger", + "device", + "download", + "error", + "exclamation", + "fix", + "hardware", + "hazard", + "important", + "ios", + "issue", + "mark", + "mobile", + "notification", + "os", + "patch", + "phone", + "portrait", + "precaution", + "problem", + "protection", + "screen", + "secure", + "security", + "shield", + "symbol", + "system", + "tablet", + "threat", + "triangle", + "update", + "vulnerability", + "warning" + ], + "popularity": 1819 + }, + "SEGMENT": { + "tags": [ + "alignment", + "analytics", + "analyze", + "breakdown", + "categorize", + "chart", + "chunk", + "classify", + "component", + "data", + "diagram", + "divided", + "division", + "element", + "fonts", + "format", + "fragment", + "graph", + "group", + "isolate", + "lines", + "list", + "modular", + "modularity", + "paragraph", + "part", + "piece", + "portion", + "rule", + "rules", + "section", + "segment", + "separate", + "slice", + "split", + "style", + "subset", + "text" + ], + "popularity": 13214 + }, + "SELECT_ALL": { + "tags": [ + "all", + "batch", + "box", + "bulk", + "check", + "choose", + "collection", + "collective", + "complete", + "comprehensive", + "dash", + "dashed", + "everything", + "full", + "group", + "highlight", + "items", + "list", + "mark", + "multiple", + "options", + "outline", + "pick", + "select", + "select all", + "selection", + "square", + "tool", + "total" + ], + "popularity": 8151 + }, + "SELF_IMPROVEMENT": { + "tags": [ + "balance", + "body", + "brain", + "calm", + "care", + "chi", + "coaching", + "counseling", + "development", + "emotional", + "growth", + "healing", + "health", + "help", + "human", + "improvement", + "life", + "meditate", + "meditation", + "mental", + "mind", + "mindfullness", + "peace", + "people", + "person", + "personal", + "progress", + "relax", + "self", + "self-care", + "sitting", + "spiritual", + "support", + "therapy", + "well-being", + "wellbeing", + "wellness", + "yoga", + "zen" + ], + "popularity": 19244 + }, + "SELL": { + "tags": [ + "bargain", + "bill", + "card", + "cart", + "cash", + "coin", + "commerce", + "coupon", + "credit", + "currency", + "deal", + "discount", + "dollars", + "label", + "market", + "money", + "offer", + "online", + "pay", + "payment", + "pointed shape", + "price", + "promotion", + "retail", + "sale", + "sell", + "shape", + "shop", + "shopping", + "special offer", + "store", + "tag", + "tag shape", + "voucher" + ], + "popularity": 37670 + }, + "SEND": { + "tags": [ + "action", + "airplane", + "arrow", + "chat", + "communication", + "complete", + "data", + "deliver", + "direct message", + "dispatch", + "document", + "email", + "flight", + "form", + "forward", + "give", + "mail", + "message", + "outgoing", + "paper", + "paper plane", + "plane", + "point", + "post", + "publish", + "reply", + "right", + "send", + "share", + "submit", + "transfer", + "transmit", + "upload" + ], + "popularity": 131092 + }, + "SEND_AND_ARCHIVE": { + "tags": [ + "archive", + "arrow", + "box", + "chat", + "chat message", + "communication", + "compose", + "deliver", + "dispatch", + "document", + "down", + "download", + "email", + "email message", + "file", + "folder", + "inbox", + "instant message", + "letters", + "mail", + "mail message", + "message", + "move", + "move to archive", + "outbox", + "quick action", + "reply", + "save", + "send", + "send and archive", + "share", + "store", + "store message" + ], + "popularity": 4746 + }, + "SEND_TIME_EXTENSION": { + "tags": [ + "action", + "add", + "add time", + "arrow", + "button", + "clock", + "communication", + "delay", + "deliver", + "dispatch", + "email", + "envelop", + "extend", + "extension", + "future", + "internet", + "mail", + "message", + "paper plane", + "plus", + "plus sign", + "postpone", + "right arrow", + "schedule", + "send", + "send button", + "send later", + "share", + "submit", + "time", + "timer", + "triangle", + "watch", + "web" + ], + "popularity": 1801 + }, + "SEND_TO_MOBILE": { + "tags": [ + "abstract", + "action", + "android", + "arrow", + "cellular", + "communication", + "connect", + "data transfer", + "device", + "direction", + "export", + "forward", + "hardware", + "ios", + "line", + "mobile", + "move", + "navigation", + "open", + "open in phone", + "open link", + "open on device", + "os", + "phone", + "pointer", + "push to device", + "redirect", + "right", + "send", + "send to mobile", + "share", + "smartphone", + "symbol", + "tablet", + "technology", + "to", + "transfer" + ], + "popularity": 4949 + }, + "SENSOR_DOOR": { + "tags": [ + "access", + "access point", + "alarm", + "alert", + "automation", + "close", + "detect", + "door", + "entrance", + "entry", + "entry point", + "exit", + "gateway", + "home security", + "indication", + "monitoring", + "open", + "opening", + "passage", + "portal", + "secure", + "security", + "security system", + "sensor", + "smart home", + "state", + "status", + "status indication", + "threshold" + ], + "popularity": 7283 + }, + "SENSOR_OCCUPIED": { + "tags": [ + "activated", + "active", + "alarm", + "alert", + "automation", + "body", + "body response", + "connection", + "detection", + "detection sensor", + "fitbit", + "human", + "human sensor", + "indicator", + "motion", + "motion sensor", + "movement", + "network", + "occupant", + "occupied", + "occupied sensor", + "people", + "person", + "person sensor", + "presence", + "presence sensor", + "scan", + "security", + "sensor", + "sensors", + "signal", + "smart body scan sensor", + "smart home", + "status", + "status indicator", + "surveillance", + "technology", + "wireless" + ], + "popularity": 2513 + }, + "SENSOR_WINDOW": { + "tags": [ + "alarm", + "area", + "border", + "boundary", + "camera", + "data", + "detection", + "device", + "display", + "focus", + "frame", + "input", + "limits", + "monitor", + "monitoring", + "outline", + "rectangle", + "region", + "screen", + "security", + "security system", + "sensor", + "sensor window", + "signal", + "square", + "surveillance", + "target", + "technology", + "view", + "window", + "zone" + ], + "popularity": 3784 + }, + "SENSORS": { + "tags": [ + "antenna", + "bar graph", + "bars", + "communication", + "connection", + "connection status", + "connectivity", + "data", + "device", + "device status", + "graduated bars", + "indicator", + "internet", + "levels", + "measurement", + "network", + "radio waves", + "reception", + "scan", + "sensing", + "sensors", + "signal", + "signal strength", + "status", + "technology", + "three bars", + "transfer", + "transmission", + "waves", + "wifi", + "wireless" + ], + "popularity": 21789 + }, + "SENSORS_OFF": { + "tags": [ + "block", + "cancel", + "connection", + "crossed out", + "detection off", + "diagonal line", + "disable", + "disabled", + "disconnected", + "enabled", + "forbid", + "inactive", + "line", + "measurement disabled", + "measurement off", + "network", + "no detection", + "no measurement", + "no sensors", + "off", + "on", + "prevent", + "scan", + "sensors", + "sensors off", + "sensory", + "signal", + "slash", + "state", + "status", + "stop", + "toggle", + "unavailable", + "wireless" + ], + "popularity": 3799 + }, + "SENTIMENT_DISSATISFIED": { + "tags": [ + "angry", + "avatar", + "bad", + "circle", + "disappointed", + "dislike", + "dissatisfied", + "emoticon", + "emotion", + "emotions", + "expression", + "expressions", + "face", + "feedback", + "feeling", + "feelings", + "frown", + "head", + "human", + "mood", + "negative", + "person", + "poor", + "profile", + "rating", + "review", + "sad", + "sentiment", + "survey", + "unhappy", + "unsatisfied", + "upset", + "user" + ], + "popularity": 22253 + }, + "SENTIMENT_NEUTRAL": { + "tags": [ + "attitude", + "avatar", + "average", + "emoji", + "emotion", + "emotionless", + "emotions", + "expression", + "expressions", + "face", + "feedback", + "feeling", + "feelings", + "fine", + "horizontal line", + "indifference", + "indifferent", + "mood", + "mouth", + "neutral", + "ok", + "okay", + "people", + "person", + "profile", + "rating", + "regular", + "sentiment", + "status", + "straight face", + "survey", + "user" + ], + "popularity": 11958 + }, + "SENTIMENT_SATISFIED": { + "tags": [ + "cheerful", + "circle", + "emoji", + "emoticon", + "emotion", + "emotions", + "expression", + "expressions", + "eyes", + "face", + "feeling", + "feelings", + "glad", + "happiness", + "happy", + "happy face", + "joy", + "like", + "mood", + "mouth", + "person", + "pleased", + "positive", + "satisfaction", + "satisfied", + "sentiment", + "smile", + "smiley", + "smiley face", + "smiling", + "survey" + ], + "popularity": 27064 + }, + "SENTIMENT_SATISFIED_ALT": { + "tags": [ + "account", + "alt", + "cheerful", + "circle", + "emoji", + "emoticon", + "emotion", + "expression", + "eyes", + "face", + "feeling", + "happy", + "happy face", + "human", + "joy", + "mood", + "mouth", + "people", + "person", + "positive", + "profile", + "satisfaction", + "satisfied", + "sentiment", + "smile", + "smiley", + "smiley face", + "smiling", + "user" + ], + "popularity": 30691 + }, + "SENTIMENT_VERY_DISSATISFIED": { + "tags": [ + "angry", + "avatar", + "character", + "circle", + "disappointed", + "disapproval", + "dislike", + "dissatisfied", + "dissatisfied face", + "emoji", + "emoticon", + "emotion", + "emotions", + "expressions", + "face", + "facial expression", + "feedback", + "feeling", + "feelings", + "frowning", + "human", + "indicator", + "low rating", + "mood", + "negative", + "outline", + "person", + "reaction", + "review", + "sad", + "sentiment", + "sorrow", + "status", + "survey", + "unhappy", + "unsatisfied", + "upset", + "very" + ], + "popularity": 21450 + }, + "SENTIMENT_VERY_SATISFIED": { + "tags": [ + "approval", + "avatar", + "character", + "cheerful", + "circle", + "delight", + "emoticon", + "emotion", + "emotions", + "excellent", + "expression", + "expressions", + "face", + "feedback", + "feeling", + "feelings", + "glad", + "happiness", + "happy", + "human", + "joyful", + "like", + "mood", + "people", + "person", + "pleased", + "positive", + "profile", + "rating", + "satisfied", + "sentiment", + "simple", + "smile", + "smiley face", + "smiling", + "survey", + "user", + "very", + "very happy" + ], + "popularity": 31528 + }, + "SET_MEAL": { + "tags": [ + "chopsticks", + "cutlery", + "dining", + "dining etiquette", + "dining room", + "dinner", + "dish", + "dishware", + "eat", + "eating", + "fish", + "food", + "fork and knife", + "lunch", + "meal", + "place setting", + "plate", + "restaurant", + "serving", + "set", + "silverware", + "spoon", + "tableware", + "teishoku", + "utensils" + ], + "popularity": 5199 + }, + "SETTINGS": { + "tags": [ + "adjustments", + "administration", + "administration panel", + "application", + "change", + "cog", + "cogwheel", + "configuration", + "control", + "control panel", + "customization settings", + "customize", + "details", + "fine tune", + "gear", + "gear wheel", + "info", + "information", + "machinery", + "manage", + "management", + "management tools", + "mechanism", + "modify", + "options", + "options button", + "panel", + "parameter", + "personal", + "preference settings", + "preferences", + "service", + "settings", + "setup", + "system", + "tools" + ], + "popularity": 610009 + }, + "SETTINGS_ACCESSIBILITY": { + "tags": [ + "access", + "accessibility", + "adaptation", + "adjustments", + "aids", + "body", + "cog", + "configuration", + "control", + "customization", + "details", + "disabilities", + "figure", + "gear", + "hearing aid", + "human", + "inclusive", + "information", + "menu", + "mobility", + "options", + "people", + "person", + "personal", + "preferences", + "profile", + "settings", + "setup", + "silhouette", + "special needs", + "symbol", + "tools", + "universal access", + "user", + "visual aid" + ], + "popularity": 14389 + }, + "SETTINGS_APPLICATIONS": { + "tags": [ + "adjust", + "administration", + "app", + "application", + "applications", + "change", + "circle", + "cog", + "computer", + "configuration", + "configure", + "control", + "customize", + "details", + "device", + "engineering", + "gear", + "gears", + "industrial", + "info", + "information", + "internet", + "machinery", + "manage", + "mechanical", + "mechanism", + "mobile", + "options", + "personal", + "preference", + "service", + "settings", + "setup", + "software", + "system", + "technology", + "tools", + "web", + "wheel" + ], + "popularity": 25060 + }, + "SETTINGS_BACKUP_RESTORE": { + "tags": [ + "archive", + "arrow", + "back", + "backup", + "backwards", + "circle", + "cloud", + "cycle", + "data", + "documents", + "download", + "files", + "history", + "loop", + "progress", + "redo", + "refresh", + "reload", + "replay", + "reset", + "restart", + "restore", + "restore defaults", + "reverse", + "rotate", + "settings", + "spin", + "status", + "sync", + "synchronize", + "transfer", + "undo", + "update", + "upload" + ], + "popularity": 14494 + }, + "SETTINGS_BLUETOOTH": { + "tags": [ + "accessories", + "adjustments", + "audio", + "bluetooth", + "configuration", + "connect", + "connection", + "connectivity", + "control", + "data", + "device", + "devices", + "disable", + "discoverable", + "enable", + "headphones", + "mobile", + "network", + "options", + "pairing", + "settings", + "setup", + "sharing", + "signal", + "speakers", + "symbol", + "technology", + "toggle", + "wireless" + ], + "popularity": 4600 + }, + "SETTINGS_BRIGHTNESS": { + "tags": [ + "adjust", + "adjustment", + "appearance", + "brightness", + "configuration", + "contrast", + "control", + "customize", + "dark", + "dial", + "display", + "environment", + "exposure", + "filter", + "glow", + "illumination", + "intensity", + "interface", + "level", + "light", + "management", + "mode", + "modify", + "monitor", + "options", + "preferences", + "screen", + "setting", + "settings", + "solar", + "sun", + "theme", + "visual" + ], + "popularity": 6084 + }, + "SETTINGS_CELL": { + "tags": [ + "adjustment", + "administration", + "administration panel", + "android", + "cell", + "cell phone", + "cellular", + "cog", + "configuration", + "control", + "customization", + "dashboard", + "device", + "gadget", + "gear", + "hardware", + "ios", + "machinery", + "management", + "mechanical", + "mobile", + "mobile menu", + "options", + "os", + "phone", + "preferences", + "settings", + "settings cell", + "setup", + "smart device", + "system", + "tablet", + "technical", + "technology", + "telephony" + ], + "popularity": 3686 + }, + "SETTINGS_ETHERNET": { + "tags": [ + "arrows", + "cable", + "communication", + "component", + "computer", + "computer network", + "connect", + "connection", + "connectivity", + "connector", + "data", + "device", + "dots", + "ethernet", + "hardware", + "infrastructure", + "interface", + "internet", + "jack", + "lan", + "line", + "link", + "local area network", + "network", + "network cable", + "network settings", + "plug", + "port", + "rj45", + "settings", + "socket", + "technology", + "wifi", + "wire", + "wired" + ], + "popularity": 12461 + }, + "SETTINGS_INPUT_ANTENNA": { + "tags": [ + "airplay", + "antenna", + "arrows", + "broadcast", + "cast", + "communication", + "computer", + "connect", + "connection", + "connectivity", + "data", + "dish", + "dish antenna", + "dots", + "entertainment", + "input", + "internet", + "media", + "network", + "parabole", + "parabolic", + "radio", + "radio signal", + "receiver", + "receiver dish", + "satellite", + "satellite dish", + "satellite signal", + "screencast", + "settings", + "signal", + "stream", + "streaming", + "technology", + "television", + "transmission", + "tv", + "tv antenna", + "wifi", + "wireless" + ], + "popularity": 9772 + }, + "SETTINGS_INPUT_COMPONENT": { + "tags": [ + "audio", + "av", + "cable", + "cables", + "component", + "composite", + "configure", + "connect", + "connection", + "connectivity", + "connector", + "device", + "entertainment", + "equipment", + "hardware", + "hookup", + "input", + "install", + "internet", + "jacks", + "link", + "media", + "multimedia", + "plug", + "plug in", + "points", + "ports", + "settings", + "setup", + "technology", + "vga", + "video", + "wifi", + "wiring" + ], + "popularity": 9128 + }, + "SETTINGS_INPUT_COMPOSITE": { + "tags": [ + "audio", + "av", + "cables", + "component", + "composite", + "configure", + "connection", + "connectivity", + "connector", + "device", + "entertainment", + "equipment", + "hardware", + "hookup", + "input", + "install", + "jacks", + "link", + "media", + "multimedia", + "plug", + "plug in", + "points", + "ports", + "settings", + "setup", + "technology", + "vga", + "video", + "wiring" + ], + "popularity": 5308 + }, + "SETTINGS_INPUT_HDMI": { + "tags": [ + "audio", + "av", + "cable", + "configuration", + "connection", + "connectivity", + "connector", + "definition", + "device", + "digital", + "display", + "electronics", + "entertainment", + "hdmi", + "high", + "high definition", + "input", + "jack", + "link", + "monitor", + "multimedia", + "plug", + "plugin", + "points", + "port", + "settings", + "setup", + "signal", + "socket", + "technology", + "television", + "video", + "wire" + ], + "popularity": 3941 + }, + "SETTINGS_INPUT_SVIDEO": { + "tags": [ + "adapter", + "audio video", + "audio visual", + "av", + "cable", + "cable connection", + "circle", + "component video", + "connection", + "connectivity", + "connector", + "definition", + "device", + "electronics", + "entertainment", + "geometric", + "input", + "line", + "media", + "multimedia", + "plug", + "plugin", + "points", + "port", + "s-video", + "settings", + "shape", + "signal", + "square", + "standard", + "svideo", + "technology", + "video", + "video input" + ], + "popularity": 3044 + }, + "SETTINGS_OVERSCAN": { + "tags": [ + "adjustment", + "arrows", + "aspect ratio", + "border", + "box", + "calibration", + "corners", + "display", + "edges", + "expand", + "four corners", + "image", + "lines", + "monitor", + "output", + "overscan", + "photo", + "picture", + "picture adjustment", + "picture settings", + "presentation", + "rectangle", + "resize", + "scan", + "screen", + "screen display", + "settings", + "settings overscan", + "square", + "television", + "tv", + "video", + "video settings", + "view", + "zoom" + ], + "popularity": 5694 + }, + "SETTINGS_PHONE": { + "tags": [ + "adjust", + "administration", + "call", + "cell", + "cellular", + "cog", + "communication", + "configuration", + "connection", + "contact", + "control", + "customize", + "details", + "device", + "feature", + "gear", + "hardware", + "manage", + "mobile", + "options", + "personalization", + "phone", + "preferences", + "settings", + "setup", + "system", + "telephone", + "tool", + "wheel" + ], + "popularity": 17623 + }, + "SETTINGS_POWER": { + "tags": [ + "access", + "action", + "button", + "circle", + "component", + "control", + "device", + "electrical", + "electricity", + "energy", + "function", + "hardware", + "icon", + "info", + "information", + "line", + "menu", + "off", + "on", + "on off", + "power", + "power off", + "reset", + "restart", + "save", + "settings", + "shutdown", + "standby", + "switch", + "symbol", + "system", + "toggle", + "turn off" + ], + "popularity": 7087 + }, + "SETTINGS_REMOTE": { + "tags": [ + "access", + "access settings", + "adjustment", + "appliance", + "bluetooth", + "configuration", + "configure", + "connection", + "connection manager", + "connection settings", + "connectivity", + "control", + "device", + "electronic", + "manage", + "management", + "media", + "options", + "preferences", + "remote", + "remote access", + "remote control", + "remote control settings", + "remote device", + "settings", + "setup", + "signal", + "system", + "television", + "tv", + "wifi", + "wireless", + "wireless control" + ], + "popularity": 8901 + }, + "SETTINGS_SUGGEST": { + "tags": [ + "adjust", + "administration", + "advise", + "ai", + "artificial", + "assist", + "asterisk", + "automatic", + "automation", + "change", + "cog", + "configuration", + "control", + "counsel", + "custom", + "customize", + "details", + "gear", + "genai", + "guidance", + "guide", + "help", + "hint", + "intelligence", + "magic", + "management", + "offering", + "options", + "panel", + "personalize", + "preferences", + "proposal", + "recommendation", + "recommendations", + "service", + "settings", + "setup", + "smart", + "spark", + "sparkle", + "star", + "suggest", + "suggestion", + "system", + "tips", + "tune" + ], + "popularity": 32287 + }, + "SETTINGS_SYSTEM_DAYDREAM": { + "tags": [ + "adjustment", + "backup", + "cloud", + "configuration", + "control", + "daydream", + "device", + "digital", + "display", + "drive", + "electronic", + "electronics", + "equipment", + "experience", + "futuristic", + "goggles", + "headset", + "immersive", + "interface element", + "monitor", + "options", + "preferences", + "screen", + "settings", + "setup", + "storage", + "system", + "tech", + "technology", + "viewing", + "virtual reality", + "vr" + ], + "popularity": 2724 + }, + "SETTINGS_VOICE": { + "tags": [ + "adjustments", + "audio", + "circle", + "circular", + "cog", + "configuration", + "control", + "controls", + "gear", + "horizontal", + "input", + "line", + "lines", + "manage", + "management", + "mic", + "microphone", + "options", + "preferences", + "record", + "recorder", + "recording", + "settings", + "setup", + "sound", + "speak", + "speaker", + "talking", + "vertical", + "voice", + "wheel" + ], + "popularity": 8089 + }, + "SEVERE_COLD": { + "tags": [ + "!", + "alert", + "atmosphere", + "attention", + "blizzard", + "caution", + "chill", + "climate", + "cold", + "condition", + "crisis", + "danger", + "disaster", + "error", + "exclamation", + "extreme", + "forecast", + "freeze", + "freezing", + "frost", + "frozen", + "hazard", + "ice", + "icicle", + "important", + "notification", + "season", + "severe", + "snow", + "snowflake", + "temperature", + "warning", + "weather", + "winter" + ], + "popularity": 1173 + }, + "SHAPE_LINE": { + "tags": [ + "border", + "circle", + "collapse", + "dash", + "decrease", + "delimiter", + "divider", + "division", + "draw", + "edit", + "editing", + "em dash", + "en dash", + "geometry", + "horizontal line", + "hyphen", + "less", + "line", + "line break", + "minimize", + "minus", + "reduce", + "remove", + "rule", + "rule-off", + "segment", + "separate", + "separation", + "shape", + "shorten", + "square", + "subtract" + ], + "popularity": 1147 + }, + "SHARE": { + "tags": [ + "activity", + "andriod share", + "android", + "arrow", + "communication", + "communication icon", + "connect", + "connection", + "contect", + "data", + "disable_ios", + "distribute", + "export", + "forward", + "geometric", + "line", + "lines", + "link", + "media", + "multimedia", + "multiple", + "network", + "options", + "outreach", + "point", + "pointing", + "send", + "send to", + "send to friends", + "send to others", + "send to social", + "share", + "shared", + "sharing", + "social", + "three dots", + "up arrow" + ], + "popularity": 126550 + }, + "SHARE_LOCATION": { + "tags": [ + "address", + "area", + "broadcast", + "communicate", + "connect", + "coordinates", + "dash", + "dashed", + "destination", + "direction", + "explore", + "find", + "geo", + "geography", + "gps", + "location", + "location share", + "map", + "maps", + "marker", + "meetup", + "navigation", + "pathway", + "pin", + "place", + "point", + "position", + "post", + "route", + "send", + "send location", + "share", + "stop", + "tracking", + "travel" + ], + "popularity": 9396 + }, + "SHIELD": { + "tags": [ + "access", + "authorized", + "certified", + "confidential", + "cyber security", + "data security", + "defense", + "digital security", + "encryption", + "internet security", + "lock", + "network security", + "online security", + "permission", + "privacy", + "private", + "protect", + "protection", + "safe", + "safeguard", + "safety", + "secret", + "secure", + "secure connection", + "security", + "shield", + "ssl", + "tls", + "verified", + "vpn", + "web security" + ], + "popularity": 28168 + }, + "SHIELD_MOON": { + "tags": [ + "certified", + "confidential", + "crescent", + "crescent moon", + "dark mode", + "defense", + "do not disturb", + "encrypted", + "guard", + "guarded", + "lock", + "moon", + "moonlight", + "night", + "night mode", + "nighttime", + "privacy", + "privacy mode", + "privacy settings", + "private", + "private browsing", + "protect", + "protected", + "protection", + "safe", + "safety", + "secure", + "secure connection", + "security", + "security settings", + "security shield", + "shield", + "shield with moon", + "verified" + ], + "popularity": 2979 + }, + "SHOP": { + "tags": [ + "architecture", + "bag", + "bill", + "building", + "business", + "buy", + "buying", + "card", + "cart", + "cash", + "coin", + "commerce", + "commercial", + "credit", + "currency", + "dollars", + "door", + "economic", + "establishment", + "facade", + "google", + "institution", + "lines", + "market", + "marketplace", + "money", + "online", + "pay", + "payment", + "play", + "rectangle", + "retail", + "selling", + "shop", + "shopping", + "shopping center", + "store", + "storefront", + "structure", + "transaction", + "window" + ], + "popularity": 9862 + }, + "SHOP_2": { + "tags": [ + "2", + "add", + "arrow", + "basket", + "business", + "buy", + "cart", + "checkout", + "commerce", + "count", + "e-commerce", + "google", + "market", + "multiple items", + "number two", + "online store", + "play", + "point of sale", + "pos", + "purchase", + "quantity", + "retail", + "retail store", + "selling", + "shop", + "shop 2", + "shopping", + "shopping bag", + "store", + "transactions" + ], + "popularity": 2799 + }, + "SHOP_TWO": { + "tags": [ + "2", + "add", + "arrow", + "basket", + "business", + "buy", + "cart", + "checkout", + "commerce", + "count", + "e-commerce", + "google", + "market", + "multiple items", + "number two", + "online store", + "play", + "point of sale", + "pos", + "purchase", + "quantity", + "retail", + "retail store", + "selling", + "shop", + "shop 2", + "shopping", + "shopping bag", + "store", + "transactions", + "two" + ], + "popularity": 4294 + }, + "SHOPPING_BAG": { + "tags": [ + "acquire", + "bag", + "basket", + "bill", + "business", + "buy", + "card", + "carry bag", + "cart", + "cash", + "checkout", + "coin", + "commerce", + "container", + "credit", + "currency", + "dollars", + "e-commerce", + "goods", + "handle", + "handle bag", + "hold", + "items", + "line", + "merchandise", + "money", + "online", + "order", + "outline", + "pay", + "payment", + "product", + "purchase", + "rectangle", + "retail", + "shop", + "shopping", + "shopping bag", + "square", + "store", + "storefront", + "stroke", + "transaction", + "transport" + ], + "popularity": 99048 + }, + "SHOPPING_BASKET": { + "tags": [ + "add", + "add to cart", + "bag", + "basket", + "bill", + "buy", + "card", + "cart", + "cash", + "checkout", + "coin", + "commerce", + "container", + "credit", + "currency", + "dollars", + "e-commerce", + "ecommerce", + "ellipse", + "goods", + "groceries", + "handle", + "items", + "market", + "marketplace", + "merchandise", + "money", + "online", + "online store", + "oval", + "pay", + "payment", + "purchase", + "retail", + "shop", + "shopping", + "shopping basket", + "shopping cart", + "store" + ], + "popularity": 46754 + }, + "SHOPPING_CART": { + "tags": [ + "add", + "add to cart", + "basket", + "bill", + "buy", + "buying", + "card", + "carriage", + "cart", + "cash", + "checkout", + "coin", + "commerce", + "credit", + "currency", + "dollars", + "e-commerce", + "general store", + "goods", + "grocery", + "items", + "local", + "market", + "merchandise", + "money", + "online", + "online shopping", + "pay", + "payment", + "products", + "purchase", + "retail", + "retail store", + "sale", + "shop", + "shopping", + "shopping bag", + "shopping cart", + "store", + "trolley" + ], + "popularity": 320068 + }, + "SHOPPING_CART_CHECKOUT": { + "tags": [ + "add", + "add to cart", + "arrow", + "bag", + "basket", + "buy", + "buying", + "cart", + "cash", + "checkout", + "coin", + "commerce", + "currency", + "dollars", + "e-commerce", + "e-commerce cart", + "e-shop", + "e-tail", + "marketplace", + "money", + "online", + "online basket", + "online purchase", + "online retail", + "online shopping", + "online store", + "pay", + "payment", + "purchase", + "retail", + "retail basket", + "retail cart", + "right", + "shop", + "shopping", + "shopping cart", + "store", + "trolley", + "webshop", + "webstore" + ], + "popularity": 11456 + }, + "SHORT_TEXT": { + "tags": [ + "abstract", + "article", + "block of text", + "brief", + "characters", + "comment", + "composition", + "content", + "copy", + "doc", + "document", + "editorial", + "font", + "letters", + "lines of text", + "lorem ipsum", + "note", + "paragraph", + "placeholder", + "placeholder text", + "reading", + "sample text", + "short", + "short text", + "text", + "type", + "typeface", + "typography", + "words", + "write", + "writing" + ], + "popularity": 3798 + }, + "SHORTCUT": { + "tags": [ + "arrow", + "communication", + "content sharing", + "direction", + "forward", + "forward icon", + "google plus", + "google plus share", + "reshare", + "reshare icon", + "right", + "right arrow", + "send", + "send icon", + "send to", + "share", + "share arrow", + "share content", + "share icon", + "share link", + "share post", + "share to", + "share with", + "shortcut", + "social icon", + "social media", + "social share" + ], + "popularity": 8106 + }, + "SHOW_CHART": { + "tags": [ + "analysis", + "analytics", + "bar", + "bars", + "business", + "chart", + "data", + "diagram", + "display", + "economy", + "finance", + "graph", + "growth", + "infographic", + "line", + "line chart", + "measure", + "metrics", + "performance", + "plotting", + "presentation", + "progress", + "report", + "show", + "show chart", + "statistics", + "stock", + "tracking", + "trends", + "view", + "visualization" + ], + "popularity": 27594 + }, + "SHOWER": { + "tags": [ + "apartment", + "bath", + "bathroom", + "cleaning", + "cleanliness", + "closet", + "droplet", + "droplets", + "fixture", + "graphic", + "head", + "home", + "hotel", + "house", + "hygiene", + "icon", + "lines", + "personal care", + "place", + "plumbing", + "rain", + "refresh", + "relaxation", + "room", + "sanitary", + "shower", + "spa", + "spray", + "sprinkler", + "stream", + "symbol", + "wash", + "washing", + "water", + "wc" + ], + "popularity": 10624 + }, + "SHUFFLE": { + "tags": [ + "alter order", + "arrange", + "arrow", + "arrows", + "change order", + "change sequence", + "control", + "controls", + "crisscross", + "crossed lines", + "diagonal", + "different order", + "disperse", + "jumble", + "list", + "media control", + "mix", + "mixed up", + "music", + "playback", + "playlist", + "random", + "random play", + "re-arrange", + "reorder", + "repeat", + "scatter", + "sequence", + "shuffle", + "sort", + "unpredictable", + "video" + ], + "popularity": 13671 + }, + "SHUFFLE_ON": { + "tags": [ + "activate", + "active", + "arrow", + "arrows", + "audio", + "control", + "controls", + "criss-cross", + "disordered", + "enabled", + "jumbled", + "lines", + "media control", + "mixed", + "music", + "music player", + "on", + "overlapping arrows", + "play order", + "playback", + "playlist", + "random", + "randomization", + "sequence", + "shuffle", + "shuffle mode", + "shuffle on", + "shuffled", + "switch", + "toggle", + "two arrows", + "video" + ], + "popularity": 2825 + }, + "SHUTTER_SPEED": { + "tags": [ + "adjustment", + "aperture", + "aperture control", + "blades", + "camera", + "camera controls", + "capture", + "circle", + "control", + "duration", + "exposure", + "exposure time", + "geometry", + "image", + "image capture", + "iris", + "lens", + "manual", + "manual mode", + "mechanism", + "photo", + "photograph", + "photographic", + "photography", + "photography settings", + "photos", + "picture", + "radial", + "segmented", + "setting", + "shutter", + "shutter speed", + "speed", + "stop", + "time", + "timer", + "watch" + ], + "popularity": 2871 + }, + "SICK": { + "tags": [ + "ailment", + "covid", + "discomfort", + "emoji", + "emoticon", + "emotion", + "emotions", + "expression", + "expressions", + "face", + "feeling", + "feeling ill", + "feeling sick", + "feeling unwell", + "feelings", + "fever", + "flu", + "health", + "health problem", + "ill", + "illness", + "infection", + "medical", + "medical condition", + "mood", + "nauseous", + "negative emotion", + "pain", + "person", + "sad", + "sad face", + "sick", + "sickness", + "survey", + "symptom", + "unhappy", + "unhappy face", + "unwell", + "unwellness", + "upset", + "virus" + ], + "popularity": 6667 + }, + "SIGN_LANGUAGE": { + "tags": [ + "accessibility", + "audio", + "caption", + "communication", + "deaf", + "disability", + "figure", + "fingers", + "gesture", + "hand", + "human", + "inclusive", + "interpretation", + "language", + "linguistics", + "mute", + "people", + "person", + "sign", + "sign language", + "sound", + "speaking", + "speech", + "subtitle", + "symbol", + "talking", + "translate", + "video", + "voice" + ], + "popularity": 1786 + }, + "SIGNAL_CELLULAR_0_BAR": { + "tags": [ + "0", + "0 bars", + "antenna", + "bad signal", + "bar", + "bars", + "bars indicator", + "cell", + "cellular", + "cellular network", + "cellular signal", + "connection", + "connectivity", + "data", + "internet", + "low signal", + "mobile", + "network", + "network strength", + "no signal", + "phone", + "signal", + "signal strength", + "speed", + "status", + "status indicator", + "strength", + "telecommunication", + "towers", + "wifi", + "wireless", + "wireless network", + "wireless signal", + "zero bars" + ], + "popularity": 2334 + }, + "SIGNAL_CELLULAR_4_BAR": { + "tags": [ + "0", + "bar", + "bars", + "bars increasing", + "cell", + "cellular", + "communication", + "connection", + "connectivity", + "data", + "four bars", + "full", + "full signal", + "indicator", + "internet", + "mobile", + "mobile data", + "network", + "network connection", + "network status", + "phone", + "reception", + "signal", + "speed", + "status", + "strength", + "strength indicator", + "technology", + "telecommunications", + "wifi", + "wireless" + ], + "popularity": 5767 + }, + "SIGNAL_CELLULAR_ALT": { + "tags": [ + "alt", + "analytics", + "ascending bars", + "bar", + "bars", + "cell", + "cellular", + "chart", + "communication", + "connection", + "connectivity", + "data", + "device", + "diagram", + "full signal", + "good signal", + "graph", + "indicator", + "infographic", + "internet", + "level", + "measure", + "measurement", + "metrics", + "mobile", + "mobile network", + "network", + "phone", + "reception", + "signal", + "signal strength", + "statistics", + "status", + "strength", + "technology", + "telecommunication", + "tracking", + "vertical bars", + "wifi", + "wireless" + ], + "popularity": 34341 + }, + "SIGNAL_CELLULAR_ALT_1_BAR": { + "tags": [ + "1 bar", + "alt", + "analytics", + "antenna", + "bar", + "bars", + "cell", + "cell signal", + "cellular", + "chart", + "communication", + "connection", + "connectivity", + "coverage", + "data", + "diagram", + "graph", + "indicator", + "infographic", + "internet", + "level", + "low signal", + "measure", + "metrics", + "mobile", + "mobile signal", + "network", + "one bar", + "phone", + "reception", + "signal", + "signal strength", + "statistics", + "status", + "strength", + "telecommunications", + "tracking", + "wifi", + "wireless" + ], + "popularity": 1207 + }, + "SIGNAL_CELLULAR_ALT_2_BAR": { + "tags": [ + "alt", + "analytics", + "bar", + "bars", + "bars up", + "cell", + "cellular", + "chart", + "communication", + "connection", + "connectivity", + "data", + "diagram", + "full", + "graph", + "half strength", + "increasing bars", + "indicator", + "infographic", + "internet", + "level", + "measure", + "medium strength", + "metrics", + "mobile", + "network", + "phone", + "reception", + "signal", + "statistics", + "status", + "strength", + "tracking", + "two bars", + "waves", + "wifi", + "wireless" + ], + "popularity": 1170 + }, + "SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_0_BAR": { + "tags": [ + "!", + "0", + "0 bars", + "alert", + "attention", + "bar", + "bars", + "caution", + "cell", + "cellular", + "communication", + "connected", + "connection", + "connectivity", + "danger", + "data", + "device", + "disconnected", + "error", + "exclamation", + "important", + "indicator", + "internet", + "low signal", + "mark", + "mobile", + "network", + "no", + "no internet", + "notification", + "phone", + "pyramid", + "signal", + "status", + "symbol", + "triangle", + "unavailable", + "warning", + "wifi", + "wireless", + "zero bars" + ], + "popularity": 1753 + }, + "SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BAR": { + "tags": [ + "!", + "4", + "4 bars", + "alert", + "attention", + "bar", + "bars", + "caution", + "cell", + "cellular", + "connected", + "connection", + "connectivity", + "danger", + "data", + "disconnection", + "error", + "exclamation", + "four bars", + "full signal", + "important", + "indicator", + "internet", + "level", + "limited connectivity", + "mark", + "mobile", + "mobile data", + "network", + "no", + "no access", + "no internet", + "notification", + "offline", + "phone", + "problem", + "service", + "signal", + "signal strength", + "status", + "symbol", + "warning", + "wifi", + "wireless" + ], + "popularity": 1957 + }, + "SIGNAL_CELLULAR_NO_SIM": { + "tags": [ + "absent", + "alert", + "bar", + "bars", + "camera", + "card", + "cellular", + "chip", + "communication", + "connection", + "cross", + "device", + "diagonal line", + "disabled", + "empty", + "enabled", + "error", + "line", + "lines", + "memory", + "missing", + "mobile", + "network", + "no", + "no service", + "no signal", + "no sim", + "not inserted", + "off", + "offline", + "on", + "phone", + "signal", + "sim", + "sim card", + "slash", + "slot", + "storage", + "triangle", + "unavailable", + "warning" + ], + "popularity": 1048 + }, + "SIGNAL_CELLULAR_NODATA": { + "tags": [ + "antenna", + "ascending", + "bars", + "cell", + "cellular", + "clear", + "communication", + "connection", + "data", + "descending", + "disconnected", + "error", + "internet", + "level", + "mobile", + "network", + "no", + "nodata", + "offline", + "phone", + "power", + "quit", + "reception", + "remove", + "service", + "signal", + "status", + "status bar", + "strength", + "technology", + "triangle", + "unavailable", + "warning", + "wifi", + "wireless", + "x" + ], + "popularity": 1417 + }, + "SIGNAL_CELLULAR_NULL": { + "tags": [ + "alert", + "bars", + "cell", + "cellular", + "communication", + "connection", + "connectivity", + "data", + "diagonal line", + "disabled", + "error", + "indicator", + "internet", + "line", + "mobile", + "network", + "no service", + "no signal", + "null", + "offline", + "phone", + "signal", + "signal strength", + "status", + "triangle", + "unavailable", + "warning", + "wifi", + "wireless" + ], + "popularity": 1365 + }, + "SIGNAL_CELLULAR_OFF": { + "tags": [ + "antenna", + "bars", + "cell", + "cellular", + "communication", + "communication status", + "connection", + "data", + "deactivated", + "disabled", + "disconnected", + "enabled", + "indicator", + "internet", + "mobile", + "mobile data", + "mobile status", + "network", + "network status", + "no cellular", + "no connection", + "no network", + "no service", + "no signal", + "off", + "offline", + "on", + "phone", + "phone signal", + "service", + "signal", + "signal bars", + "slash", + "status", + "unavailable", + "unavailable signal", + "wifi", + "wireless" + ], + "popularity": 1384 + }, + "SIGNAL_WIFI_0_BAR": { + "tags": [ + "0", + "access", + "arc", + "bar", + "cell", + "cellular", + "communication", + "connection", + "connectivity", + "connectivity status", + "data", + "disconnected", + "indicator", + "internet", + "internet access", + "internet signal", + "mobile", + "network", + "network icon", + "network status", + "no connection", + "no service", + "no signal", + "offline", + "phone", + "signal", + "status bar", + "symbol", + "technology", + "waves", + "weak signal", + "wifi", + "wifi icon", + "wireless", + "wireless network", + "zero bars" + ], + "popularity": 3247 + }, + "SIGNAL_WIFI_4_BAR": { + "tags": [ + "4", + "available", + "bar", + "bars", + "cell", + "cellular", + "communication", + "connected", + "connection", + "connection quality", + "connectivity", + "data", + "four bars", + "full", + "indicator", + "internet", + "max", + "mobile", + "network", + "online", + "phone", + "service", + "signal", + "signal strength.", + "status", + "status bar", + "strength", + "system", + "waves", + "wifi", + "wireless" + ], + "popularity": 7205 + }, + "SIGNAL_WIFI_4_BAR_LOCK": { + "tags": [ + "4", + "access", + "authentication", + "bar", + "bars", + "cell", + "cellular", + "connect", + "connection", + "connectivity", + "data", + "encrypted", + "four bars", + "full signal", + "internet", + "lock", + "locked", + "maximum signal", + "mobile", + "network", + "network access.", + "password", + "phone", + "privacy", + "private", + "protected", + "protection", + "safe", + "safety", + "secure", + "security", + "signal", + "strength", + "wifi", + "wireless" + ], + "popularity": 1374 + }, + "SIGNAL_WIFI_BAD": { + "tags": [ + "access", + "arc", + "bad", + "bar", + "bars", + "cancel", + "cell", + "cellular", + "clear", + "close", + "communication", + "cone", + "connect", + "connection", + "data", + "disconnected", + "error", + "exit", + "hotspot", + "icon", + "internet", + "issue", + "lines", + "mobile", + "network", + "no", + "outage", + "phone", + "problem", + "quit", + "radiating", + "remove", + "signal", + "stop", + "symbol", + "technology", + "triangle", + "unconnected", + "waves", + "wifi", + "wireless", + "x" + ], + "popularity": 2579 + }, + "SIGNAL_WIFI_CONNECTED_NO_INTERNET_4": { + "tags": [ + "4", + "access", + "arc", + "bad", + "bars", + "cell", + "cellular", + "communication", + "cone", + "connect", + "connected", + "connection", + "data", + "disconnected", + "error", + "hotspot", + "icon", + "internet", + "issue", + "lines", + "mobile", + "network", + "no", + "offline", + "outage", + "phone", + "problem", + "radiating", + "signal", + "symbol", + "technology", + "triangle", + "unconnected", + "waves", + "wifi", + "wireless", + "x" + ], + "popularity": 2470 + }, + "SIGNAL_WIFI_OFF": { + "tags": [ + "alert", + "antenna", + "arcs", + "bars", + "cell", + "cellular", + "communication", + "connection off", + "connection symbol", + "data", + "diagonal line", + "disabled", + "disconnect", + "disconnected", + "enabled", + "error", + "indicator", + "internet", + "internet off", + "internet symbol", + "mobile", + "network", + "network off", + "network symbol", + "no wifi", + "not connected", + "off", + "offline", + "on", + "phone", + "problem", + "signal", + "signal symbol", + "slash", + "speed", + "status", + "unavailable", + "warning", + "wifi", + "wifi off", + "wifi symbol", + "wireless", + "wireless off", + "wireless symbol" + ], + "popularity": 2775 + }, + "SIGNAL_WIFI_STATUSBAR_4_BAR": { + "tags": [ + "4", + "available", + "bar", + "bars", + "cell", + "cellular", + "communication", + "connected", + "connection", + "connection quality", + "connectivity", + "data", + "four bars", + "full", + "indicator", + "internet", + "max", + "mobile", + "network", + "online", + "phone", + "service", + "signal", + "signal strength.", + "speed", + "status", + "status bar", + "statusbar", + "strength", + "system", + "waves", + "wifi", + "wireless" + ], + "popularity": 4443 + }, + "SIGNAL_WIFI_STATUSBAR_CONNECTED_NO_INTERNET_4": { + "tags": [ + "!", + "4", + "alert", + "attention", + "caution", + "cell", + "cellular", + "connected", + "danger", + "data", + "error", + "exclamation", + "important", + "internet", + "mark", + "mobile", + "network", + "no", + "notification", + "phone", + "signal", + "speed", + "statusbar", + "symbol", + "warning", + "wifi", + "wireless" + ], + "popularity": 4349 + }, + "SIGNAL_WIFI_STATUSBAR_NULL": { + "tags": [ + "access", + "arc", + "bar", + "cell", + "cellular", + "communication", + "connection", + "connectivity", + "curve", + "data", + "device", + "disconnected", + "empty", + "indicator", + "internet", + "level", + "mobile", + "network", + "no signal", + "none", + "null", + "offline", + "phone", + "signal", + "speed", + "status", + "statusbar", + "technology", + "unavailable", + "wave", + "wifi", + "wireless", + "zero" + ], + "popularity": 2255 + }, + "SIGNPOST": { + "tags": [ + "arrow", + "bar", + "destination", + "direction", + "guidance", + "guidepost", + "horizontal", + "indicator", + "information", + "journey", + "landmark", + "left", + "location", + "map", + "maps", + "marker", + "navigation", + "path", + "pinpoint", + "pointer", + "post", + "right", + "road", + "route", + "sign", + "signal", + "signpost", + "signs", + "stick", + "street", + "traffic", + "travel", + "upright", + "vertical", + "wayfinding" + ], + "popularity": 3649 + }, + "SIM_CARD": { + "tags": [ + "camera", + "card", + "carrier", + "cellular", + "cellular service", + "chip", + "communication", + "communication device", + "connection", + "connectivity", + "contact", + "corner cut", + "data", + "device", + "electronics", + "hardware", + "identity", + "internet", + "memory", + "mobile", + "module", + "network", + "phone", + "service", + "signal", + "sim", + "sim card", + "smart card", + "square", + "storage", + "subscriber", + "subscriber identity module", + "technology", + "telecom", + "telephone" + ], + "popularity": 4465 + }, + "SIM_CARD_ALERT": { + "tags": [ + "!", + "alert", + "attention", + "camera", + "card", + "caution", + "chip", + "communication", + "danger", + "data", + "device", + "digital", + "electronic", + "error", + "exclamation", + "exclamation point", + "fail", + "failed", + "hardware", + "important", + "indication", + "indicator", + "issue", + "mark", + "memory", + "mobile", + "network", + "notification", + "phone", + "photos", + "problem", + "sd", + "sd card", + "secure", + "sim card", + "slot", + "status", + "storage", + "symbol", + "triangle", + "warning" + ], + "popularity": 1735 + }, + "SIM_CARD_DOWNLOAD": { + "tags": [ + "arrow", + "button", + "camera", + "card", + "cellular", + "chip", + "communication", + "connection", + "data", + "device", + "down", + "down arrow", + "download", + "element", + "get", + "icon", + "import", + "install", + "memory", + "mobile", + "network", + "phone", + "receive", + "rectangle", + "rounded rectangle", + "save", + "sim", + "sim card", + "storage", + "symbol", + "transfer" + ], + "popularity": 5355 + }, + "SINGLE_BED": { + "tags": [ + "accommodations", + "apartment", + "bed", + "bed silhouette", + "bedroom", + "bedtime", + "comfort", + "double", + "furniture", + "furniture outline", + "guest room", + "home", + "hostel", + "hotel", + "hotel icon", + "house", + "king", + "lodging", + "motel", + "nap", + "night", + "pillows", + "queen", + "relax", + "relaxation", + "rest", + "room", + "room icon", + "single", + "single bed", + "sleep", + "sleeping", + "tourism", + "travel", + "twin" + ], + "popularity": 3664 + }, + "SIP": { + "tags": [ + "alphabet", + "audio call", + "call", + "call control", + "character", + "communication", + "connect", + "connection", + "contact", + "conversation", + "dial", + "dialer", + "earpiece", + "font", + "handset", + "incoming call", + "initiation", + "internet", + "internet call", + "letters", + "line", + "microphone", + "network", + "outgoing call", + "over", + "phone", + "phone call", + "protocol", + "ring", + "routing", + "session", + "signal", + "sip", + "softphone", + "symbol", + "talk", + "telephone", + "telephony", + "text", + "type", + "voice", + "voice call", + "voip" + ], + "popularity": 1531 + }, + "SKATEBOARDING": { + "tags": [ + "action", + "active", + "activity", + "athlete", + "athletic", + "board", + "body", + "entertainment", + "exercise", + "extreme sport", + "extreme sports", + "fun", + "hobby", + "human", + "jump", + "leisure", + "lifestyle", + "motion", + "movement", + "ollie", + "outdoor", + "park", + "people", + "person", + "recreation", + "recreational", + "riding", + "skate", + "skateboard", + "skateboarder", + "skateboarding", + "skatepark", + "social", + "sport", + "sports", + "street", + "trick", + "urban", + "wheels", + "youth", + "youthful" + ], + "popularity": 3491 + }, + "SKIP_NEXT": { + "tags": [ + "advance", + "arrow", + "audio player", + "bar", + "button", + "control", + "controls", + "fast forward", + "forward", + "jump", + "media button", + "media control", + "media player", + "move forward", + "music", + "navigation", + "next", + "next track", + "play", + "playback", + "previous", + "right arrow", + "sequence", + "skip", + "skip next", + "triangle", + "vertical bar", + "video", + "video player" + ], + "popularity": 34393 + }, + "SKIP_PREVIOUS": { + "tags": [ + "arrow", + "audio", + "back", + "bar", + "beginning", + "button", + "control", + "controls", + "double line", + "file", + "go back", + "history", + "interface control", + "line", + "media", + "media controls", + "multimedia", + "music", + "next", + "play", + "playback", + "player", + "previous", + "previous song", + "previous track", + "rewind", + "skip", + "skip previous", + "song", + "start", + "track", + "transport controls", + "triangle", + "ui icon", + "vertical line", + "video" + ], + "popularity": 25007 + }, + "SLEDDING": { + "tags": [ + "activity", + "athlete", + "athletic", + "body", + "child", + "christmas", + "cold", + "downhill", + "entertainment", + "exercise", + "festive", + "fun", + "hill", + "hobby", + "holiday", + "human", + "leisure", + "mountain", + "outdoor", + "people", + "person", + "play", + "recreation", + "ride", + "season", + "sled", + "sledding", + "sledge", + "sliding", + "slope", + "snow", + "snow day", + "snowy hill", + "snowy slope", + "social", + "sport", + "sports", + "travel", + "winter", + "winter activity", + "winter sport" + ], + "popularity": 1911 + }, + "SLIDESHOW": { + "tags": [ + "begin", + "demonstrate", + "display", + "entertainment", + "exhibit", + "film", + "image sequence", + "media", + "movie", + "movie screen", + "multimedia", + "photo display", + "photos", + "play", + "play button", + "playback", + "presentation", + "projector", + "projector screen", + "right arrow", + "screen", + "screen display", + "show", + "show images", + "slide", + "slideshow", + "square", + "start", + "triangle", + "video", + "view", + "viewing" + ], + "popularity": 10107 + }, + "SLOW_MOTION_VIDEO": { + "tags": [ + "adjust speed", + "arrow", + "camera", + "circle", + "control", + "controls", + "dash", + "dashed", + "edit video", + "effect", + "enhance video", + "film", + "icon", + "media", + "media control", + "modify", + "motion", + "movie", + "music", + "play", + "playback", + "playback speed", + "rate", + "slow", + "slow motion", + "speed", + "speed control", + "symbol", + "time", + "triangle", + "video", + "video control", + "video effect", + "video speed", + "visual effect" + ], + "popularity": 3940 + }, + "SMART_BUTTON": { + "tags": [ + "action", + "ai", + "appliance", + "artificial", + "automated", + "automatic", + "automation", + "button", + "circle", + "clever", + "command", + "components", + "composer", + "connected", + "connection", + "control", + "custom", + "device", + "digital", + "electric", + "electronic", + "function", + "genai", + "home automation", + "intelligence", + "interface", + "internet of things", + "iot", + "link", + "magic", + "network", + "remote", + "site", + "smart", + "smart button", + "spark", + "sparkle", + "special", + "star", + "stars", + "switch", + "technology", + "toggle", + "trigger", + "ui", + "ux", + "web", + "website", + "wireless" + ], + "popularity": 7239 + }, + "SMART_DISPLAY": { + "tags": [ + "airplay", + "appliance", + "automation", + "base", + "cast", + "chrome", + "connect", + "connected", + "connected device", + "control", + "device", + "digital assistant", + "display", + "electronic", + "entertainment", + "entertainment device", + "home", + "home control", + "household", + "information", + "interactive", + "kitchen", + "living room", + "media", + "monitor", + "play", + "rectangular", + "screen", + "screencast", + "smart", + "smart display", + "smart home", + "stand", + "stream", + "technology", + "television", + "touch screen", + "tv", + "video", + "voice assistant", + "voice control" + ], + "popularity": 28102 + }, + "SMART_SCREEN": { + "tags": [ + "airplay", + "android", + "cast", + "cell", + "communication", + "connect", + "connection", + "connectivity", + "data", + "device", + "device icon", + "display", + "display dots", + "dots", + "entertainment", + "hardware", + "interface", + "ios", + "link", + "media", + "mirror", + "mobile", + "mobile dots", + "mobile icon", + "network", + "os", + "pairing", + "phone", + "replicate", + "screen", + "screencast", + "sharing", + "smart", + "smart screen", + "stream", + "sync", + "synchronize", + "tablet", + "technology", + "transfer", + "video", + "wireless" + ], + "popularity": 1504 + }, + "SMART_TOY": { + "tags": [ + "ai", + "android", + "artificial intelligence", + "assistant", + "automation", + "bot", + "character", + "chatbot", + "companion", + "computing", + "digital", + "droid", + "future", + "futuristic", + "games", + "head", + "icon", + "innovation", + "intelligence", + "interaction", + "interface", + "machine learning", + "mechanical", + "playful", + "robot", + "round eyes", + "smart", + "smart toy", + "square", + "symbol", + "technology", + "toy", + "virtual" + ], + "popularity": 20829 + }, + "SMARTPHONE": { + "tags": [ + "android", + "border", + "call", + "cell", + "cellphone", + "cellular", + "chat", + "communication", + "current", + "device", + "display", + "frame", + "gadget", + "handheld", + "hardware", + "ios", + "mobile", + "orientation", + "os", + "outline", + "phone", + "portable", + "portrait", + "rectangle", + "rounded corners", + "screen", + "smartphone", + "stay", + "stroke", + "tablet", + "technology", + "text", + "vertical" + ], + "popularity": 47048 + }, + "SMOKE_FREE": { + "tags": [ + "addiction", + "area", + "banned", + "cigar", + "cigarette", + "circle", + "clean air", + "diagonal line", + "disabled", + "enabled", + "environment", + "forbidden", + "free", + "graphic", + "health", + "never", + "no", + "no smoking", + "not allowed", + "off", + "on", + "pictogram", + "places", + "policy", + "prohibited", + "prohibition", + "public space", + "restricted", + "rule", + "sign", + "slash", + "smoke", + "smoke free", + "smoking", + "smoking prohibited", + "symbol", + "tobacco", + "warning", + "zone" + ], + "popularity": 2899 + }, + "SMOKING_ROOMS": { + "tags": [ + "access", + "airport", + "allowed", + "amenity", + "area", + "bar", + "break", + "building", + "cigarette", + "designated", + "facility", + "hotel", + "location", + "lounge", + "permission", + "permitted", + "places", + "point of interest", + "public", + "recreation", + "relaxation", + "restaurant", + "room", + "rooms", + "sign", + "smoke", + "smoking", + "space", + "symbol", + "tobacco", + "zone" + ], + "popularity": 3679 + }, + "SMS": { + "tags": [ + "3", + "alert", + "app", + "bubble", + "chat", + "communicate", + "communication", + "conversation", + "dialog", + "dialogue", + "dots", + "inbox", + "lines", + "mail", + "message", + "message bubble", + "messaging", + "mobile", + "more", + "new", + "notification", + "phone", + "pointer", + "receive", + "rectangle", + "send", + "service", + "sms", + "social", + "speech", + "speech bubble", + "square", + "talk", + "text", + "texting", + "three" + ], + "popularity": 22505 + }, + "SMS_FAILED": { + "tags": [ + "!", + "alert", + "announcement", + "attention", + "broadcast", + "caution", + "chat", + "chat bubble", + "comment", + "communicate", + "communication", + "conversation", + "danger", + "delivery failed", + "element", + "error", + "exclamation", + "fail", + "failed", + "feedback", + "icon", + "important", + "mark", + "megaphone", + "message", + "news", + "notification", + "public address", + "send failed", + "service", + "sms", + "sound", + "speaker", + "speech", + "symbol", + "text message", + "volume", + "warning" + ], + "popularity": 5373 + }, + "SNIPPET_FOLDER": { + "tags": [ + "archive", + "box", + "business", + "categorized", + "collection", + "compartment", + "container", + "data", + "directory", + "doc", + "document", + "documents", + "drive", + "file", + "files", + "folder", + "indexed", + "management", + "office", + "organize", + "repository", + "save", + "sheet", + "slide", + "snippet", + "storage", + "store", + "structured", + "tabbed" + ], + "popularity": 4034 + }, + "SNOOZE": { + "tags": [ + "alarm", + "alert", + "bedtime", + "bell", + "clock", + "curve", + "delay", + "duration", + "icon", + "notification", + "pause", + "postpone", + "quiet", + "reminder", + "repeat", + "rest", + "shape", + "silence", + "sleep", + "snooze", + "stop", + "symbol", + "temporary", + "three z's", + "time", + "timer", + "wake up", + "watch", + "wavy line", + "z", + "zzz" + ], + "popularity": 3420 + }, + "SNOWBOARDING": { + "tags": [ + "action", + "activity", + "athlete", + "athletic", + "board", + "body", + "carve", + "cold", + "downhill", + "entertainment", + "exercise", + "extreme sport", + "figure", + "freestyle", + "hobby", + "human", + "jump", + "maneuver", + "mountains", + "outdoor", + "people", + "person", + "pictogram", + "recreation", + "rider", + "silhouette", + "slide", + "slope", + "snow", + "snowboarder", + "snowboarding", + "social", + "sport", + "sports", + "travel", + "trick", + "winter", + "winter sport" + ], + "popularity": 2494 + }, + "SNOWMOBILE": { + "tags": [ + "activity", + "adventure", + "automobile", + "car", + "cold", + "direction", + "driver", + "engine", + "graphic", + "handlebars", + "icon", + "illustration", + "leisure", + "line art", + "machine", + "motor", + "outdoor", + "pictogram", + "recreation", + "rider", + "sign", + "skimobile", + "skis", + "snow", + "snowmobile", + "social", + "sport", + "sports", + "symbol", + "track", + "transportation", + "travel", + "vehicle", + "winter" + ], + "popularity": 1405 + }, + "SNOWSHOEING": { + "tags": [ + "activity", + "adventure", + "body", + "boots", + "cold", + "equipment", + "explore", + "footwear", + "gear", + "graphic", + "hiking", + "human", + "icon", + "illustration", + "journey", + "outdoor", + "outline", + "people", + "person", + "recreation", + "shape", + "silhouette", + "snow", + "snowshoe", + "snowshoeing", + "snowshoes", + "sport", + "sports", + "symbol", + "trail", + "travel", + "trek", + "walking", + "winter" + ], + "popularity": 2244 + }, + "SOAP": { + "tags": [ + "bar", + "bath", + "bathroom", + "beauty", + "block", + "body wash", + "bubbles", + "clean", + "cleaning product", + "cosmetic", + "detergent", + "fingers", + "foam", + "freshness", + "gesture", + "hand", + "healthcare", + "hygiene", + "item", + "lather", + "personal care", + "product", + "rectangle", + "sanitation", + "shower", + "soap", + "spa", + "suds", + "symbol", + "toiletries", + "wash", + "wc" + ], + "popularity": 3095 + }, + "SOCIAL_DISTANCE": { + "tags": [ + "6", + "alert", + "apart", + "body", + "caution", + "concept", + "covid-19", + "distance", + "distance between people", + "distancing", + "figures", + "ft", + "health", + "healthcare", + "human", + "hygiene", + "icon", + "infection", + "medical", + "pandemic", + "people", + "person", + "prevention", + "public health", + "safety", + "social", + "social distance", + "space", + "spread", + "standing", + "symbol", + "two people", + "virus", + "warning" + ], + "popularity": 5586 + }, + "SOLAR_POWER": { + "tags": [ + "array", + "clean energy", + "clean power", + "eco", + "electric power", + "electricity", + "energy", + "generation", + "green energy", + "green power", + "heat", + "nest", + "panel", + "photovoltaic", + "photovoltaic panel", + "power", + "power generation", + "rays", + "renewable", + "solar", + "solar energy", + "solar panel", + "solar power", + "sun", + "sun rays", + "sunlight", + "sunny", + "sustainable", + "sustainable energy" + ], + "popularity": 3879 + }, + "SORT": { + "tags": [ + "alphabetize", + "arrange", + "arrow", + "ascending", + "categorize", + "change order", + "content", + "data", + "descending", + "direction", + "display", + "down", + "filter", + "group", + "hierarchy", + "list", + "management", + "options", + "order", + "organize", + "organize data", + "preference", + "rearrange", + "reorder", + "sequence", + "settings", + "sort", + "table", + "up", + "view" + ], + "popularity": 51851 + }, + "SORT_BY_ALPHA": { + "tags": [ + "a", + "a to z", + "alphabet", + "alphabetical list", + "alphabetical order", + "alphabetically", + "alphabetize", + "arrange", + "arrangement", + "az", + "by alpha", + "character", + "character order", + "font", + "letter order", + "letters", + "list", + "list order", + "order", + "order symbols", + "order text", + "organize", + "reorganize", + "sort", + "sort alphabetically", + "sort text", + "symbol", + "symbols", + "text", + "text list", + "type", + "z", + "z to a" + ], + "popularity": 12195 + }, + "SOS": { + "tags": [ + "alert", + "box", + "button", + "communication", + "danger", + "distress", + "element", + "emergency", + "font", + "four sides", + "graphic", + "help", + "icon", + "letters", + "safety", + "save", + "shape", + "signal", + "sos", + "square", + "symbol", + "text", + "type", + "ui icon", + "warning" + ], + "popularity": 1486 + }, + "SOUP_KITCHEN": { + "tags": [ + "aid", + "assistance", + "bowl", + "breakfast", + "brunch", + "care", + "charity", + "community", + "dining", + "donation", + "feeding", + "food", + "giving", + "help", + "helping hand", + "human services", + "hunger", + "kitchen", + "lunch", + "meal", + "non-profit", + "nourishment", + "outreach", + "poverty", + "service", + "serving", + "sharing", + "shelter", + "social services", + "soup", + "soup kitchen", + "spoon", + "support", + "volunteer" + ], + "popularity": 3509 + }, + "SOURCE": { + "tags": [ + "area", + "basis", + "category", + "code", + "composer", + "concern", + "content", + "context", + "creation", + "data", + "details", + "doc", + "document", + "domain", + "element", + "facts", + "field", + "file", + "folder", + "foundation", + "header", + "heading", + "information", + "issue", + "knowledge", + "matter", + "mode", + "origin", + "point", + "question", + "reference", + "resources", + "root", + "source", + "storage", + "subject", + "subject matter", + "theme", + "title", + "topic", + "view" + ], + "popularity": 24787 + }, + "SOUTH": { + "tags": [ + "arrow", + "arrow down", + "below", + "bottom", + "button", + "chevron", + "control", + "cursor", + "direction", + "directional", + "down", + "down arrow", + "downward", + "graphic", + "guide", + "indicator", + "interface element", + "location", + "maps", + "move down", + "movement", + "navigation", + "pointer", + "pointing down", + "position", + "scroll down", + "south", + "symbol", + "triangle", + "vertical" + ], + "popularity": 20782 + }, + "SOUTH_AMERICA": { + "tags": [ + "area", + "boundary", + "cartography", + "continent", + "continent map", + "continent outline", + "country", + "domain", + "earth", + "geographical", + "geography", + "global", + "globe", + "international", + "international travel", + "landform", + "landmass", + "landscape", + "location", + "map", + "national", + "outline", + "place", + "region", + "shape", + "south america", + "south american map", + "territory", + "travel", + "world", + "zone" + ], + "popularity": 2351 + }, + "SOUTH_EAST": { + "tags": [ + "arrow", + "bottom right arrow", + "box", + "corner arrow", + "diagonal arrow", + "direction", + "directional", + "down", + "east", + "enlarge", + "expand", + "external link", + "fullscreen", + "indicator", + "jump", + "line", + "link", + "maps", + "maximize", + "movement", + "navigation", + "new window", + "open", + "orientation", + "out", + "outline", + "pointer", + "rectangle", + "resize", + "right", + "south", + "southeast arrow", + "square", + "stroke" + ], + "popularity": 6203 + }, + "SOUTH_WEST": { + "tags": [ + "angle", + "angle icon", + "angled arrow", + "arrow", + "arrow icon", + "change direction", + "diagonal", + "diagonal arrow", + "direction", + "direction icon", + "directional", + "down", + "flow", + "indicator", + "left", + "maps", + "move", + "movement", + "movement icon", + "navigation", + "path", + "point", + "pointer", + "progress", + "route", + "south", + "south west", + "south-west", + "southwest arrow", + "travel", + "turn", + "west" + ], + "popularity": 4516 + }, + "SPA": { + "tags": [ + "aromatherapy", + "bath", + "beauty", + "body", + "flower", + "glyph", + "graphic", + "health", + "healthcare", + "hot springs", + "hotel", + "icon", + "leaf", + "luxury", + "massage", + "meditation", + "nature", + "petals", + "places", + "rejuvenation", + "relax", + "relaxation", + "resort", + "sauna", + "spa", + "steam room", + "symbol", + "therapy", + "treatment", + "water", + "wellbeing", + "wellness" + ], + "popularity": 23940 + }, + "SPACE_BAR": { + "tags": [ + "bar", + "break", + "button", + "character", + "control", + "document", + "editor", + "enter", + "gap", + "horizontal", + "icon", + "input", + "key", + "keyboard", + "line", + "long", + "paragraph", + "press", + "rectangle", + "separation", + "space", + "spacebar", + "text", + "typing", + "ui", + "ux", + "wide", + "word", + "writing" + ], + "popularity": 2539 + }, + "SPACE_DASHBOARD": { + "tags": [ + "analytics", + "arrangement", + "blocks", + "cards", + "composition", + "dashboard", + "dashboard view", + "data", + "display", + "format", + "grid", + "layout", + "layout arrangement", + "metrics", + "modular", + "module", + "organize", + "overview", + "panels", + "rectangle", + "rectangular", + "report", + "sections", + "segments", + "shapes", + "space", + "square", + "squares", + "structure", + "system", + "tiles", + "view", + "web", + "website", + "windows" + ], + "popularity": 31866 + }, + "SPATIAL_AUDIO": { + "tags": [ + "3d audio", + "acoustic", + "audio", + "audio effects", + "audio processing", + "audio rendering", + "audio settings", + "direction", + "ears", + "enhanced audio", + "environment audio", + "head", + "headphone icon", + "headphones", + "immersive audio", + "listening", + "music", + "note", + "positional audio", + "sonic", + "sound", + "sound control", + "sound waves", + "sound waves radiating", + "spatial", + "spatial audio", + "stereo", + "surround sound", + "virtual sound" + ], + "popularity": 1414 + }, + "SPATIAL_AUDIO_OFF": { + "tags": [ + "3d audio off", + "audio", + "audio control", + "audio icon", + "audio off", + "audio off icon", + "audio options", + "audio setting off", + "circular sound waves off", + "crossed out audio", + "crossed out sound", + "disable audio", + "disable sound", + "disabled", + "disabled sound", + "disabled state", + "enabled", + "immersive audio off", + "music", + "mute spatial audio", + "no sound", + "no sound icon", + "note", + "off", + "off state", + "offline", + "on", + "settings", + "slash", + "sound", + "sound control", + "sound icon", + "sound off", + "sound options", + "sound waves off", + "spatial", + "spatial audio off", + "spatial audio setting", + "spatial sound disabled", + "surround sound disabled", + "volume off" + ], + "popularity": 2529 + }, + "SPATIAL_TRACKING": { + "tags": [ + "3d", + "ar", + "arrow", + "audio", + "augmented reality", + "data", + "direction", + "disabled", + "discover", + "enabled", + "explore", + "find", + "follow", + "live", + "locate", + "location", + "mapping", + "motion", + "movement", + "music", + "navigation", + "note", + "off", + "offline", + "on", + "path", + "pinpoint", + "pointer", + "position", + "real-time", + "sense", + "sensor", + "slash", + "sound", + "spatial", + "spatial tracking", + "three dimensional", + "trace", + "tracking", + "virtual reality", + "vr" + ], + "popularity": 1494 + }, + "SPEAKER": { + "tags": [ + "acoustic", + "acoustics", + "adjust", + "amplifier", + "audio", + "audio device", + "box", + "broadcast", + "communication", + "control", + "earphone", + "electronic", + "hifi", + "listen", + "loud", + "media", + "megaphone", + "multimedia", + "music", + "mute", + "noise", + "play", + "playback", + "quiet", + "settings", + "sound", + "speaker", + "speakerphone", + "stereo", + "system", + "unmute", + "video", + "voice", + "volume" + ], + "popularity": 4836 + }, + "SPEAKER_GROUP": { + "tags": [ + "audio", + "audio devices", + "audio group", + "audio output", + "box", + "casting", + "configuration", + "connect", + "connect devices", + "control", + "device management", + "electronic", + "group", + "grouping", + "link", + "loud", + "media", + "multiple", + "multiple speakers", + "music", + "network", + "playback", + "settings", + "sharing", + "sound", + "sound devices", + "sound group", + "speaker", + "speaker group", + "speakers", + "stereo", + "stream", + "sync", + "system", + "video", + "volume", + "volume group", + "wireless" + ], + "popularity": 2233 + }, + "SPEAKER_NOTES": { + "tags": [ + "annotation", + "audio", + "bubble", + "bullet points", + "chat", + "comment", + "communicate", + "detail", + "dialogue", + "document", + "explanation", + "format", + "information", + "lecture", + "lines", + "list", + "meeting", + "message", + "mute", + "notes", + "page", + "paper", + "presentation", + "record", + "rectangle", + "sound", + "speaker", + "speaker notes", + "speech", + "square", + "talking", + "text", + "three lines", + "transcript", + "voice", + "volume" + ], + "popularity": 16680 + }, + "SPEAKER_NOTES_OFF": { + "tags": [ + "bubble", + "cancel", + "chat", + "comment", + "communicate", + "confidential notes", + "control", + "crossed out", + "diagonal line", + "disable", + "disabled", + "disabled speaker notes", + "document", + "enabled", + "format", + "hide notes", + "interface", + "lines", + "list", + "meeting", + "meeting notes off", + "message", + "mute", + "no speaker notes", + "notes", + "notes off", + "off", + "on", + "paper", + "presentation", + "presentation notes off", + "presenter view off", + "private notes", + "slash", + "speaker", + "speaker notes off", + "speech", + "text", + "view" + ], + "popularity": 4171 + }, + "SPEAKER_PHONE": { + "tags": [ + "android", + "audio", + "broadcast", + "button", + "call", + "cell", + "communication", + "conference", + "control", + "device", + "enable", + "handsfree", + "hardware", + "icon", + "ios", + "loud", + "media", + "mobile", + "on", + "options", + "os", + "output", + "phone", + "settings", + "shape", + "signal", + "sound", + "speaker", + "speakerphone", + "symbol", + "tablet", + "talking", + "toggle", + "voice", + "volume", + "waves" + ], + "popularity": 2456 + }, + "SPEED": { + "tags": [ + "acceleration", + "arrow", + "automotive", + "car", + "circle", + "circular", + "control", + "controls", + "dashboard", + "data", + "decreasing", + "dial", + "fast", + "gauge", + "increasing", + "indicator", + "information", + "lines", + "measurement", + "meter", + "motion", + "music", + "needle", + "performance", + "pointed", + "progress", + "setting", + "settings", + "slow", + "speed", + "speedometer", + "ticks", + "values", + "velocity", + "video" + ], + "popularity": 32189 + }, + "SPELLCHECK": { + "tags": [ + "a", + "accuracy", + "action", + "alphabet", + "approve", + "button", + "character", + "check", + "checkmark", + "control", + "correct", + "correction", + "document", + "editor", + "font", + "grammar", + "interface", + "language", + "letter", + "letters", + "mark", + "ok", + "processor", + "proofread", + "proofreading", + "review", + "right", + "select", + "spell", + "spellcheck", + "symbol", + "text", + "tick", + "type", + "typing", + "ui", + "ux", + "validation", + "verified", + "word", + "write", + "writing", + "yes" + ], + "popularity": 6064 + }, + "SPLITSCREEN": { + "tags": [ + "arrangement", + "arrangement of elements", + "column", + "display", + "divide", + "dual screen", + "grid", + "horizontal split", + "interface layout", + "layout", + "monitor", + "multi-window", + "multiple windows", + "multitasking", + "organization", + "pane", + "panels", + "presentation", + "productivity", + "row", + "screen", + "screen layout", + "sections", + "separate", + "side by side", + "spaces", + "split", + "split screen", + "splitscreen", + "user interface view", + "vertical split", + "view", + "view options", + "window", + "workspace" + ], + "popularity": 5545 + }, + "SPOKE": { + "tags": [ + "access point", + "broadcast", + "center", + "central point", + "communicate", + "connect", + "connection", + "connections", + "directions", + "disperse", + "distribution", + "emanating", + "expand", + "grow", + "links", + "network", + "nodes", + "outward", + "points", + "radial lines", + "radiating", + "radius", + "rays", + "share", + "signal", + "spoke", + "spread", + "star", + "wheel", + "wifi" + ], + "popularity": 2558 + }, + "SPORTS": { + "tags": [ + "action", + "activity", + "athlete", + "athletic", + "blowing", + "coach", + "competition", + "dynamic", + "entertainment", + "exercise", + "fast", + "figure", + "fitness", + "game", + "healthy", + "hobby", + "instrument", + "jog", + "lifestyle", + "motion", + "movement", + "performance", + "person", + "race", + "referee", + "runner", + "running", + "silhouette", + "social", + "sound", + "speed", + "sports", + "sprint", + "swift", + "track and field", + "training", + "warning", + "whistle" + ], + "popularity": 6796 + }, + "SPORTS_BAR": { + "tags": [ + "alcohol", + "bar", + "beer", + "building", + "casual", + "cheers", + "drink", + "drinking", + "drinks", + "entertainment", + "establishment", + "facility", + "food", + "gathering", + "hangout", + "leisure", + "liquor", + "location", + "lounge", + "nightlife", + "pint", + "place", + "pub", + "rectangular", + "relaxation", + "restaurant", + "rounded corners", + "social", + "sports", + "sports bar", + "tavern", + "venue" + ], + "popularity": 7199 + }, + "SPORTS_BASEBALL": { + "tags": [ + "activity", + "american sport", + "athlete", + "athletic", + "ball", + "baseball", + "catch", + "circle", + "curved lines", + "entertainment", + "equipment", + "exercise", + "field", + "game", + "gear", + "hit", + "hobby", + "league", + "leisure", + "mlb", + "pitch", + "play", + "player", + "recreation", + "round", + "seams", + "social", + "softball", + "sport", + "sports", + "stadium", + "stitches", + "team", + "throw", + "usa sport" + ], + "popularity": 4771 + }, + "SPORTS_BASKETBALL": { + "tags": [ + "activity", + "arena", + "athlete", + "athletic", + "ball", + "basketball", + "circle", + "competition", + "court", + "curves", + "dribble", + "entertainment", + "exercise", + "fitness", + "game", + "hobby", + "hoop", + "league", + "lines", + "match", + "net", + "orange ball", + "play", + "points", + "recreation", + "round", + "score", + "seams", + "shoot", + "social", + "sports", + "team", + "workout" + ], + "popularity": 7867 + }, + "SPORTS_CRICKET": { + "tags": [ + "activity", + "athlete", + "athletic", + "athletics", + "ball", + "bat", + "circle", + "competition", + "cricket", + "entertainment", + "equipment", + "event", + "exercise", + "game", + "hobby", + "leisure", + "line", + "match", + "outdoor", + "play", + "recreation", + "social", + "sphere", + "sport", + "sports", + "stick", + "stump", + "team", + "tournament", + "wicket" + ], + "popularity": 3047 + }, + "SPORTS_ESPORTS": { + "tags": [ + "asset", + "competitive gaming", + "computer games", + "console", + "console controller", + "console games", + "control", + "controller", + "device", + "digital", + "digital entertainment", + "entertainment", + "esports", + "game", + "game console", + "game controller", + "game input", + "gamepad", + "gaming", + "gaming controller", + "google", + "handheld", + "hardware", + "hobby", + "joystick", + "leisure", + "online", + "online gaming", + "play", + "play games", + "playstation", + "remote", + "social", + "sports", + "stadia", + "technology", + "tournament", + "video", + "video game", + "video game controller", + "video games", + "videogame", + "xbox" + ], + "popularity": 32834 + }, + "SPORTS_FOOTBALL": { + "tags": [ + "activity", + "athlete", + "athletic", + "ball", + "championship", + "competition", + "entertainment", + "equipment", + "event", + "exercise", + "field", + "football", + "fun", + "game", + "gear", + "hobby", + "league", + "leisure", + "lines", + "match", + "outdoor", + "park", + "pastime", + "pattern", + "play", + "recreation", + "round", + "soccer", + "social", + "sphere", + "sports", + "stitching", + "team", + "tournament" + ], + "popularity": 4011 + }, + "SPORTS_GOLF": { + "tags": [ + "activity", + "athlete", + "athletic", + "ball", + "club", + "course", + "driver", + "entertainment", + "exercise", + "game", + "golf", + "golfer", + "golfing", + "hobby", + "hole", + "iron", + "leisure", + "outdoors", + "play", + "putt", + "recreation", + "social", + "sport", + "sports", + "stroke", + "swing", + "tee", + "wedge" + ], + "popularity": 2840 + }, + "SPORTS_GYMNASTICS": { + "tags": [ + "active", + "activity", + "agility", + "athlete", + "athletic", + "balance", + "body", + "competition", + "entertainment", + "exercise", + "figure", + "fitness", + "flexibility", + "gymnastics", + "healthy", + "hobby", + "human", + "leisure", + "movement", + "performance", + "person", + "pose", + "recreation", + "silhouette", + "social", + "sport", + "sports", + "training", + "workout" + ], + "popularity": 2859 + }, + "SPORTS_HANDBALL": { + "tags": [ + "activity", + "athlete", + "athletic", + "athletic event", + "athletics", + "ball", + "body", + "circle", + "competition", + "court", + "curved lines", + "entertainment", + "equipment", + "exercise", + "field", + "game", + "gear", + "gym", + "handball", + "hobby", + "human", + "indoor sport", + "leisure", + "lines", + "match", + "people", + "person", + "play", + "player", + "recreation", + "rounded", + "seam", + "social", + "sport", + "sports", + "sports and recreation", + "sports equipment", + "team sport" + ], + "popularity": 4787 + }, + "SPORTS_HOCKEY": { + "tags": [ + "activity", + "athlete", + "athletic", + "athletic activity", + "athletic game", + "athletic sports", + "championship", + "club", + "competition", + "entertainment", + "exercise", + "field", + "game", + "goal", + "hobby", + "hockey", + "ice", + "league", + "leisure", + "net", + "puck", + "recreation", + "rink", + "scoreboard", + "scoreboard icon", + "social", + "sport", + "sports", + "stats", + "stats icon", + "stick", + "sticks", + "team", + "tournament", + "winter sports" + ], + "popularity": 2175 + }, + "SPORTS_KABADDI": { + "tags": [ + "action", + "active", + "agility", + "asian", + "athlete", + "athletic", + "athletics", + "body", + "combat", + "competition", + "court", + "defense", + "dynamic", + "entertainment", + "exercise", + "fighting", + "figure", + "fitness", + "game", + "hobby", + "human", + "india", + "kabaddi", + "mat", + "movement", + "people", + "person", + "physical", + "player", + "power", + "raid", + "recreational", + "silhouette", + "social", + "sports", + "sportsperson", + "struggle", + "team", + "traditional", + "wrestle", + "wrestling" + ], + "popularity": 6873 + }, + "SPORTS_MARTIAL_ARTS": { + "tags": [ + "action", + "activity", + "agility", + "arts", + "athlete", + "athletic", + "combat", + "competition", + "discipline", + "dojo", + "entertainment", + "event", + "exercise", + "fighting", + "fitness", + "flexibility", + "game", + "gym", + "hobby", + "human", + "karate", + "kick", + "martial", + "martial arts", + "movement", + "people", + "person", + "physical", + "power", + "punch", + "self-defense", + "social", + "sports", + "stance", + "strength", + "strike", + "studio", + "technique", + "training" + ], + "popularity": 3117 + }, + "SPORTS_MMA": { + "tags": [ + "action", + "activity", + "aggression", + "arena", + "arts", + "athlete", + "athletic", + "boxing", + "combat", + "competition", + "contest", + "dynamic", + "entertainment", + "event", + "exercise", + "fighting", + "fitness", + "game", + "glove", + "gym", + "health", + "hobby", + "martial", + "martial arts", + "match", + "mixed", + "mma", + "power", + "punch", + "ring", + "social", + "speed", + "sports", + "strength", + "strike", + "training", + "workout" + ], + "popularity": 3035 + }, + "SPORTS_MOTORSPORTS": { + "tags": [ + "activity", + "athlete", + "athletic", + "automobile", + "automotive", + "automotive industry", + "bike", + "car", + "championship", + "competition", + "drive", + "driving", + "entertainment", + "event", + "fast", + "go-kart", + "helmet", + "hobby", + "kart", + "leisure", + "motor vehicle", + "motorcycle", + "motorsport", + "motorsport event", + "motorsports", + "protect", + "race", + "race car", + "racing", + "recreation", + "social", + "speed", + "sports", + "sports car", + "track", + "transport", + "transportation", + "vehicle" + ], + "popularity": 5041 + }, + "SPORTS_RUGBY": { + "tags": [ + "activity", + "athlete", + "athletic", + "athletic gear", + "ball", + "competition", + "entertainment", + "equipment", + "exercise", + "field", + "fitness", + "game", + "game object", + "game piece", + "gear", + "hobby", + "laces", + "leather", + "movement", + "oval", + "oval object", + "play", + "recreation", + "recreational activity", + "rugby", + "social", + "sport", + "sports", + "sports equipment", + "sports gear", + "stitched", + "team", + "team sport" + ], + "popularity": 2058 + }, + "SPORTS_SCORE": { + "tags": [ + "athletics", + "competition", + "destination", + "display", + "final score", + "flag", + "game", + "game score", + "goal", + "live score", + "match", + "number", + "numbers", + "points", + "result", + "results", + "score", + "score board", + "scoreboard", + "sport competition", + "sport results", + "sport scores", + "sport stats", + "sports", + "sports score", + "statistics", + "stats", + "tally", + "team score" + ], + "popularity": 11270 + }, + "SPORTS_SOCCER": { + "tags": [ + "activity", + "athlete", + "athletic", + "ball", + "championship", + "circle", + "competition", + "dribble", + "entertainment", + "exercise", + "field", + "fitness", + "football", + "game", + "goal", + "hexagon", + "hobby", + "kick", + "league", + "leisure", + "match", + "pentagon", + "play", + "recreation", + "soccer", + "social", + "sport", + "sports", + "stadium", + "team", + "training", + "workout" + ], + "popularity": 16479 + }, + "SPORTS_TENNIS": { + "tags": [ + "active", + "activity", + "athlete", + "athletic", + "ball", + "bat", + "competition", + "court", + "entertainment", + "equipment", + "exercise", + "fitness", + "fun", + "game", + "gear", + "health", + "hobby", + "indoor", + "leisure", + "match", + "outdoors", + "play", + "player", + "racket", + "racquet", + "recreation", + "social", + "sport", + "sports", + "tennis", + "wellness" + ], + "popularity": 6281 + }, + "SPORTS_VOLLEYBALL": { + "tags": [ + "activity", + "athlete", + "athletic", + "ball", + "block", + "competition", + "court", + "dig", + "entertainment", + "exercise", + "fitness", + "fun", + "game", + "hobby", + "indoor", + "leisure", + "lines", + "net", + "outdoor", + "physical", + "play", + "recreation", + "round", + "serve", + "set", + "social", + "sphere", + "spike", + "sport", + "sports", + "stitch", + "striped", + "team", + "volleyball" + ], + "popularity": 4312 + }, + "SQUARE": { + "tags": [ + "area", + "basic", + "block", + "border", + "box", + "building block", + "container", + "draw", + "element", + "empty", + "form", + "four", + "frame", + "fundamental", + "geometry", + "graphic", + "grid", + "layout", + "minimal", + "object", + "outline", + "placeholder", + "quadrangle", + "region", + "section", + "shape", + "sides", + "simple", + "square", + "structure", + "symbol", + "vector" + ], + "popularity": 7289 + }, + "SQUARE_FOOT": { + "tags": [ + "architecture", + "area", + "construction", + "design", + "diagram", + "dimension", + "feet", + "floor plan", + "foot", + "geometry", + "guide", + "height", + "inches", + "layout", + "length", + "linear", + "map", + "mapping", + "measure", + "measurement", + "plan", + "property", + "proportion", + "real estate", + "ruler", + "scale", + "school", + "set", + "size", + "sketch", + "space", + "square", + "square footage", + "tools", + "width" + ], + "popularity": 12499 + }, + "SSID_CHART": { + "tags": [ + "analysis", + "analytics", + "bars", + "chart", + "communication", + "connection", + "connectivity", + "data", + "diagram", + "graph", + "information", + "internet", + "lines", + "measurement", + "network", + "performance", + "progress", + "report", + "signal", + "ssid", + "statistics", + "status", + "strength", + "trend", + "visual", + "wifi", + "wireless" + ], + "popularity": 3348 + }, + "STACKED_BAR_CHART": { + "tags": [ + "analysis", + "analytics", + "bar", + "bar chart", + "bars", + "business", + "chart", + "chart-chart", + "dashboard", + "data", + "data visualization", + "diagram", + "financial", + "graph", + "growth", + "history", + "infographic", + "information", + "measure", + "metrics", + "performance", + "presentation", + "progress", + "report", + "results", + "results graph", + "stacked", + "stacked bars", + "stacked graph", + "statistics", + "tracking", + "trend", + "visualization" + ], + "popularity": 12617 + }, + "STACKED_LINE_CHART": { + "tags": [ + "analysis", + "analytics", + "area chart", + "business", + "chart", + "data", + "decline", + "diagram", + "finance", + "graph", + "growth", + "infographic", + "information", + "layered", + "line", + "lines", + "measure", + "measurement", + "metrics", + "multiple lines", + "performance", + "plotting", + "progress", + "report", + "representation", + "result", + "stacked", + "statistics", + "summary", + "tracking", + "trend", + "visualization" + ], + "popularity": 8655 + }, + "STADIUM": { + "tags": [ + "activity", + "amphitheater", + "architecture", + "arena", + "audience", + "bleachers", + "building", + "coliseum", + "competition", + "concert", + "court", + "crowd", + "entertainment", + "event", + "field", + "game", + "grandstand", + "indoor", + "landmark", + "leisure", + "local", + "location", + "map", + "outdoor", + "performance", + "point of interest", + "recreation", + "seats", + "sports", + "stadium", + "star", + "structure", + "things", + "ticket", + "track", + "travel", + "venue" + ], + "popularity": 2653 + }, + "STAIRS": { + "tags": [ + "abstract", + "access", + "architecture", + "ascending", + "building", + "climb", + "descending", + "direction", + "down", + "downward", + "elevation", + "fall", + "floor", + "geometric", + "icon", + "incline", + "ladder", + "level", + "linear", + "movement", + "navigate", + "path", + "perspective", + "rise", + "shape", + "simple", + "staircase", + "stairs", + "stairway", + "stairwell", + "steps", + "stroke", + "symbol", + "up", + "upward" + ], + "popularity": 4531 + }, + "STAR": { + "tags": [ + "add to favorite", + "best", + "bookmark", + "border", + "empty", + "empty star", + "favorite", + "five pointed star", + "five points", + "grade", + "highlight", + "hollow", + "hollow star", + "important", + "mark", + "news", + "not filled", + "outline", + "point", + "ranking", + "rate", + "rating", + "rating symbol", + "save", + "shape", + "star", + "symbol", + "toggle", + "ui action", + "ui element", + "unselected" + ], + "popularity": 143879 + }, + "STAR_BORDER": { + "tags": [ + "add to favorite", + "best", + "bookmark", + "border", + "empty", + "empty star", + "favorite", + "five pointed star", + "five points", + "grade", + "highlight", + "hollow", + "hollow star", + "important", + "mark", + "news", + "not filled", + "outline", + "point", + "ranking", + "rate", + "rating", + "rating symbol", + "save", + "shape", + "star", + "symbol", + "toggle", + "ui action", + "ui element", + "unselected" + ], + "popularity": 55895 + }, + "STAR_BORDER_PURPLE500": { + "tags": [ + "500", + "add to favorite", + "best", + "bookmark", + "border", + "empty", + "empty star", + "favorite", + "five pointed star", + "five points", + "grade", + "highlight", + "hollow", + "hollow star", + "important", + "mark", + "news", + "not filled", + "outline", + "point", + "purple", + "ranking", + "rate", + "rating", + "rating symbol", + "save", + "shape", + "star", + "symbol", + "toggle", + "ui action", + "ui element", + "unselected" + ], + "popularity": 7483 + }, + "STAR_HALF": { + "tags": [ + "achievement", + "assessment", + "bookmark", + "completion", + "evaluation", + "favorite", + "favorite icon", + "feedback", + "half", + "half filled star", + "half star", + "highlight", + "important", + "incomplete star", + "mark", + "mark icon", + "marked", + "partial star", + "progress", + "progress indicator", + "ranking", + "rate", + "rating", + "rating icon", + "rating rank", + "rating system", + "review", + "review icon", + "reward", + "save", + "saved", + "score", + "score icon", + "shape", + "special", + "star", + "status", + "toggle", + "ui element", + "user rating", + "visual indicator" + ], + "popularity": 17947 + }, + "STAR_OUTLINE": { + "tags": [ + "add to favorite", + "bookmark", + "border", + "empty", + "empty star", + "favorite", + "five pointed star", + "five points", + "grade", + "half", + "highlight", + "hollow", + "hollow star", + "important", + "mark", + "news", + "not filled", + "outline", + "point", + "ranking", + "rate", + "rating", + "rating symbol", + "save", + "shape", + "star", + "symbol", + "toggle", + "ui action", + "ui element", + "unselected" + ], + "popularity": 38224 + }, + "STAR_PURPLE500": { + "tags": [ + "500", + "add to favorite", + "best", + "bookmark", + "border", + "empty", + "empty star", + "favorite", + "five pointed star", + "five points", + "grade", + "highlight", + "hollow", + "hollow star", + "important", + "mark", + "news", + "not filled", + "outline", + "point", + "purple", + "ranking", + "rate", + "rating", + "rating symbol", + "save", + "shape", + "star", + "symbol", + "toggle", + "ui action", + "ui element", + "unselected" + ], + "popularity": 9945 + }, + "STAR_RATE": { + "tags": [ + "achievement", + "assessment", + "award", + "bookmark", + "celestial", + "evaluation", + "excellence", + "favorite", + "feedback", + "five points", + "geometry", + "highlight", + "important", + "mark", + "marked", + "pointed", + "positive", + "preference", + "quality", + "ranking", + "rate", + "rating", + "rating rank", + "review", + "reward", + "save", + "saved", + "selection", + "shape", + "special", + "star" + ], + "popularity": 81362 + }, + "STARS": { + "tags": [ + "achievement", + "alert", + "badge", + "bookmark", + "bright", + "circle", + "favorite", + "feature", + "five point", + "geometric", + "glowing", + "highlight", + "important", + "indicator", + "magic", + "marked", + "new", + "notification", + "points", + "premium", + "quality", + "ranking", + "rate", + "rating", + "rating rank", + "reward", + "save", + "saved", + "shape", + "shiny", + "sparkle", + "special", + "star", + "stars", + "success", + "update" + ], + "popularity": 35021 + }, + "START": { + "tags": [ + "action", + "arrow", + "audio", + "begin", + "button", + "continue", + "control", + "enter", + "film", + "forward", + "go", + "initiate", + "keyboard", + "launch", + "media", + "multimedia", + "music", + "navigation", + "next", + "play", + "playback", + "pointer", + "proceed", + "right", + "right arrow", + "run", + "start", + "stream", + "triangle", + "ui control", + "video" + ], + "popularity": 10384 + }, + "STAY_CURRENT_LANDSCAPE": { + "tags": [ + "android", + "current", + "device", + "device display", + "direction", + "display", + "display setting", + "hardware", + "horizontal", + "image", + "ios", + "landscape", + "layout", + "lock orientation", + "media", + "media controls", + "mobile", + "mobile device", + "orientation", + "os", + "phone", + "photo", + "photo viewer", + "primary", + "rectangle", + "rectangle with rounded corners", + "rotate", + "screen", + "stay", + "tablet", + "video", + "video playback", + "view", + "viewing mode" + ], + "popularity": 1545 + }, + "STAY_CURRENT_PORTRAIT": { + "tags": [ + "android", + "border", + "call", + "cell", + "cellphone", + "cellular", + "chat", + "communication", + "current", + "device", + "display", + "frame", + "gadget", + "handheld", + "hardware", + "ios", + "mobile", + "orientation", + "os", + "outline", + "phone", + "portable", + "portrait", + "rectangle", + "rounded corners", + "screen", + "smartphone", + "stay", + "stroke", + "tablet", + "technology", + "text", + "vertical" + ], + "popularity": 4791 + }, + "STAY_PRIMARY_LANDSCAPE": { + "tags": [ + "android", + "current", + "device", + "device display", + "direction", + "display", + "display setting", + "hardware", + "horizontal", + "image", + "ios", + "landscape", + "layout", + "lock orientation", + "media", + "media controls", + "mobile", + "mobile device", + "orientation", + "os", + "phone", + "photo", + "photo viewer", + "primary", + "rectangle", + "rectangle with rounded corners", + "rotate", + "screen", + "stay", + "tablet", + "video", + "video playback", + "view", + "viewing mode" + ], + "popularity": 1410 + }, + "STAY_PRIMARY_PORTRAIT": { + "tags": [ + "!", + "alert", + "android", + "attention", + "bug", + "caution", + "critical", + "danger", + "device", + "download", + "error", + "exclamation", + "fix", + "hardware", + "hazard", + "important", + "ios", + "issue", + "mark", + "mobile", + "notification", + "os", + "patch", + "phone", + "portrait", + "precaution", + "problem", + "protection", + "screen", + "secure", + "security", + "shield", + "symbol", + "system", + "tablet", + "threat", + "triangle", + "update", + "vulnerability", + "warning" + ], + "popularity": 3602 + }, + "STICKY_NOTE_2": { + "tags": [ + "2", + "angle", + "bookmark", + "communication", + "corner", + "data", + "document", + "fold", + "ideas", + "information", + "list", + "mark", + "memo", + "message", + "note", + "office", + "organization", + "page", + "paper", + "peel", + "planning", + "post it", + "records", + "rectangle", + "reminder", + "square", + "stationery", + "sticky", + "sticky note", + "tab", + "task", + "text", + "thoughts", + "work", + "writing" + ], + "popularity": 24732 + }, + "STOP": { + "tags": [ + "action", + "audio", + "basic", + "block", + "button", + "close", + "command", + "control", + "control panel", + "controls", + "end", + "exit", + "filled", + "finish", + "geometric", + "halt", + "icon", + "media", + "music", + "pause", + "play", + "playback", + "player", + "recorder", + "recording", + "shape", + "simple", + "solid", + "square", + "stop", + "symbol", + "video" + ], + "popularity": 31680 + }, + "STOP_CIRCLE": { + "tags": [ + "audio", + "block", + "button", + "cancel", + "caution", + "circle", + "command", + "control", + "controls", + "end", + "exit", + "finish", + "forbidden", + "halt", + "media", + "media control", + "music", + "pause", + "play", + "playback", + "playback control", + "player", + "prevent", + "prohibit", + "record stop", + "recording", + "restricted", + "round", + "square", + "stop", + "terminate", + "video", + "warning" + ], + "popularity": 15837 + }, + "STOP_SCREEN_SHARE": { + "tags": [ + "android", + "application", + "arrow", + "cast", + "chrome", + "close", + "collaboration", + "computer", + "conference", + "content sharing", + "desktop", + "device", + "diagonal line", + "disabled", + "display", + "enabled", + "end", + "end share", + "exit", + "hardware", + "ios", + "laptop", + "mac", + "meeting", + "mirror", + "monitor", + "multimedia", + "off", + "offline", + "on", + "online communication", + "os", + "presentation", + "rectangle", + "remote work", + "screen", + "share", + "sharing", + "slash", + "software", + "stop", + "stop screen share", + "stream", + "streaming", + "technology", + "video call", + "web", + "window" + ], + "popularity": 2294 + }, + "STORAGE": { + "tags": [ + "archive", + "backup", + "boxes", + "capacity", + "cloud", + "computer", + "computing", + "data", + "database", + "digital", + "disk", + "documents", + "drive", + "files", + "hard drive", + "horizontal", + "information", + "layers", + "lines", + "memory", + "rectangle", + "save", + "server", + "server rack", + "space", + "square", + "stack", + "storage", + "technology", + "vertical" + ], + "popularity": 28250 + }, + "STORE": { + "tags": [ + "address", + "aisle", + "bill", + "building", + "business", + "buying", + "card", + "cash", + "coin", + "commerce", + "commercial", + "company", + "credit", + "currency", + "destination", + "directory", + "dollars", + "establishment", + "goods", + "location", + "mall", + "map", + "marker", + "market", + "marketplace", + "merchandise", + "money", + "navigation", + "online", + "pay", + "payment", + "pin", + "place", + "pointer", + "retail", + "retail building", + "selling", + "shop", + "shop building", + "shopping", + "store", + "storefront" + ], + "popularity": 70308 + }, + "STORE_MALL_DIRECTORY": { + "tags": [ + "address", + "aisle", + "building", + "business", + "buying", + "commerce", + "commercial", + "destination", + "directory", + "establishment", + "goods", + "location", + "mall", + "map", + "marker", + "market", + "marketplace", + "merchandise", + "navigation", + "pin", + "place", + "pointer", + "retail", + "retail building", + "selling", + "shop", + "shop building", + "shopping", + "store", + "storefront" + ], + "popularity": 5752 + }, + "STOREFRONT": { + "tags": [ + "brick and mortar", + "building", + "business", + "buy", + "buying", + "cafe", + "commerce", + "commercial", + "e-commerce", + "economy", + "establishment", + "front", + "goods", + "lines", + "market", + "marketplace", + "merchant", + "online store", + "places", + "products", + "purchase", + "rectangular", + "restaurant", + "retail", + "sale", + "sell", + "selling", + "shop", + "shop icon", + "shopping", + "store", + "store building", + "storefront", + "storefront icon", + "trade", + "vendor", + "window" + ], + "popularity": 53188 + }, + "STORM": { + "tags": [ + "abstract", + "alert", + "angular", + "bad weather", + "bolt", + "climate", + "crackle", + "danger", + "electrical storm", + "electricity", + "energy", + "flash", + "forecast", + "hurricane", + "jagged line", + "lightning", + "nature", + "pointy", + "power", + "severe weather", + "sky", + "storm", + "strike", + "temperature", + "thunder", + "twister", + "warning", + "weather", + "wind", + "zig zag" + ], + "popularity": 3325 + }, + "STRAIGHT": { + "tags": [ + "abstract", + "abstract shape", + "arrow", + "arrows", + "bar", + "basic shape", + "dash", + "direction", + "directions", + "divider", + "element", + "geometric shape", + "horizontal bar", + "horizontal line", + "horizontal rule", + "line", + "maps", + "minimalist", + "navigation", + "path", + "route", + "rule", + "segment", + "separator", + "separator bar", + "shape", + "sign", + "simple shape", + "single line", + "solid line", + "straight", + "straight line", + "stroke", + "thin line", + "traffic", + "underscore", + "up" + ], + "popularity": 3294 + }, + "STRAIGHTEN": { + "tags": [ + "adjust", + "align", + "angle", + "arrangement", + "bend", + "calibrate", + "curve", + "distribute", + "evenly", + "grid", + "horizontal", + "layout", + "length", + "levels", + "line", + "linear", + "measure", + "measurement", + "order", + "organize", + "parallel", + "perpendicular", + "position", + "right angle", + "ruler", + "size", + "straight", + "straighten", + "structure", + "symmetrical", + "tidy", + "uniform", + "vertical" + ], + "popularity": 15887 + }, + "STREAM": { + "tags": [ + "abstract", + "broadcast", + "cast", + "communication", + "connected", + "connection", + "current", + "data stream", + "digital", + "dynamic", + "energy", + "feed", + "flow", + "internet", + "lines", + "liquid", + "live", + "live stream", + "motion", + "movement", + "multiple lines", + "network", + "organic shape", + "parallel lines", + "real-time", + "sequence", + "signal", + "stream", + "technology", + "transmission", + "undulating lines", + "water", + "wave pattern", + "waves", + "wireless" + ], + "popularity": 9739 + }, + "STREETVIEW": { + "tags": [ + "360 degrees", + "angle", + "camera", + "environment", + "explore", + "eye", + "globe", + "immersive", + "interactive", + "landscape", + "location", + "mapping", + "maps", + "navigation", + "outdoors", + "panoramic", + "perspective", + "place", + "point of interest", + "roads", + "sphere", + "street", + "street view", + "streetview", + "tour", + "travel", + "view", + "virtual reality", + "vision", + "vr", + "world" + ], + "popularity": 2202 + }, + "STRIKETHROUGH_S": { + "tags": [ + "alphabet", + "character", + "correction", + "cross", + "cross out", + "delete", + "doc", + "document", + "edit", + "edit text", + "editing", + "editor", + "font", + "formatting", + "incorrect", + "letter", + "letter s", + "letters", + "line through text", + "markdown", + "out", + "proofread", + "remove", + "rich text", + "s", + "sheet", + "spreadsheet", + "strike", + "strikethrough", + "styles", + "symbol", + "text", + "text editing", + "text formatting", + "text style", + "type", + "typo", + "word", + "writing" + ], + "popularity": 3521 + }, + "STROLLER": { + "tags": [ + "accessibility", + "accessible", + "baby", + "buggy", + "care", + "carriage", + "child", + "childcare", + "children", + "family", + "father", + "handle", + "infant", + "kid", + "mother", + "newborn", + "outdoor", + "parent", + "park", + "perambulator", + "pram", + "pushchair", + "seat", + "shopping", + "stroller", + "toddler", + "transportation", + "travel", + "walk", + "wheels", + "young" + ], + "popularity": 1615 + }, + "STYLE": { + "tags": [ + "adjust", + "alignment", + "arrangement", + "block", + "booklet", + "cards", + "configure", + "content", + "design", + "document", + "edit", + "editor", + "filters", + "formatting", + "indent", + "layout", + "lines", + "menu", + "options", + "paragraph", + "paragraphs", + "preferences", + "presentation", + "rich text", + "settings", + "spacing", + "structure", + "style", + "tags", + "text", + "typeface", + "typography", + "visual", + "writing" + ], + "popularity": 16841 + }, + "SUBDIRECTORY_ARROW_LEFT": { + "tags": [ + "angle", + "arrow", + "back", + "button", + "control", + "curve", + "direction", + "directory", + "down", + "file", + "folder", + "go back", + "hierarchy", + "indicate", + "left", + "level up", + "line", + "move up", + "navigation", + "path", + "point", + "return", + "reverse", + "structure", + "sub", + "subdirectory", + "symbol", + "ui element", + "up" + ], + "popularity": 5811 + }, + "SUBDIRECTORY_ARROW_RIGHT": { + "tags": [ + "angle", + "arrow", + "bend", + "continue", + "corner", + "curve", + "direction", + "directory", + "down", + "exit", + "file", + "folder", + "forward", + "guide", + "indent", + "jump", + "line", + "link", + "message", + "move", + "navigation", + "next", + "path", + "pointer", + "reply", + "return", + "right", + "route", + "sub", + "subdirectory", + "symbol", + "turn" + ], + "popularity": 12299 + }, + "SUBJECT": { + "tags": [ + "alignment", + "answer", + "assistance", + "balloon", + "bubble", + "chat", + "comment", + "communication", + "dialogue", + "doc", + "document", + "email", + "full", + "help", + "help bubble", + "icon", + "information", + "information bubble", + "isolated", + "justify", + "list", + "note", + "problem", + "query", + "query bubble", + "question", + "question mark", + "rounded corners", + "shape", + "square", + "subject", + "support", + "symbol", + "text", + "writing" + ], + "popularity": 20540 + }, + "SUBSCRIPT": { + "tags": [ + "2", + "alphanumeric", + "baseline", + "character", + "chemical formula", + "doc", + "document", + "edit", + "editing", + "editor", + "equation", + "footnote", + "formatting", + "gmail", + "index", + "lower", + "math", + "novitas", + "number", + "power", + "science", + "sheet", + "smaller", + "spreadsheet", + "style", + "subscript", + "symbol", + "text", + "text editor", + "text format", + "text style", + "type", + "typesetting", + "typography", + "writing", + "writing tools", + "x" + ], + "popularity": 1733 + }, + "SUBSCRIPTIONS": { + "tags": [ + "abstract", + "alert", + "alerts", + "app", + "application", + "bell", + "button", + "channel", + "channels", + "circle", + "communication", + "content", + "digital", + "enroll", + "feed", + "graphic", + "icon", + "interface", + "list", + "media", + "mobile", + "news", + "notifications", + "order", + "play", + "rss", + "signup", + "stack", + "subscribe", + "subscriptions", + "symbol", + "technology", + "ui element", + "update", + "updates", + "web", + "website" + ], + "popularity": 15005 + }, + "SUBTITLES": { + "tags": [ + "accessibility", + "accessible", + "audio", + "caption", + "captions", + "cc", + "character", + "closed", + "closed captioning", + "control", + "conversation", + "deaf", + "decoder", + "dialogue", + "display", + "film", + "hearing impaired", + "language", + "lines", + "live caption", + "media", + "movie", + "movies", + "option", + "parallel lines", + "playback", + "reading", + "rectangle", + "screen", + "speech", + "square", + "subtitle", + "subtitles", + "text", + "three lines", + "translate", + "translation", + "tv", + "typography", + "video" + ], + "popularity": 8439 + }, + "SUBTITLES_OFF": { + "tags": [ + "accessibility", + "accessibility feature", + "accessible", + "audio", + "caption", + "captions disabled", + "captions off", + "cc", + "cc off", + "closed", + "closed captioning disabled", + "closed captioning off", + "diagonal line", + "disable", + "disabled", + "enabled", + "film", + "language", + "live caption", + "media control", + "movie", + "no", + "off", + "on", + "rectangle", + "slash", + "sound", + "square", + "streaming", + "subtitle", + "subtitles", + "subtitles disabled", + "subtitles off", + "text disabled", + "text off", + "toggle off", + "translate", + "turn off", + "tv", + "video", + "video control" + ], + "popularity": 3463 + }, + "SUBWAY": { + "tags": [ + "automobile", + "bike", + "car", + "cars", + "city", + "city transport", + "commute", + "line", + "maps", + "mass transit", + "metro", + "network", + "public network", + "public transit", + "public transport", + "rail", + "rail line", + "railroad", + "railway", + "route", + "scooter", + "station", + "subway", + "train", + "train line", + "transit", + "transit map", + "transport", + "transportation", + "travel", + "travel route", + "tunnel", + "underground", + "urban", + "urban rail", + "urban transport", + "vehicle" + ], + "popularity": 3180 + }, + "SUMMARIZE": { + "tags": [ + "arrows", + "aspect ratio", + "button", + "control", + "corners", + "corners out", + "display", + "doc", + "document", + "enlarge", + "expand", + "form", + "four arrows", + "fullscreen", + "growth", + "image", + "in", + "increase", + "list", + "magnify", + "maximize", + "media", + "menu", + "mode", + "note", + "out", + "presentation", + "report", + "scale", + "size", + "square", + "summary", + "toggle", + "video", + "view", + "viewer", + "window", + "zoom in" + ], + "popularity": 42715 + }, + "SUPERSCRIPT": { + "tags": [ + "2", + "alphanumeric", + "calculation", + "character", + "digit", + "doc", + "document", + "edit", + "editing", + "editor", + "elevated", + "equation", + "exponent", + "formatting", + "formula", + "gmail", + "index", + "letter", + "math", + "mathematics", + "notation", + "novitas", + "number", + "numeral", + "power", + "raised", + "sheet", + "small text", + "spreadsheet", + "style", + "superior", + "superscript", + "symbol", + "text", + "type", + "typography", + "word processor", + "writing", + "x" + ], + "popularity": 2088 + }, + "SUPERVISED_USER_CIRCLE": { + "tags": [ + "account", + "account settings", + "avatar", + "child", + "circle", + "control", + "face", + "family", + "figure", + "guardian", + "head", + "human", + "kid", + "limited access", + "monitored", + "parent", + "parental", + "parents", + "people", + "person", + "privacy", + "profile", + "restricted", + "safety", + "secure", + "shoulders", + "silhouette", + "supervised", + "supervised user circle", + "supervision", + "supervisor", + "user", + "user avatar", + "user profile", + "youth" + ], + "popularity": 30678 + }, + "SUPERVISOR_ACCOUNT": { + "tags": [ + "access", + "account", + "account settings", + "admin", + "administrator", + "avatar", + "block", + "configuration", + "control", + "control panel", + "custodian", + "face", + "family", + "filter", + "guardian", + "human", + "kids", + "manage", + "options", + "parent", + "parental", + "parental control", + "parental controls", + "parents", + "people", + "person", + "preferences", + "profile", + "restriction settings", + "restrictions", + "safety", + "security", + "settings", + "supervised", + "supervisor", + "supervisor account", + "tv settings", + "user", + "user profile", + "viewing restrictions" + ], + "popularity": 44800 + }, + "SUPPORT": { + "tags": [ + "advice", + "agent", + "assist", + "assistance", + "avatar", + "basic", + "buoy", + "call", + "common", + "communication", + "contact", + "essential", + "general", + "head", + "headphones", + "headset", + "help", + "human", + "information", + "life", + "lifebuoy", + "line art", + "outline", + "person", + "phone", + "question", + "representative", + "rescue", + "safe", + "safety", + "service", + "silhouette", + "simple", + "support", + "universal" + ], + "popularity": 23828 + }, + "SUPPORT_AGENT": { + "tags": [ + "advisor", + "agent", + "answer", + "assistance", + "avatar", + "bubble", + "call", + "care", + "chat", + "communication", + "consultant", + "contact", + "conversation", + "customer", + "customer service", + "dialog", + "dialogue", + "face", + "head", + "headphone", + "headset", + "help", + "online", + "operator", + "person", + "profile", + "question", + "representative", + "service", + "speech bubble", + "support", + "talk", + "tech support" + ], + "popularity": 99081 + }, + "SURFING": { + "tags": [ + "action", + "activity", + "athlete", + "athletic", + "beach", + "board", + "body", + "entertainment", + "exercise", + "extreme sport", + "figure", + "graphic", + "hobby", + "human", + "icon", + "illustration", + "individual", + "leisure", + "movement", + "ocean", + "outdoor", + "outline", + "people", + "person", + "recreation", + "sea", + "silhouette", + "social sports", + "sport", + "sports", + "stylized", + "summer", + "surfer", + "surfing", + "symbol", + "vacation", + "water", + "wave" + ], + "popularity": 4962 + }, + "SURROUND_SOUND": { + "tags": [ + "360 audio", + "adjustment", + "audio", + "audio setup", + "audio system", + "channel", + "channels", + "cinema", + "circle", + "configuration", + "control", + "entertainment", + "home theater", + "immersive", + "media", + "movie", + "multimedia", + "music", + "playback", + "settings", + "signal", + "sound", + "sound system", + "spatial audio", + "speaker", + "speakers", + "surround", + "surround sound", + "system", + "theater", + "video", + "volume", + "volumn", + "wireless" + ], + "popularity": 1664 + }, + "SWAP_CALLS": { + "tags": [ + "arrow", + "arrow up and down", + "arrows", + "bidirectional", + "calls", + "change direction", + "communications", + "connect", + "connection", + "device", + "direction", + "exchange", + "invert", + "linking", + "mobile", + "order", + "phone", + "rearrange", + "reorder", + "reverse", + "share", + "shift", + "sort", + "swap", + "switch", + "telephone", + "toggle", + "transfer", + "transition", + "two arrows", + "up down arrows", + "vertical arrows" + ], + "popularity": 3670 + }, + "SWAP_HORIZ": { + "tags": [ + "alternate", + "arrow", + "arrows", + "back", + "change", + "data transfer", + "direction", + "double-ended arrow", + "exchange", + "flow", + "forward", + "horizontal", + "horizontal swap", + "left arrow", + "move", + "movement", + "opposing arrows", + "orientation", + "rearrange", + "reorder", + "replace", + "right arrow", + "shift", + "sort", + "swap", + "switch", + "transaction", + "transfer", + "transform", + "two arrows" + ], + "popularity": 35881 + }, + "SWAP_HORIZONTAL_CIRCLE": { + "tags": [ + "alternate", + "arrow", + "arrows", + "back", + "back and forth", + "button", + "change", + "circle", + "circular", + "connection", + "convert", + "currency", + "cycle", + "direction", + "double arrow", + "exchange", + "exchange rate", + "flow", + "forward", + "horizontal", + "link", + "movement", + "reverse", + "rotate", + "round", + "shift", + "sideways", + "swap", + "switch", + "trade", + "transaction", + "transfer" + ], + "popularity": 8478 + }, + "SWAP_VERT": { + "tags": [ + "arrow", + "arrows", + "bidirectional", + "connection", + "data", + "direction", + "direction change", + "document", + "down", + "exchange", + "export", + "file", + "flow", + "import", + "interchange", + "link", + "move", + "navigation", + "process", + "reorder", + "shuffle", + "sort", + "sorting", + "swap", + "switch", + "sync", + "synchronize", + "transaction", + "transfer", + "up", + "up down", + "vert", + "vertical" + ], + "popularity": 25314 + }, + "SWAP_VERTICAL_CIRCLE": { + "tags": [ + "arrow", + "arrows", + "bidirectional", + "change", + "circle", + "circular", + "communication", + "content", + "data", + "direction", + "down", + "exchange", + "flow", + "move", + "opposite", + "orientation", + "rearrange", + "reorder", + "reverse", + "rotation", + "round", + "sort", + "sorting", + "swap", + "switch", + "transfer", + "two-way", + "up", + "vertical" + ], + "popularity": 5416 + }, + "SWIPE": { + "tags": [ + "action", + "animation", + "arrow", + "arrows", + "control", + "cursor", + "direction", + "drag", + "fingers", + "gesture", + "guide", + "hand", + "hands", + "help", + "horizontal", + "indicator", + "instruction", + "interaction", + "left", + "mobile", + "motion", + "movement", + "navigation", + "pan", + "pointer", + "progress", + "right", + "scroll", + "slide", + "swipe", + "touch", + "transition", + "tutorial" + ], + "popularity": 14619 + }, + "SWIPE_DOWN": { + "tags": [ + "action", + "arrows", + "content loading", + "control", + "direction", + "disable", + "down", + "down arrow", + "drag down", + "enable", + "finger", + "gesture", + "graphic", + "hand", + "hands", + "hit", + "input", + "interaction", + "interface control", + "mobile", + "move down", + "navigation", + "pointing down", + "pull down", + "pull to refresh", + "refresh", + "screen", + "scroll", + "scroll down", + "strike", + "swing", + "swipe down", + "swpie", + "symbol", + "take", + "touch", + "touchscreen", + "ui action", + "vertical movement" + ], + "popularity": 2439 + }, + "SWIPE_DOWN_ALT": { + "tags": [ + "action", + "alt", + "alternate", + "arrows", + "direction", + "disable", + "down", + "downwards", + "drag", + "enable", + "finger", + "gesture", + "guide", + "hand gesture", + "hands", + "hit", + "indication", + "indicator", + "instruction", + "interaction", + "interface", + "mobile", + "motion", + "move", + "navigation", + "pointer", + "pull down", + "screen", + "scroll", + "strike", + "swing", + "swipe down", + "swpie", + "take", + "tap", + "touch", + "touch screen", + "ui element" + ], + "popularity": 1568 + }, + "SWIPE_LEFT": { + "tags": [ + "action", + "app", + "arrow", + "arrows", + "back", + "button", + "command", + "control", + "direction", + "drag", + "finger", + "fingertip", + "gesture", + "guidance", + "hand", + "hit", + "indicator", + "instruction", + "interaction", + "left", + "mobile", + "move", + "movement", + "navigation", + "pointer", + "previous", + "prompt", + "reject", + "scroll", + "sideways", + "slide", + "strike", + "swing", + "swipe", + "swipe left", + "take", + "touch", + "ui", + "ux" + ], + "popularity": 3503 + }, + "SWIPE_LEFT_ALT": { + "tags": [ + "alt", + "archive", + "arrow", + "arrows", + "control", + "delete", + "direction", + "dismiss", + "finger", + "gesture", + "go left", + "hand", + "hit", + "horizontal", + "indicator", + "interaction", + "interface", + "left", + "move", + "movement", + "navigation", + "next", + "pointer", + "previous", + "reject", + "reveal", + "screen", + "scroll", + "show more", + "slide", + "strike", + "swing", + "swipe", + "take", + "touch" + ], + "popularity": 1426 + }, + "SWIPE_RIGHT": { + "tags": [ + "accept", + "action", + "advance", + "app", + "arrow", + "arrows", + "command", + "digital", + "direction", + "finger", + "forward", + "gesture", + "gesture control", + "graphic", + "hands", + "hit", + "horizontal movement", + "indicator", + "interaction", + "interface", + "mobile", + "motion", + "move", + "navigation", + "next", + "pointer", + "pointing", + "progress", + "right", + "screen", + "strike", + "swing", + "swipe right", + "swpie", + "take", + "touch", + "touchscreen", + "ui element", + "user control", + "website" + ], + "popularity": 3212 + }, + "SWIPE_RIGHT_ALT": { + "tags": [ + "accept", + "action", + "alt", + "arrow", + "arrows", + "control", + "cursor", + "direction", + "drag", + "finger", + "forward", + "gesture", + "hands", + "hit", + "indicator", + "instruction", + "interface", + "mobile", + "movement", + "navigation", + "next", + "pointer", + "right", + "screen", + "signal", + "skip", + "slide", + "strike", + "swing", + "swipe", + "swpie", + "take", + "touch", + "tutorial" + ], + "popularity": 1999 + }, + "SWIPE_UP": { + "tags": [ + "arc", + "arrow", + "arrows", + "caret", + "clean", + "curve", + "direction", + "disable", + "enable", + "finger", + "gesture", + "hand", + "hands", + "hit", + "indicator", + "interaction", + "line", + "minimal", + "mobile", + "mobile gesture", + "motion", + "move up", + "navigation", + "outline", + "pointer", + "prompt", + "scroll up", + "simple", + "strike", + "swing", + "swipe up", + "swpie", + "take", + "touch", + "touch screen", + "up", + "upward" + ], + "popularity": 3120 + }, + "SWIPE_UP_ALT": { + "tags": [ + "action", + "alt", + "alternative", + "alternative swipe", + "arrow", + "arrow up", + "arrows", + "control", + "direction", + "disable", + "enable", + "finger", + "gesture", + "hands", + "hit", + "indicator", + "interactive", + "interface", + "mobile", + "movement", + "navigation", + "pointer", + "screen", + "scroll", + "scroll up", + "strike", + "swing", + "swipe", + "swipe up", + "swpie", + "take", + "touch", + "touch screen", + "ui action", + "up", + "upward", + "user input", + "variant" + ], + "popularity": 1363 + }, + "SWIPE_VERTICAL": { + "tags": [ + "action", + "arrows", + "control", + "digital", + "direction", + "down", + "drag", + "drag down", + "drag up", + "finger", + "flick", + "gesture", + "hand", + "hands", + "hit", + "input", + "interaction", + "mobile", + "move", + "movement", + "navigation", + "pointer", + "scroll", + "scroll down", + "scroll up", + "strike", + "swing", + "swipe", + "swpie", + "take", + "technology", + "touch", + "touch screen", + "ui gesture", + "up", + "up/down", + "vertical swipe", + "verticle" + ], + "popularity": 2215 + }, + "SWITCH_ACCESS_SHORTCUT": { + "tags": [ + "access", + "access point", + "accessibility", + "activation", + "alternative input", + "arrow", + "arrows", + "assistance", + "assistive technology", + "button", + "connected device", + "connection", + "control", + "device", + "direction", + "disability", + "electronic", + "enabling", + "external device", + "input method", + "interface control", + "link", + "management", + "navigation", + "new", + "north", + "on/off", + "peripheral", + "remote control", + "setting", + "shortcut", + "switch", + "symbol", + "technology", + "toggle", + "up", + "wired", + "wireless" + ], + "popularity": 5585 + }, + "SWITCH_ACCESS_SHORTCUT_ADD": { + "tags": [ + "+", + "access", + "accessibility", + "add", + "arrow", + "arrows", + "button", + "control", + "cursor", + "direction", + "focus", + "highlight", + "input", + "interactive", + "mechanism", + "navigation", + "new", + "north", + "on/off", + "option", + "plus", + "pointer", + "selection", + "setting", + "shortcut", + "switch", + "symbol", + "toggle", + "up" + ], + "popularity": 3992 + }, + "SWITCH_ACCOUNT": { + "tags": [ + "access", + "access control", + "account", + "account management", + "accounts", + "arrows", + "bidirectional", + "change profile", + "change user", + "choices", + "circle", + "exchange", + "face", + "head", + "human", + "identity", + "login", + "logout", + "manage profiles", + "move", + "multiple", + "multiple accounts", + "options", + "people", + "person", + "personalize", + "profile", + "select account", + "shift", + "shoulders", + "silhouette", + "social", + "stack", + "switch", + "switch account", + "transfer", + "two arrows", + "user", + "user profile", + "user switching", + "users" + ], + "popularity": 9507 + }, + "SWITCH_CAMERA": { + "tags": [ + "app", + "application", + "arrow", + "arrows", + "back camera", + "camera", + "camera direction", + "capture", + "change camera", + "communication", + "content", + "creation", + "device", + "flip camera", + "front camera", + "media", + "mobile", + "photo", + "photography", + "picture", + "rear camera", + "record", + "rectangle", + "rotate camera", + "selfie camera", + "switch", + "switch camera", + "toggle camera", + "two arrows", + "video", + "video camera", + "videography" + ], + "popularity": 1746 + }, + "SWITCH_LEFT": { + "tags": [ + "activation", + "arrows", + "button", + "circle", + "control", + "deactivation", + "device control", + "directional", + "directional switch", + "element", + "feature", + "handle", + "horizontal", + "indicator", + "interaction", + "left", + "navigation", + "on/off", + "option", + "oval", + "preference", + "preference switch", + "selection", + "setting", + "slider", + "state", + "state control", + "switch", + "switch left", + "toggle", + "toggle left", + "track", + "ui element" + ], + "popularity": 5337 + }, + "SWITCH_RIGHT": { + "tags": [ + "active", + "arrow", + "arrows", + "button", + "configuration", + "control", + "direction", + "directional", + "inactive", + "indicator", + "move", + "navigation", + "off", + "on", + "option", + "position", + "preference", + "right", + "selection", + "setting", + "shift", + "slider", + "state", + "switch", + "toggle" + ], + "popularity": 4127 + }, + "SWITCH_VIDEO": { + "tags": [ + "arrow", + "arrows", + "back camera", + "broadcasting", + "call", + "camera", + "camera direction", + "camera flip", + "camera rotation", + "camera switch", + "camera toggle", + "camera view", + "change camera", + "conference", + "filming", + "flip camera", + "front camera", + "photography", + "record", + "reverse camera", + "rotate camera", + "selfie camera", + "streaming", + "switch", + "switch camera", + "switch video", + "toggle camera", + "video", + "video call", + "video camera", + "video switch", + "videos", + "view camera" + ], + "popularity": 1706 + }, + "SYNAGOGUE": { + "tags": [ + "architecture", + "building", + "church", + "city", + "community", + "dome", + "faith", + "hebrew", + "holy place", + "ideology", + "israel", + "jerusalem", + "jew", + "jewish", + "judaism", + "landmark", + "monument", + "prayer", + "religion", + "religious building", + "shul", + "spiritual", + "star", + "star of david", + "structure", + "synagogue", + "temple", + "tourism", + "travel", + "urban", + "worship" + ], + "popularity": 1066 + }, + "SYNC": { + "tags": [ + "360", + "align", + "around", + "arrow", + "arrows", + "circular", + "cloud", + "connection", + "consistency", + "continuous", + "current", + "cycle", + "data", + "direction", + "exchange", + "inprogress", + "latest", + "load", + "loading refresh", + "loop", + "process", + "recurring", + "refresh", + "reload", + "renew", + "reorder", + "retrieve", + "rotate", + "rotation", + "sync", + "synchronization", + "synchronize", + "transfer", + "turn", + "update" + ], + "popularity": 46882 + }, + "SYNC_ALT": { + "tags": [ + "alt", + "arrow", + "arrows", + "back and forth", + "change", + "circle", + "circular", + "connecting", + "connection", + "cycle", + "data", + "direction", + "double arrow", + "exchange", + "flow", + "horizontal", + "interaction", + "internet", + "link", + "loop", + "oval", + "process", + "reciprocal", + "refresh", + "relationship", + "round", + "swap", + "switch", + "sync", + "synchronize", + "technology", + "transfer", + "two way", + "up", + "update", + "wifi" + ], + "popularity": 34854 + }, + "SYNC_DISABLED": { + "tags": [ + "360", + "around", + "arrow", + "arrows", + "broken arrow", + "broken circle", + "cancel sync", + "circle", + "circular arrows", + "data transfer disabled", + "diagonal line", + "direction", + "disabled", + "disconnect", + "enabled", + "inactive", + "inprogress", + "line", + "load", + "loading refresh", + "no connection", + "no sync", + "not syncing", + "off", + "offline", + "on", + "pause sync", + "refresh disabled", + "renew", + "rotate", + "slash", + "stop sync", + "sync", + "sync disabled", + "synchronization off", + "turn", + "two arrows", + "two lines", + "unavailable", + "update disabled" + ], + "popularity": 3493 + }, + "SYNC_LOCK": { + "tags": [ + "access", + "access control", + "around", + "arrow", + "arrows", + "circle", + "circular arrows", + "connection", + "data", + "encryption", + "encryption lock", + "key", + "lock", + "locked", + "loop", + "network", + "password", + "privacy", + "private", + "protected", + "protection", + "refresh", + "renew", + "restricted", + "rotate", + "safety", + "secure", + "security", + "sync", + "sync lock", + "synchronize", + "system", + "turn", + "update" + ], + "popularity": 2023 + }, + "SYNC_PROBLEM": { + "tags": [ + "!", + "360", + "alert", + "around", + "arrow", + "arrows", + "attention", + "caution", + "circular arrows", + "cloud", + "cloud sync", + "connectivity issue", + "danger", + "data error", + "data issue", + "direction", + "error", + "exclamation", + "exclamation point", + "failed", + "failure", + "important", + "inprogress", + "issue", + "load", + "loading refresh", + "mark", + "network issue", + "notification", + "problem", + "refresh arrows", + "renew", + "retry", + "rotate", + "symbol", + "sync", + "sync error", + "sync problem", + "synchronization error", + "synchronization problem", + "transfer error", + "triangle", + "turn", + "update error", + "warning" + ], + "popularity": 9069 + }, + "SYSTEM_SECURITY_UPDATE": { + "tags": [ + "android", + "app", + "app install", + "app promo", + "arrow", + "cell", + "device", + "down", + "down arrow", + "download", + "download app", + "hardware", + "install", + "install app", + "install mobile", + "ios", + "marketing", + "mobile", + "mobile download", + "os", + "phone", + "phone download", + "promotion", + "security", + "security update", + "software", + "software update", + "system", + "system update", + "system upgrade", + "tablet", + "update", + "upgrade" + ], + "popularity": 1558 + }, + "SYSTEM_SECURITY_UPDATE_GOOD": { + "tags": [ + "android", + "approve", + "approved", + "cell", + "check", + "checkmark", + "complete", + "device", + "display", + "done", + "friendly", + "good", + "hardware", + "icon", + "ios", + "mark", + "mobile", + "mobile check", + "mobile phone", + "ok", + "os", + "phone", + "protection", + "safe", + "screen", + "secure", + "security", + "security update", + "select", + "smartphone", + "success", + "symbol", + "system", + "system update", + "tablet", + "technology", + "tick", + "ui", + "update", + "validate", + "validated", + "verified", + "yes" + ], + "popularity": 4092 + }, + "SYSTEM_SECURITY_UPDATE_WARNING": { + "tags": [ + "!", + "alert", + "android", + "attention", + "bug", + "caution", + "cell", + "critical", + "danger", + "device", + "error", + "exclamation", + "fix", + "hardware", + "hazard", + "important", + "ios", + "issue", + "mark", + "mobile", + "notification", + "os", + "patch", + "phone", + "portrait", + "precaution", + "problem", + "protection", + "screen", + "secure", + "security", + "shield", + "symbol", + "system", + "tablet", + "threat", + "triangle", + "update", + "vulnerability", + "warning" + ], + "popularity": 1586 + }, + "SYSTEM_UPDATE": { + "tags": [ + "android", + "app", + "app install", + "app promo", + "arrow", + "arrows", + "cell", + "device", + "direction", + "down", + "down arrow", + "download", + "download app", + "hardware", + "install", + "install app", + "install mobile", + "ios", + "marketing", + "mobile", + "mobile download", + "os", + "phone", + "phone download", + "promotion", + "security", + "security update", + "software", + "software update", + "system", + "system update", + "system upgrade", + "tablet", + "update", + "upgrade" + ], + "popularity": 4790 + }, + "SYSTEM_UPDATE_ALT": { + "tags": [ + "application", + "arrow", + "backup", + "cloud", + "computer", + "data transfer", + "device", + "down", + "down arrow", + "download", + "export", + "file transfer", + "installation", + "internet", + "loading", + "maintenance", + "monitor", + "network", + "progress", + "refresh", + "restore", + "screen", + "security", + "server", + "software update", + "sync", + "synchronize", + "system", + "system update", + "technology", + "update", + "upgrade", + "upload" + ], + "popularity": 11444 + }, + "TAB": { + "tags": [ + "add button", + "add document", + "add tab", + "add window", + "application management", + "application window", + "browser", + "browser control", + "browser tab", + "browser window", + "computer", + "create new", + "desktop", + "document", + "document tab", + "documents", + "file tab", + "folder", + "internet", + "internet browser", + "layering windows", + "multiple windows", + "new document", + "new tab", + "new window", + "plus button", + "program window", + "project tab", + "software window", + "stacking windows", + "tab", + "tabs", + "web", + "web browser", + "website", + "window", + "window management", + "windows" + ], + "popularity": 7487 + }, + "TAB_UNSELECTED": { + "tags": [ + "application", + "background", + "blank", + "border", + "browser", + "computer", + "content", + "dash", + "dashed", + "document", + "documents", + "empty", + "folder", + "inactive", + "inactive tab", + "internet", + "layer", + "multiple", + "navigation", + "organization", + "outline", + "overlapping", + "page", + "placeholder", + "rectangle", + "section", + "shape", + "stack", + "stacking", + "switch", + "tab", + "tabs", + "toggle", + "unselected", + "unselected tab", + "view", + "web", + "website", + "window", + "windows" + ], + "popularity": 2637 + }, + "TABLE_BAR": { + "tags": [ + "analysis", + "analytics", + "bar", + "business", + "cafe", + "chart", + "columns", + "data", + "diagram", + "figures", + "finance", + "graph", + "grid", + "infographic", + "information", + "lines", + "metrics", + "numbers", + "performance", + "planning", + "presentation", + "report", + "research", + "results", + "round", + "rows", + "spreadsheet", + "statistics", + "table", + "trend", + "visualization" + ], + "popularity": 3154 + }, + "TABLE_CHART": { + "tags": [ + "analytics", + "arrange", + "bar", + "bars", + "business", + "chart", + "columns", + "data", + "diagram", + "display", + "document", + "finance", + "graph", + "grid", + "infographic grid", + "information", + "lines", + "matrix", + "measure", + "metrics", + "numbers", + "organize", + "outline", + "plot", + "presentation", + "rectangle", + "report", + "rows", + "shape", + "spreadsheet", + "squares", + "statistics", + "table", + "tracking", + "view" + ], + "popularity": 21911 + }, + "TABLE_RESTAURANT": { + "tags": [ + "bar", + "bistro", + "bistro table", + "book table", + "booking", + "cafe", + "cafe table", + "dining", + "dining experience", + "dining room", + "dining table", + "dinner", + "eat", + "eatery", + "eating", + "food", + "food and drink", + "food service", + "furniture", + "lunch", + "meal", + "place setting", + "pub", + "reservation", + "reserve", + "restaurant", + "restaurant table", + "seat", + "seating", + "serve", + "table" + ], + "popularity": 4442 + }, + "TABLE_ROWS": { + "tags": [ + "array", + "background", + "chart", + "data", + "database", + "document", + "entries", + "file", + "filter", + "graph", + "grid", + "horizontal lines", + "information", + "layout", + "lines", + "list", + "organize", + "parallel lines", + "presentation", + "records", + "report", + "rows", + "section", + "sort", + "spreadsheet", + "stacked", + "structure", + "table", + "view" + ], + "popularity": 15094 + }, + "TABLE_VIEW": { + "tags": [ + "arrangement", + "cell", + "chart", + "columns", + "data", + "data visualization", + "display", + "format", + "geometry", + "grid", + "group", + "information", + "layout", + "lines", + "list", + "matrix", + "multiple", + "order", + "organize", + "organized data", + "presentation", + "rectangular", + "report", + "rows", + "segmented", + "spreadsheet", + "square", + "structure", + "table", + "tabular", + "tabular data", + "view" + ], + "popularity": 21356 + }, + "TABLET": { + "tags": [ + "android", + "border", + "communication", + "computer", + "device", + "digital", + "display", + "drawing", + "education", + "electronic", + "entertainment", + "frame", + "gadget", + "handheld", + "hardware", + "ios", + "ipad", + "media", + "mobile", + "os", + "portable", + "reading", + "rectangle", + "screen", + "square", + "tablet", + "technology", + "web", + "work" + ], + "popularity": 2723 + }, + "TABLET_ANDROID": { + "tags": [ + "android", + "app", + "application", + "browsing", + "communication", + "computing", + "connectivity", + "device", + "digital", + "display", + "electronic", + "gadget", + "google", + "handheld", + "hardware", + "icon", + "ios", + "ipad", + "lenovo", + "mobile", + "nexus", + "operating system", + "os", + "platform", + "portable", + "rectangle", + "samsung", + "screen", + "symbol", + "tablet", + "technology", + "web" + ], + "popularity": 3613 + }, + "TABLET_MAC": { + "tags": [ + "android", + "apple", + "computer", + "device", + "digital", + "display", + "electronic", + "gadget", + "hardware", + "horizontal", + "ios", + "ipad", + "landscape", + "macintosh", + "mobile", + "os", + "pad", + "portable", + "rectangle", + "rounded edges", + "screen", + "square corners", + "tablet", + "tablet mac", + "technology", + "web" + ], + "popularity": 6754 + }, + "TAG": { + "tags": [ + "app", + "banner", + "bookmark", + "button", + "categorize", + "classification", + "corner", + "diagonal", + "document", + "favorite", + "file", + "fold", + "folded corner", + "hash", + "hashtag", + "key", + "label", + "marker", + "media", + "note", + "numbers", + "organise", + "page", + "paper", + "pound", + "ribbon", + "save", + "shape", + "slant", + "social", + "symbol", + "tag", + "trend", + "triangle", + "ui", + "ui element", + "web" + ], + "popularity": 20693 + }, + "TAG_FACES": { + "tags": [ + "add", + "character", + "chat", + "cheerful", + "circle", + "communication", + "emoji", + "emoticon", + "emotion", + "expression", + "face", + "faces", + "feeling", + "grin", + "happy", + "insert", + "joy", + "message", + "mood", + "outline", + "reaction", + "round", + "satisfied", + "select", + "smile", + "smiley", + "symbol", + "tag", + "text" + ], + "popularity": 5846 + }, + "TAKEOUT_DINING": { + "tags": [ + "box", + "catering", + "container", + "cutlery", + "delivery", + "dining", + "dining out", + "eating", + "food", + "food box", + "food container", + "food delivery", + "fork", + "knife", + "meal", + "meal box", + "meal container", + "meal delivery", + "order", + "rectangle", + "restaurant", + "restaurant delivery", + "restaurant take out", + "takeaway", + "takeout", + "takeout box", + "to go", + "utensil" + ], + "popularity": 5743 + }, + "TAP_AND_PLAY": { + "tags": [ + "android", + "broadcast", + "cast", + "casting", + "cell", + "connect", + "connection", + "device", + "display", + "entertainment", + "hardware", + "internet", + "ios", + "media", + "mirror", + "mirroring", + "mobile", + "network", + "os wifi", + "phone", + "play", + "pointer", + "rectangle", + "screen", + "screen mirroring", + "share", + "signal", + "stream", + "streaming", + "tablet", + "tap", + "technology", + "television", + "to", + "triangle", + "tv", + "video", + "waves", + "wifi", + "wireless" + ], + "popularity": 3262 + }, + "TAPAS": { + "tags": [ + "app logo", + "appetizer", + "book", + "brand", + "brunch", + "cartoon", + "comic", + "content", + "creative", + "digital comics", + "digital content", + "dinner", + "entertainment", + "episode", + "food", + "graphic novel", + "illustration", + "literature", + "lunch", + "media", + "mobile app", + "online reading", + "open book", + "platform", + "publication", + "publisher", + "reader", + "reading", + "restaurant", + "series", + "snack", + "story", + "tapas", + "visual story", + "web app", + "webtoon" + ], + "popularity": 2630 + }, + "TASK": { + "tags": [ + "accepted", + "agenda", + "approve", + "assignment", + "box", + "check", + "check box", + "checklist", + "checkmark", + "complete", + "confirmed", + "data", + "doc", + "document", + "done", + "drive", + "file", + "folder", + "folders", + "list", + "management", + "mark", + "memo", + "note", + "notification", + "ok", + "organize", + "page", + "paper", + "plan", + "productivity", + "progress", + "project", + "reminder", + "schedule", + "select", + "sheet", + "slide", + "square", + "task", + "tick", + "to do", + "validate", + "verified", + "workflow", + "writing", + "yes" + ], + "popularity": 45595 + }, + "TASK_ALT": { + "tags": [ + "approval", + "approve", + "check", + "checklist", + "checkmark", + "circle", + "complete", + "completed", + "correct", + "done", + "finish", + "mark", + "ok", + "ring", + "select", + "selected", + "status", + "success", + "task", + "tick", + "todo", + "valid", + "validate", + "validation", + "verification", + "verified", + "verify", + "yes" + ], + "popularity": 114897 + }, + "TAXI_ALERT": { + "tags": [ + "!", + "alarm", + "alert", + "attention", + "automobile", + "cab", + "car", + "cars", + "caution", + "danger", + "direction", + "driving", + "error", + "exclamation", + "exclamation mark", + "important", + "issue", + "lyft", + "maps", + "mark", + "message", + "notice", + "notification", + "problem", + "public", + "public transport", + "ride", + "road", + "service", + "signal", + "symbol", + "taxi", + "traffic", + "transport", + "transportation", + "travel", + "triangle", + "uber", + "vehicle", + "warning", + "yellow" + ], + "popularity": 3295 + }, + "TEMPLE_BUDDHIST": { + "tags": [ + "architecture", + "asia", + "asian", + "buddha", + "buddhism", + "buddhist", + "building", + "cultural", + "eastern", + "historical", + "ideology", + "landmark", + "location", + "monastery", + "monument", + "pagoda", + "place", + "prayer", + "religion", + "sanctuary", + "shrine", + "spiritual", + "structure", + "temple", + "tourism", + "traditional", + "travel", + "worship" + ], + "popularity": 1289 + }, + "TEMPLE_HINDU": { + "tags": [ + "ancient", + "architecture", + "asian", + "building", + "culture", + "destination", + "graphic", + "hindu", + "hinduism", + "hindus", + "historical site", + "icon", + "ideology", + "illustration", + "indian", + "landmark", + "mandir", + "monument", + "outline", + "pilgrimage", + "place of worship", + "religion", + "religious building", + "sacred", + "shape", + "spiritual", + "spirituality", + "structure", + "symbol", + "temple", + "tourism", + "traditional", + "travel", + "worship" + ], + "popularity": 1084 + }, + "TERMINAL": { + "tags": [ + "administration", + "angle brackets", + "application", + "code", + "coding", + "command line", + "command prompt", + "computer", + "computing", + "console", + "debugger", + "developer", + "developer tools", + "emulator", + "execute", + "input field", + "it", + "program", + "programming", + "prompt", + "rectangle", + "run code", + "script", + "software", + "system", + "tech", + "technology", + "terminal", + "text editor", + "text input", + "window" + ], + "popularity": 9071 + }, + "TERRAIN": { + "tags": [ + "chart", + "contour", + "data", + "diagram", + "elevation", + "environment", + "geography", + "graphic", + "hill", + "hills", + "image", + "land", + "landscape", + "location", + "map", + "mountain", + "mountains", + "natural", + "nature", + "outdoor", + "peak", + "photo", + "photography", + "picture", + "region", + "scenery", + "terrain", + "travel", + "view" + ], + "popularity": 6270 + }, + "TEXT_DECREASE": { + "tags": [ + "-", + "a", + "accessibility", + "alphabet", + "character", + "decrease", + "decrease text", + "diminish", + "font", + "font size", + "lessen", + "letter", + "letters", + "minus", + "reading", + "reduce", + "reduce text", + "remove", + "resize", + "scale", + "scale text", + "shrink", + "shrink text", + "size", + "subtract", + "subtraction", + "symbol", + "text", + "text size", + "text smaller", + "type", + "typography", + "zoom out text" + ], + "popularity": 1778 + }, + "TEXT_FIELDS": { + "tags": [ + "add", + "add text", + "alphabet", + "blank", + "blinking cursor", + "box", + "character", + "compose", + "control", + "cursor", + "data entry", + "document", + "edit field", + "edit text", + "enter text", + "entry", + "field", + "fields", + "font", + "form", + "input", + "insert", + "interface", + "keyboard", + "letters", + "lines", + "point", + "space", + "symbol", + "t", + "text", + "text box", + "text fields", + "type", + "typing", + "underscore", + "user input", + "writer", + "writing" + ], + "popularity": 15129 + }, + "TEXT_FORMAT": { + "tags": [ + "align", + "alignment", + "alphabet", + "article", + "character", + "characters", + "content", + "document", + "edit", + "editing", + "file", + "font", + "format", + "formatting", + "letter", + "letters", + "lines", + "paragraph", + "plain text", + "rich text", + "square a", + "style", + "symbol", + "text", + "text editor", + "type", + "typeface", + "typography", + "word processor", + "writing", + "writing tools" + ], + "popularity": 7145 + }, + "TEXT_INCREASE": { + "tags": [ + "+", + "accessibility", + "add", + "adjust", + "alphabet", + "character", + "document", + "enlarge", + "expand", + "font", + "grow", + "increase", + "letter", + "letters", + "new", + "page", + "plus", + "readability", + "resize", + "scale", + "settings", + "size", + "symbol", + "text", + "type", + "typography", + "view", + "viewing", + "zoom" + ], + "popularity": 2899 + }, + "TEXT_ROTATE_UP": { + "tags": [ + "a", + "adjustment", + "alphabet", + "arrange", + "arrow", + "character", + "characters", + "clockwise", + "content", + "control", + "curve", + "direction", + "document", + "edit", + "field", + "flow", + "font", + "format", + "glyphs", + "heading", + "layout", + "letters", + "move", + "orientation", + "paragraph", + "position", + "rotate", + "spin", + "symbol", + "text", + "transform", + "turning", + "type", + "typography", + "up", + "word", + "writing" + ], + "popularity": 1701 + }, + "TEXT_ROTATE_VERTICAL": { + "tags": [ + "a", + "alignment", + "alphabet", + "arrange", + "arrow", + "arrows", + "change direction", + "change orientation", + "character", + "direction", + "document", + "double arrow", + "down", + "down arrow", + "edit text", + "editor", + "field", + "flip", + "font", + "formatting", + "glyph", + "layout", + "letters", + "lines", + "move", + "orientation", + "rotate", + "symbol", + "text", + "transform", + "two arrows", + "type", + "typography", + "up arrow", + "vertical", + "word processing", + "writing" + ], + "popularity": 2466 + }, + "TEXT_ROTATION_ANGLEDOWN": { + "tags": [ + "a", + "adjust text", + "align", + "alignment", + "alphabet", + "angle", + "angledown", + "arrow", + "arrow down", + "character", + "diagonal", + "document", + "document editing", + "down arrow", + "down indicator", + "edit text", + "field", + "file", + "font", + "letters", + "manipulate text", + "move", + "orientation", + "page", + "rotate", + "rotation", + "symbol", + "text", + "text control", + "text direction", + "text layout", + "text orientation", + "type", + "typography", + "word processing", + "words", + "writing" + ], + "popularity": 1685 + }, + "TEXT_ROTATION_ANGLEUP": { + "tags": [ + "a", + "adjustment", + "alphabet", + "angle", + "angleup", + "arrange", + "arrow", + "character", + "creative", + "design", + "direction", + "document", + "edit", + "field", + "font", + "formatting", + "layout", + "letter", + "letters", + "modify", + "move", + "orientation", + "rotate", + "rotation", + "skew", + "symbol", + "text", + "tilt", + "transform", + "type", + "typography", + "up", + "upward", + "writing" + ], + "popularity": 1652 + }, + "TEXT_ROTATION_DOWN": { + "tags": [ + "a", + "adjust", + "alphabet", + "arrow", + "character", + "direction", + "document", + "dow", + "down", + "edit", + "field", + "file", + "font", + "format", + "horizontal", + "layout", + "letter", + "letters", + "modify", + "move", + "orientation", + "point", + "rotate", + "rotation", + "symbol", + "text", + "transform", + "type", + "typography", + "vertical", + "word" + ], + "popularity": 1639 + }, + "TEXT_ROTATION_NONE": { + "tags": [ + "a", + "alignment", + "alphabet", + "arrow", + "box", + "character", + "content", + "document", + "field", + "file", + "font", + "horizontal", + "layout", + "letters", + "move", + "none", + "orientation", + "page", + "paper", + "rectangle", + "rotate", + "rotation", + "sheet", + "square", + "straight", + "symbol", + "text", + "type", + "upright", + "vertical" + ], + "popularity": 2335 + }, + "TEXT_SNIPPET": { + "tags": [ + "article", + "character", + "communication", + "content", + "data", + "doc", + "document", + "excerpt", + "extract", + "file", + "fragment", + "information", + "language", + "letter", + "literature", + "note", + "notes", + "partial", + "piece", + "portion", + "preview", + "quotation", + "quote", + "reading", + "report", + "section", + "segment", + "snippet", + "storage", + "summary", + "text", + "typography", + "words", + "writing" + ], + "popularity": 33166 + }, + "TEXTSMS": { + "tags": [ + "alert", + "app", + "bubble", + "chat", + "comment", + "communicate", + "communication", + "conversation", + "dialog", + "dialogue", + "dots", + "feedback", + "inbox", + "lines", + "mail", + "message", + "message bubble", + "messaging", + "mobile", + "new", + "notification", + "phone", + "pointer", + "receive", + "rectangle", + "send", + "sms", + "social", + "speech", + "speech bubble", + "square", + "talk", + "text", + "texting", + "textsms" + ], + "popularity": 32031 + }, + "TEXTURE": { + "tags": [ + "abstract", + "appearance", + "background", + "bumpy", + "crosshatch", + "detail", + "diagonal", + "effect", + "fill", + "filter", + "finish", + "grain", + "grid", + "grit", + "horizontal lines", + "layer", + "lines", + "material", + "matte", + "overlay", + "parallel lines", + "pattern", + "rough", + "shiny", + "smooth", + "stripes", + "style", + "surface", + "surface finish", + "texture", + "vertical lines", + "visual" + ], + "popularity": 4053 + }, + "THEATER_COMEDY": { + "tags": [ + "acting", + "art", + "broadway", + "comedian", + "comedy", + "culture", + "drama", + "emotion", + "entertainment", + "event", + "face", + "film", + "frown", + "graphic", + "happy", + "icon", + "illustration", + "joy", + "mask", + "masks", + "movie", + "musical", + "performance", + "performing arts", + "places", + "play", + "representation", + "sad", + "show", + "smile", + "stage", + "standup", + "symbol", + "theater", + "theatre mask", + "tour", + "tragedy", + "watch" + ], + "popularity": 7359 + }, + "THEATERS": { + "tags": [ + "box office", + "cinema", + "clip", + "documentary", + "entertainment", + "feature", + "film", + "independent", + "local", + "media", + "movie", + "movies", + "perforation", + "performance", + "play", + "playback", + "production", + "projector", + "rectangle", + "reel", + "rounded corners", + "screening", + "short", + "show", + "showtimes", + "square", + "stream", + "theater", + "theaters", + "video", + "view", + "watch" + ], + "popularity": 12220 + }, + "THERMOSTAT": { + "tags": [ + "adjustment", + "automation", + "climate", + "control", + "cool", + "cooling", + "device", + "energy", + "environmental control", + "forecast", + "gauge", + "heat", + "heating", + "home automation", + "hvac", + "measure", + "meter", + "monitor", + "regulate", + "setting", + "smart home", + "temperature", + "temperature setting", + "thermometer", + "thermostat", + "utility", + "weather" + ], + "popularity": 23676 + }, + "THERMOSTAT_AUTO": { + "tags": [ + "a", + "adjustment", + "appliance", + "auto", + "automatic", + "automation", + "celsius", + "circle", + "climate", + "comfort", + "control", + "cooling", + "device", + "dial", + "environment", + "fahrenheit", + "gauge", + "heating", + "home automation", + "hvac", + "indicator", + "meter", + "mode", + "pointer", + "sensor", + "settings", + "smart home", + "system", + "temp", + "temperature", + "thermometer", + "thermostat", + "weather" + ], + "popularity": 2911 + }, + "THUMB_DOWN": { + "tags": [ + "ate", + "cancel", + "disagree", + "disapproval", + "dislike", + "down", + "favorite", + "feedback", + "fingers", + "gesture", + "hand", + "hand gesture", + "hands", + "hate", + "like", + "negative", + "negative feedback", + "no", + "opposite", + "rank", + "ranking", + "rating", + "refusal", + "reject", + "rejection", + "thumb", + "thumbs down", + "unlike", + "unlike button", + "vote", + "vote down" + ], + "popularity": 26226 + }, + "THUMB_DOWN_ALT": { + "tags": [ + "bad", + "cancel", + "decline", + "disagree", + "disapproval", + "disapprove", + "dislike", + "down", + "feedback", + "gesture", + "hand", + "hand gesture", + "hate", + "negative", + "negative feedback", + "no", + "opposite", + "rating", + "refusal", + "reject", + "rejection", + "social", + "thumb", + "thumbs down", + "unlike", + "unlike button", + "veto", + "vote", + "vote down" + ], + "popularity": 11923 + }, + "THUMB_DOWN_OFF_ALT": { + "tags": [ + "cancel", + "disabled", + "disagree", + "disapproval", + "dislike", + "down", + "enabled", + "favorite", + "feedback", + "filled", + "fingers", + "gesture", + "hand", + "hand gesture", + "hands", + "hate", + "like", + "negative", + "negative feedback", + "no", + "off", + "offline", + "on", + "opposite", + "rank", + "ranking", + "rate", + "rating", + "refusal", + "reject", + "rejection", + "slash", + "thumb", + "thumbs down", + "unlike", + "unlike button", + "vote", + "vote down" + ], + "popularity": 12190 + }, + "THUMB_UP": { + "tags": [ + "acknowledgement", + "agree", + "approve", + "button", + "choice", + "confirmation", + "content interaction", + "control", + "endorsement", + "excellent", + "favorite", + "feedback", + "fingers", + "gesture", + "good", + "hand", + "hand gesture", + "hand sign", + "hands", + "indicator", + "like", + "option", + "positive", + "preference", + "rank", + "ranking", + "rate", + "rating", + "reaction", + "recommend", + "selection", + "share", + "social media", + "thumb", + "thumbs up", + "up", + "vote", + "yes" + ], + "popularity": 150661 + }, + "THUMB_UP_ALT": { + "tags": [ + "acknowledgement", + "agree", + "agreed", + "approve", + "approved", + "button", + "choice", + "confirm", + "confirmation", + "content interaction", + "control", + "correct", + "endorsement", + "excellent", + "favorite", + "feedback", + "good", + "hand gesture", + "hand sign", + "happy", + "indicator", + "like", + "okay", + "option", + "positive", + "preference", + "rating", + "reaction", + "recommend", + "satisfaction", + "selection", + "share", + "social", + "social media", + "thumb", + "thumbs up", + "up", + "vote", + "yes" + ], + "popularity": 37219 + }, + "THUMB_UP_OFF_ALT": { + "tags": [ + "acknowledgement", + "agree", + "alt", + "approve", + "button", + "choice", + "confirmation", + "content interaction", + "control", + "disabled", + "enabled", + "endorsement", + "excellent", + "favorite", + "feedback", + "fingers", + "gesture", + "good", + "hand", + "hand gesture", + "hand sign", + "hands", + "indicator", + "like", + "off", + "offline", + "on", + "option", + "positive", + "preference", + "rank", + "ranking", + "rate", + "rating", + "reaction", + "recommend", + "selection", + "share", + "slash", + "social media", + "thumb", + "thumbs up", + "up", + "vote", + "yes" + ], + "popularity": 42752 + }, + "THUMBS_UP_DOWN": { + "tags": [ + "agree", + "approval", + "comparison", + "contrast", + "decision", + "direction", + "disagree", + "dislike", + "down", + "favorite", + "feedback", + "finger", + "fingers", + "gesture", + "hand gesture", + "hand signal", + "hands", + "human body", + "like", + "negative", + "opinion", + "positive", + "rate", + "rating", + "rejection", + "review", + "social media", + "survey", + "thumb", + "thumbs", + "thumbs down", + "thumbs up", + "up", + "vote" + ], + "popularity": 12390 + }, + "THUNDERSTORM": { + "tags": [ + "alert", + "atmosphere", + "bad weather", + "bolt", + "climate", + "cloud", + "cloudy", + "danger", + "electricity", + "forecast", + "lightning", + "lightning bolt", + "meteorological event", + "meteorology", + "natural phenomenon", + "nature", + "precipitation", + "rain", + "raincloud", + "rainfall", + "rainstorm", + "severe", + "sky", + "storm", + "thunder", + "thunderstorm", + "warning", + "weather", + "weather condition" + ], + "popularity": 3414 + }, + "TIME_TO_LEAVE": { + "tags": [ + "auto", + "automobile", + "automotive", + "car", + "car symbol", + "cars", + "destination", + "direction", + "directions", + "drive", + "drive time", + "driving", + "estimate", + "estimated time", + "eta", + "journey", + "maps", + "mobility", + "navigate", + "navigation", + "passenger vehicle", + "public", + "road", + "route", + "sedan", + "time", + "transport", + "transport symbol", + "transportation", + "travel", + "travel time", + "trip", + "vehicle", + "vehicle icon" + ], + "popularity": 8421 + }, + "TIMELAPSE": { + "tags": [ + "accelerate", + "adjustment", + "arrow", + "camera", + "capture", + "circle", + "clock", + "clockwise", + "control", + "duration", + "effect", + "fast", + "film", + "filmography", + "loop", + "media", + "motion", + "photo", + "photography", + "playback", + "recording", + "setting", + "speed", + "speed up", + "time", + "timelapse", + "timer", + "video", + "videography" + ], + "popularity": 11029 + }, + "TIMELINE": { + "tags": [ + "chart", + "chronological", + "data", + "dates", + "diagram", + "dots", + "duration", + "events", + "flow", + "future", + "history", + "journey", + "line", + "milestones", + "movement", + "past", + "path", + "period", + "point", + "points", + "points in time", + "progress", + "progression", + "roadmap", + "schedule", + "sequence", + "stages", + "steps", + "timeline", + "tracking", + "trending", + "visual representation", + "zigzag" + ], + "popularity": 35064 + }, + "TIMER": { + "tags": [ + "alarm", + "alert", + "appointment", + "bell", + "chronometer", + "circular", + "clock", + "countdown", + "deadline", + "deadline management", + "deadline tracking", + "disabled", + "duration", + "enabled", + "event", + "event tracking", + "hand", + "hour hand", + "measurement", + "minute hand", + "notification", + "pointer", + "reminder", + "ringing", + "round", + "running time", + "schedule", + "second hand", + "speed", + "stopwatch", + "time", + "time limit", + "timekeeping", + "timer", + "watch" + ], + "popularity": 49214 + }, + "TIMER_10": { + "tags": [ + "10", + "alarm", + "alert", + "bell", + "camera", + "circle", + "circular", + "clock", + "control", + "countdown", + "delay", + "dial", + "digits", + "disabled", + "duration", + "enabled", + "hour", + "measurement", + "media control", + "minute", + "notification", + "number", + "number 10", + "numbers", + "photo", + "recording", + "reminder", + "schedule", + "second", + "seconds", + "setting", + "stopwatch", + "ten", + "time", + "timer", + "video", + "watch" + ], + "popularity": 1302 + }, + "TIMER_10_SELECT": { + "tags": [ + "10", + "adjustment", + "alphabet", + "analog", + "camera", + "character", + "circle", + "clock", + "control", + "countdown", + "digit", + "digital", + "duration", + "font", + "letters", + "measure", + "number", + "numbers", + "option", + "outline", + "preference", + "seconds", + "select", + "setting", + "stop", + "symbol", + "ten", + "text", + "time", + "timer", + "type" + ], + "popularity": 1114 + }, + "TIMER_3": { + "tags": [ + "3", + "circle", + "clock", + "control", + "countdown", + "digit", + "digits", + "duration", + "fast", + "interval", + "lapse", + "measure", + "minutes", + "number", + "numbers", + "numeral", + "outline", + "quick", + "record", + "round", + "seconds", + "shape", + "speed", + "start", + "stop", + "stopwatch", + "three", + "time", + "timer", + "track" + ], + "popularity": 1082 + }, + "TIMER_3_SELECT": { + "tags": [ + "3", + "alphabet", + "camera", + "character", + "choose", + "chronometer", + "circle", + "clock", + "control", + "count", + "countdown", + "delay", + "digit", + "duration", + "feature", + "font", + "function", + "interval", + "letters", + "measurement", + "number", + "numbers", + "option", + "radial", + "round", + "seconds", + "select", + "setting", + "stopwatch", + "symbol", + "text", + "three", + "time", + "timer", + "tool", + "type", + "utility" + ], + "popularity": 902 + }, + "TIMER_OFF": { + "tags": [ + "alarm", + "alarm disabled", + "alarm off", + "alert", + "bell", + "cancel", + "chronometer off", + "circle", + "clock", + "clock canceled", + "clock disabled", + "clock off", + "countdown", + "cross out", + "diagonal line", + "disable timer", + "disabled", + "duration", + "enabled", + "measurement", + "no alarm", + "no time clock", + "no timer", + "notification", + "off", + "on", + "remove", + "remove timer", + "rounded shape", + "schedule", + "slash", + "stop", + "stop alarm", + "stop timer", + "stopwatch off", + "time", + "time clock disabled", + "time clock off", + "time off", + "timer", + "timer canceled", + "timer disabled", + "timer off", + "watch", + "x" + ], + "popularity": 3857 + }, + "TIPS_AND_UPDATES": { + "tags": [ + "advice", + "ai", + "alert", + "and", + "announcement", + "artificial", + "automatic", + "automation", + "bright", + "bulb", + "custom", + "electricity", + "energy", + "genai", + "glow", + "guidance", + "guide", + "helpful", + "idea", + "illumination", + "info", + "information", + "innovation", + "inspiration", + "intelligence", + "invention", + "knowledge", + "latest", + "learning", + "light", + "lightbulb", + "magic", + "message", + "new", + "news", + "notification", + "recent", + "smart", + "solution", + "spark", + "sparkle", + "star", + "thought", + "tip", + "tips", + "update", + "updates" + ], + "popularity": 37484 + }, + "TIRE_REPAIR": { + "tags": [ + "alert", + "assistance", + "auto", + "automobile", + "automotive", + "car", + "cars", + "circular", + "fix", + "flat", + "gauge", + "inflate", + "issue", + "maintenance", + "mechanic", + "patch", + "plug", + "pressure", + "problem", + "pump", + "puncture", + "repair", + "roadside", + "round", + "service", + "spare", + "tire", + "tool", + "transportation", + "vehicle", + "warning", + "wheel", + "wrench" + ], + "popularity": 1502 + }, + "TITLE": { + "tags": [ + "action", + "alphabet", + "basic", + "basic minus", + "box", + "button", + "character", + "control", + "decrease box", + "essential", + "font", + "function", + "geometric", + "header", + "less box", + "letters", + "line icon", + "minimal minus", + "minimize box", + "minus square", + "negative box", + "outline", + "remove box", + "shape", + "simple", + "simple minus", + "square", + "subject", + "subtract box", + "symbol", + "t", + "text", + "thin line", + "title", + "type", + "ui control" + ], + "popularity": 14565 + }, + "TOC": { + "tags": [ + "bullet points", + "chapter list", + "chapters", + "content", + "document", + "document navigation", + "document sections", + "file", + "format", + "hierarchy", + "index", + "index list", + "lines", + "list", + "menu", + "navigation", + "options", + "order", + "organize", + "outline", + "overview", + "points", + "reorder", + "section list", + "sections", + "stacked", + "structure", + "structure of a document", + "summary", + "table", + "table of contents", + "text", + "title", + "titles", + "toc" + ], + "popularity": 19288 + }, + "TODAY": { + "tags": [ + "agenda", + "appointment", + "calendar", + "circle", + "circle with dot", + "clock", + "contemporary", + "current", + "date", + "day", + "dot", + "dot in circle", + "event", + "filled circle", + "indicator", + "mark", + "marker", + "month", + "now", + "outline", + "plan", + "point", + "present", + "remember", + "reminder", + "ring", + "round", + "schedule", + "solid circle", + "time", + "today" + ], + "popularity": 66398 + }, + "TOGGLE_OFF": { + "tags": [ + "action", + "active", + "button", + "choice", + "circle", + "components", + "configuration", + "control", + "device", + "disable", + "disabled", + "elliptical", + "inable", + "inactive", + "indicator", + "interface", + "interface control", + "management", + "off", + "on", + "on-off", + "on/off", + "option", + "oval", + "power", + "preference", + "preference control", + "selection", + "setting", + "settings", + "site", + "slider", + "slider switch", + "state", + "status", + "switch", + "system", + "toggle", + "ui", + "ui control", + "ux", + "web", + "website" + ], + "popularity": 32050 + }, + "TOGGLE_ON": { + "tags": [ + "activate", + "active", + "button", + "circle", + "component", + "components", + "configuration", + "control", + "control on", + "disable", + "element", + "enable", + "enabled", + "feature", + "function", + "horizontal", + "inable", + "inactive", + "indicator", + "interface", + "off", + "on", + "option", + "oval", + "power", + "selection", + "setting", + "setting on", + "settings", + "site", + "slider", + "state", + "switch", + "switch on", + "toggle", + "toggle on", + "turn on", + "ui", + "ui control", + "ux", + "web", + "website" + ], + "popularity": 52381 + }, + "TOKEN": { + "tags": [ + "access", + "access token", + "account", + "approval", + "authentication", + "authentication token", + "authorization", + "badge", + "credentials", + "entry", + "grant", + "hexagon", + "identity", + "key", + "lock", + "login", + "logout", + "mark", + "password", + "permission", + "private", + "profile", + "protected", + "secure", + "security", + "shield", + "sign", + "sign in", + "sign out", + "symbol", + "token", + "unlock", + "user", + "verification" + ], + "popularity": 7840 + }, + "TOLL": { + "tags": [ + "assets", + "bill", + "booth", + "budget", + "car", + "card", + "cash", + "charge", + "circle", + "circles", + "coin", + "coin stack", + "commerce", + "cost", + "credit", + "currency", + "debit", + "dollar", + "dollars", + "economic", + "economy", + "euro", + "fees", + "finance", + "financial", + "funds", + "highway", + "income", + "money", + "online", + "pay", + "payment", + "price", + "revenue", + "stack", + "ticket", + "toll", + "transaction", + "wealth", + "yen" + ], + "popularity": 8442 + }, + "TONALITY": { + "tags": [ + "adjust", + "audio", + "audio icon", + "audio settings", + "circle", + "control", + "edit", + "editing", + "equalizer", + "equalizer icon", + "equalizer settings", + "filter", + "frequency", + "frequency spectrum", + "greyscale", + "image", + "levels", + "levels icon", + "music", + "music icon", + "music settings", + "photography", + "picture", + "settings", + "shade", + "shadow", + "sound control", + "sound wave", + "sound wave icon", + "spectrum", + "spectrum icon", + "tonality", + "volume", + "volume control", + "volume icon", + "wave", + "waveform", + "waveform icon" + ], + "popularity": 2405 + }, + "TOPIC": { + "tags": [ + "area", + "basis", + "category", + "concern", + "context", + "data", + "details", + "doc", + "document", + "domain", + "drive", + "element", + "facts", + "field", + "file", + "folder", + "foundation", + "header", + "heading", + "information", + "issue", + "knowledge", + "matter", + "origin", + "point", + "question", + "reference", + "resources", + "root", + "sheet", + "slide", + "source", + "storage", + "subject", + "subject matter", + "theme", + "title", + "topic" + ], + "popularity": 10724 + }, + "TORNADO": { + "tags": [ + "alert", + "atmospheric", + "climate", + "cone", + "crisis", + "danger", + "destructive", + "disaster", + "emergency", + "funnel", + "funnel cloud", + "hazard", + "line art", + "meteorological", + "natural", + "natural disaster", + "outline", + "pointed", + "rain", + "severe weather", + "spinning", + "storm", + "stroke", + "swirling", + "tornado", + "twister", + "vortex", + "warning", + "weather", + "weather warning", + "wind", + "windstorm" + ], + "popularity": 1067 + }, + "TOUCH_APP": { + "tags": [ + "action", + "app", + "application", + "button", + "click", + "command", + "control", + "cursor", + "device", + "digital", + "element", + "finger", + "fingers", + "gesture", + "hand", + "input", + "interact", + "mobile", + "navigation", + "phone", + "pointer", + "press", + "screen", + "select", + "software", + "tablet", + "tap", + "touch", + "ui element" + ], + "popularity": 44964 + }, + "TOUR": { + "tags": [ + "assist", + "assistance", + "circle", + "destination", + "dot", + "explanation", + "feature", + "first time", + "flag", + "guidance", + "guide", + "help", + "highlight", + "indicator", + "information", + "introduction", + "learn", + "learning", + "onboard", + "onboarding", + "places", + "pointer", + "progress", + "question", + "question mark", + "start", + "steps", + "support", + "tip", + "tour", + "travel", + "tutorial", + "visit", + "walk-through", + "walkthrough" + ], + "popularity": 10509 + }, + "TOYS": { + "tags": [ + "activity", + "assemble", + "blocks", + "building", + "building blocks", + "car", + "child", + "children", + "construct", + "cube", + "education", + "elementary", + "fun", + "game", + "games", + "geometry", + "item", + "kid", + "kids", + "learning", + "object", + "play", + "product", + "puzzle", + "shape", + "shop", + "shopping", + "square", + "stack", + "store", + "toy", + "toys", + "windmill" + ], + "popularity": 4641 + }, + "TRACK_CHANGES": { + "tags": [ + "bullseye", + "changes", + "circle", + "collaboration", + "compare", + "comparison", + "content", + "differences", + "document editing", + "document history", + "document management", + "document versions", + "draft", + "editing", + "editing features", + "editorial", + "evolve", + "file history", + "history", + "lines", + "movement", + "review", + "revisions", + "revisions history", + "rotate", + "shift", + "target", + "text", + "track", + "track changes", + "version control", + "version history", + "workflow", + "writing" + ], + "popularity": 19396 + }, + "TRAFFIC": { + "tags": [ + "accident", + "barrier", + "block", + "car", + "caution", + "cone", + "construction", + "detour", + "direction", + "guide", + "hazard", + "highway", + "light", + "maps", + "marker", + "obstacle", + "orange", + "pylon", + "road", + "safety", + "signal", + "slowdown", + "street", + "traffic", + "transportation", + "travel", + "vehicle", + "warning", + "work" + ], + "popularity": 10678 + }, + "TRAIN": { + "tags": [ + "automobile", + "car", + "cargo", + "cars", + "commute", + "destination", + "diesel", + "direction", + "electric", + "engine", + "freight", + "itinerary", + "journey", + "locomotive", + "maps", + "passenger", + "platform", + "public", + "public transport", + "rail", + "railroad", + "rails", + "railway", + "route", + "schedule", + "station", + "steam", + "subway", + "timetable", + "tourism", + "tracks", + "train", + "tram", + "transit", + "transportation", + "travel", + "trolley", + "vehicle", + "voyage" + ], + "popularity": 13057 + }, + "TRAM": { + "tags": [ + "automobile", + "cable car", + "car", + "cars", + "city", + "city icon", + "city transport", + "commute", + "direction", + "electric", + "journey", + "light rail", + "maps", + "passenger", + "passenger transport", + "public", + "public transport", + "rail", + "rail icon", + "rail vehicle", + "rails", + "railway", + "streetcar", + "subway", + "tracks", + "train", + "tram", + "transit", + "transportation", + "transportation icon", + "travel", + "travel icon", + "trolley", + "urban", + "urban transit", + "vehicle", + "vehicle icon" + ], + "popularity": 3392 + }, + "TRANSCRIBE": { + "tags": [ + "ai", + "analysis", + "assistant", + "audio", + "automatic", + "caption", + "communication", + "conversion", + "dictation", + "digital", + "document", + "instant", + "interpret", + "language", + "listen", + "live", + "machine learning", + "real-time", + "recognition", + "record", + "recording", + "sound", + "speech", + "technology", + "text", + "transcribe", + "transform", + "translate", + "voice" + ], + "popularity": 1074 + }, + "TRANSFER_WITHIN_A_STATION": { + "tags": [ + "a", + "arrow", + "arrows", + "body", + "bus", + "commute", + "connection", + "destination", + "direction", + "dots", + "exchange", + "horizontal arrows", + "human", + "left", + "line", + "location", + "map", + "maps", + "movement", + "navigation", + "opposite directions", + "people", + "person", + "point", + "public", + "public transport", + "rectangle", + "right", + "route", + "station", + "stop", + "train", + "transfer", + "transit", + "transport", + "transportation", + "travel", + "two arrows", + "vehicle", + "walk", + "within" + ], + "popularity": 6717 + }, + "TRANSFORM": { + "tags": [ + "adjust", + "alter", + "anchors", + "aspect ratio", + "box", + "change", + "contract", + "corners", + "crop", + "distortion", + "edit", + "editing", + "enlarge", + "expand", + "format", + "graphic design", + "image", + "image editing", + "layout", + "modify", + "move", + "perspective", + "photo", + "picture", + "points", + "position", + "rearrange", + "resize", + "scale", + "shrink", + "size", + "square", + "transform", + "visual" + ], + "popularity": 3776 + }, + "TRANSGENDER": { + "tags": [ + "arrow", + "biological sex", + "circle", + "community", + "cross", + "diversity", + "equality", + "female", + "gender", + "gender diverse", + "gender identity", + "gender symbol", + "human", + "identity", + "inclusion", + "lgbt", + "lgbtq+", + "line", + "male", + "neutral", + "non-binary", + "people", + "person", + "pride", + "pronoun", + "representation", + "sex", + "social", + "symbol", + "transgender" + ], + "popularity": 5922 + }, + "TRANSIT_ENTEREXIT": { + "tags": [ + "access", + "arrival", + "arrow", + "bus", + "commute", + "departure", + "direction", + "directional", + "door", + "egress", + "enter", + "enterexit", + "exit", + "gate", + "ingress", + "itinerary", + "line", + "location", + "maps", + "metro", + "navigation", + "passenger", + "point of interest", + "public transport", + "route", + "station", + "subway", + "train", + "transit", + "transit information", + "transportation", + "travel", + "travel plans", + "travel stop" + ], + "popularity": 2968 + }, + "TRANSLATE": { + "tags": [ + "arrow", + "bidirectional", + "bubble", + "change", + "chat", + "communication", + "conversion", + "dictionary", + "direction", + "double", + "exchange", + "global", + "international", + "language", + "left", + "linguistics", + "meaning", + "phrase", + "right", + "speak", + "speaking", + "speech", + "swap", + "talk", + "text", + "translate", + "translator", + "word", + "words" + ], + "popularity": 31470 + }, + "TRAVEL_EXPLORE": { + "tags": [ + "adventure", + "browser", + "circle", + "destination", + "discover", + "discovery", + "earth", + "explore", + "explore world", + "find", + "glass", + "global", + "globe", + "international", + "journey", + "location", + "look", + "magnify", + "magnifying", + "magnifying glass", + "map", + "navigate", + "navigation", + "network", + "plan", + "planet", + "search", + "see", + "social", + "space", + "sphere", + "tourism", + "tourist", + "travel", + "trip", + "wander", + "web", + "world", + "worldwide", + "zoom" + ], + "popularity": 35460 + }, + "TRENDING_DOWN": { + "tags": [ + "analysis", + "analytics", + "arrow", + "arrow down", + "arrow icon", + "business", + "chart", + "data", + "decline", + "decrease", + "decrease icon", + "diagonal arrow", + "diagonal line", + "diagram", + "dip", + "direction", + "down", + "downtrend", + "downward", + "drop", + "falling", + "finance", + "graph", + "infographic", + "line graph", + "lowering", + "measure", + "metrics", + "movement", + "negative trend", + "rate", + "rating", + "slump", + "statistics", + "stock market", + "tracking", + "trend icon", + "trending", + "trending down" + ], + "popularity": 15686 + }, + "TRENDING_FLAT": { + "tags": [ + "arrow", + "average", + "change", + "chart", + "constant", + "data", + "direction", + "equal", + "flat", + "forward arrow", + "graph", + "horizontal arrow", + "indicator", + "level", + "line", + "metric", + "movement", + "no change", + "normal", + "progress", + "rate", + "representation", + "right", + "right arrow", + "stable", + "standard", + "status", + "steady", + "straight arrow", + "track", + "tracking", + "trend", + "trending", + "trending flat", + "visual" + ], + "popularity": 26836 + }, + "TRENDING_UP": { + "tags": [ + "analysis", + "analytics", + "arrow", + "ascending", + "business", + "chart", + "data", + "diagram", + "direction", + "finance", + "gain", + "graph", + "growth", + "improve", + "increase", + "infographic", + "line graph", + "measure", + "metric", + "metrics", + "movement", + "performance", + "positive", + "progress", + "rate", + "rating", + "report", + "rising", + "statistics", + "status", + "tracking", + "trend", + "trending", + "trending up", + "up" + ], + "popularity": 93118 + }, + "TRIP_ORIGIN": { + "tags": [ + "address", + "beginning", + "circle", + "departure", + "destination", + "direction", + "dot", + "geo", + "geo location", + "gps", + "journey", + "location marker", + "map marker", + "map pin", + "marker", + "navigation", + "origin", + "pin", + "place", + "point", + "position", + "route", + "start", + "start location", + "starting point", + "travel", + "trip", + "trip origin" + ], + "popularity": 7687 + }, + "TROUBLESHOOT": { + "tags": [ + "adjust", + "analytics", + "chart", + "cogs", + "configure", + "data", + "diagnose", + "diagram", + "engineering", + "find", + "fix", + "gear", + "glass", + "graph", + "help", + "infographic", + "issue", + "line", + "look", + "machinery", + "magnify", + "magnifying", + "maintenance", + "measure", + "mechanic", + "mechanical", + "metrics", + "options", + "problem", + "repair", + "search", + "see", + "service", + "settings", + "setup", + "solution", + "spanner", + "statistics", + "support", + "system", + "technical", + "tool", + "tool bar", + "tracking", + "troubleshoot", + "utility", + "work", + "wrench" + ], + "popularity": 5683 + }, + "TRY": { + "tags": [ + "approve", + "attempt", + "best", + "bookmark", + "bubble", + "chat", + "comment", + "communicate", + "evaluation", + "excellence", + "favorite", + "feedback", + "gold star", + "grade", + "highlight", + "highlighted", + "important", + "marked", + "message", + "preferred", + "premium", + "quality", + "rank", + "ranking", + "rate", + "rating", + "recommended", + "review", + "save", + "saved", + "score", + "shape", + "special", + "speech", + "star", + "top", + "try", + "trying", + "valued" + ], + "popularity": 6878 + }, + "TSUNAMI": { + "tags": [ + "alert", + "breaking wave", + "climate", + "coastal", + "cresting wave", + "crisis", + "danger", + "disaster", + "disaster warning", + "emergency", + "environment", + "flood", + "force of nature", + "hazard", + "high wave", + "large wave", + "marine", + "natural disaster", + "ocean", + "ocean wave", + "powerful wave", + "rain", + "sea", + "storm", + "surge", + "swell", + "tsunami", + "turbulent water", + "warning", + "water", + "wave", + "weather" + ], + "popularity": 1227 + }, + "TTY": { + "tags": [ + "accessibility", + "aid", + "assistance", + "audio", + "buttons", + "call", + "cell", + "chat", + "communication", + "connection", + "contact", + "conversation", + "deaf", + "device", + "disability", + "display", + "hardware", + "hearing impaired", + "impaired", + "input", + "keypad", + "messaging", + "mobile", + "output", + "phone", + "rectangle", + "screen", + "sound", + "speech", + "square", + "talk", + "telephone", + "teletype", + "teletypewriter", + "terminal", + "text", + "text telephone", + "tty" + ], + "popularity": 2536 + }, + "TUNE": { + "tags": [ + "adjust", + "adjustments", + "audio", + "balance", + "bars", + "bass", + "configure", + "control", + "controls", + "custom", + "customize", + "edit", + "editing", + "equalizer", + "filter", + "filters", + "instant", + "levels", + "lines", + "mix", + "modify", + "music", + "options", + "preferences", + "setting", + "settings", + "setup", + "slider", + "sliders", + "sound", + "switches", + "three lines", + "tone", + "treble", + "tune", + "volume" + ], + "popularity": 70481 + }, + "TUNGSTEN": { + "tags": [ + "adjustments", + "balance", + "bright", + "brightness", + "camera", + "edit", + "editing", + "effects", + "electric", + "electricity", + "energy", + "filter", + "fluorescent", + "gleam", + "glow", + "illumination", + "image", + "incandescent", + "indoor", + "iridescent", + "lamp", + "light", + "light bulb", + "lightbulb", + "lighting", + "photo", + "photography", + "picture", + "power", + "setting", + "settings", + "shimmer", + "sparkle", + "tungsten", + "wb", + "white", + "white balance", + "wp" + ], + "popularity": 15272 + }, + "TURN_LEFT": { + "tags": [ + "angle", + "arrow", + "arrows", + "bend", + "curve", + "direction", + "directions", + "driving", + "follow", + "go", + "guidance", + "guide", + "lead", + "left", + "line", + "map", + "maps", + "navigation", + "path", + "point", + "proceed", + "road", + "route", + "segment", + "sign", + "trace", + "traffic", + "transit", + "travel", + "turn" + ], + "popularity": 1682 + }, + "TURN_RIGHT": { + "tags": [ + "arrow", + "arrows", + "bend right", + "changing direction", + "curved arrow", + "direction", + "directions", + "driving", + "forward and right", + "forward direction", + "future direction", + "gps", + "highway", + "indicator", + "location", + "map", + "maps", + "mobility", + "navigate", + "navigation", + "path", + "pointing right", + "right", + "right arrow", + "right turn", + "road", + "route", + "sign", + "street", + "symbol", + "traffic", + "travel", + "turn", + "turn right" + ], + "popularity": 2064 + }, + "TURN_SHARP_LEFT": { + "tags": [ + "angle", + "arrow", + "arrows", + "bend", + "curve", + "detour", + "direction", + "directions", + "drive", + "gps", + "indicator", + "instruction", + "left", + "left turn", + "maneuver", + "map", + "maps", + "navigation", + "path", + "pointer", + "road", + "route", + "sharp", + "sharp turn", + "sign", + "signage", + "street", + "symbol", + "traffic", + "transportation", + "travel", + "turn", + "turning" + ], + "popularity": 707 + }, + "TURN_SHARP_RIGHT": { + "tags": [ + "acute turn", + "arrow", + "arrows", + "car", + "curve", + "detour", + "direction", + "directions", + "driving", + "go", + "gps", + "guidance", + "instruction", + "journey", + "location", + "map", + "maps", + "movement", + "navigation", + "next", + "path", + "pointing", + "right", + "road", + "route", + "sharp", + "sign", + "traffic", + "transit", + "travel", + "turn", + "turn right", + "turning" + ], + "popularity": 1022 + }, + "TURN_SLIGHT_LEFT": { + "tags": [ + "angle", + "arrow", + "arrows", + "bend", + "change direction", + "corner", + "curve", + "direction", + "directional", + "directions", + "driving", + "go left", + "gps", + "guidance", + "left", + "location", + "map", + "maps", + "mobility", + "move", + "navigation", + "orientation", + "path", + "redirect", + "right", + "road", + "route", + "sign", + "slight", + "traffic", + "travel", + "turn", + "turning", + "walking", + "wayfinding" + ], + "popularity": 914 + }, + "TURN_SLIGHT_RIGHT": { + "tags": [ + "arrow", + "arrows", + "bend", + "curve", + "detour", + "direction", + "directions", + "driving", + "follow", + "gps", + "guidance", + "highway", + "instruction", + "map", + "maps", + "navigation", + "next", + "path", + "redirect", + "right", + "right turn", + "road", + "route", + "sharp", + "sign", + "slight", + "slight right", + "slight turn", + "street", + "symbol", + "traffic", + "travel", + "turn", + "turn right" + ], + "popularity": 954 + }, + "TURNED_IN": { + "tags": [ + "app", + "archive", + "article", + "book", + "bookmark", + "browser", + "collection", + "content", + "corner", + "document", + "favorite", + "file", + "fold", + "guide", + "in", + "keep", + "label", + "library", + "mark", + "mobile", + "organize", + "page", + "pin", + "read", + "reading", + "remember", + "ribbon", + "save", + "site", + "tag", + "turned", + "tutorial", + "web page" + ], + "popularity": 9722 + }, + "TURNED_IN_NOT": { + "tags": [ + "app", + "archive", + "article", + "book", + "bookmark", + "browser", + "collection", + "content", + "corner", + "document", + "favorite", + "file", + "fold", + "guide", + "in", + "keep", + "label", + "library", + "mark", + "mobile", + "not", + "organize", + "page", + "pin", + "read", + "reading", + "remember", + "ribbon", + "save", + "site", + "tag", + "turned", + "tutorial", + "web page" + ], + "popularity": 8650 + }, + "TV": { + "tags": [ + "device", + "display", + "entertainment", + "entertainment center", + "glyph", + "home", + "house", + "living room", + "media", + "monitor", + "outline", + "personal", + "rectangle", + "screen", + "screencast", + "solid fill", + "squared corners", + "stream", + "streaming", + "television", + "tv", + "video", + "wireless" + ], + "popularity": 15969 + }, + "TV_OFF": { + "tags": [ + "android", + "block", + "cancel", + "chrome", + "cross out", + "desktop", + "device", + "diagonal line", + "disabled", + "display", + "electronic", + "enabled", + "entertainment", + "hardware", + "inactive", + "ios", + "mac", + "media", + "monitor", + "multimedia", + "off", + "on", + "os", + "rectangular", + "screen", + "slash", + "technology", + "television", + "tv", + "unavailable", + "web", + "window" + ], + "popularity": 1217 + }, + "TWO_WHEELER": { + "tags": [ + "automobile", + "bike", + "car", + "cars", + "commuting", + "delivery", + "direction", + "driver", + "engine", + "journey", + "location", + "maps", + "mobility", + "motorbike", + "motorcycle", + "pavement", + "public", + "race", + "racing", + "ride", + "riding", + "road", + "route", + "scooter", + "speed", + "sport", + "street", + "transport", + "transportation", + "travel", + "two wheeler", + "two wheels", + "urban", + "vehicle", + "vehicle type", + "wheels" + ], + "popularity": 11524 + }, + "TYPE_SPECIMEN": { + "tags": [ + "characters", + "creative", + "design", + "detail", + "display", + "document", + "editing", + "example", + "file", + "font", + "formatting", + "graphic", + "information", + "layout", + "letters", + "lines", + "page", + "paragraph", + "preview", + "sample", + "showcase", + "specimen", + "style", + "text", + "type", + "typeface", + "typography", + "view", + "writing" + ], + "popularity": 662 + }, + "U_TURN_LEFT": { + "tags": [ + "arrow", + "arrows", + "bend", + "change direction", + "circle", + "curve", + "direction", + "directions", + "driving", + "driving directions", + "guide", + "left", + "left turn", + "loop", + "maps", + "navigation", + "path", + "return", + "reversal", + "reverse", + "road", + "road sign", + "route", + "sign", + "signage", + "street", + "traffic", + "transport", + "turn", + "turn around", + "u-turn", + "vehicle" + ], + "popularity": 1675 + }, + "U_TURN_RIGHT": { + "tags": [ + "arrow", + "arrows", + "bend", + "car", + "change direction", + "curve", + "curved arrow", + "direction", + "directions", + "driving", + "gps", + "guidance", + "maneuver", + "map", + "maps", + "navigation", + "path", + "reverse direction", + "right", + "road", + "road sign", + "route", + "sign", + "street", + "symbol", + "traffic", + "transportation", + "travel", + "turn", + "u-turn", + "vehicle" + ], + "popularity": 1185 + }, + "UMBRELLA": { + "tags": [ + "accessory", + "bad weather", + "beach", + "clothing", + "cover", + "curved", + "element", + "equipment", + "forecast", + "gear", + "handle", + "item", + "object", + "open", + "outdoor", + "pictogram", + "pole", + "portable", + "protection", + "rain", + "rainy day", + "safety", + "semicircle", + "shelter", + "shield", + "stick", + "sun", + "sunny", + "symbol", + "umbrella", + "weather", + "wet" + ], + "popularity": 2862 + }, + "UNARCHIVE": { + "tags": [ + "access", + "action", + "archive", + "arrow", + "box", + "button", + "command", + "container", + "data", + "direction", + "document", + "extract", + "file", + "folder", + "graphic", + "icon", + "inbox", + "interface control", + "item", + "linear", + "mail", + "menu", + "move up", + "open folder", + "option", + "rectangle", + "restore", + "retrieve", + "square", + "storage", + "store", + "symbol", + "unarchive", + "undo", + "up", + "up arrow" + ], + "popularity": 8552 + }, + "UNDO": { + "tags": [ + "action", + "arrow", + "back", + "backward", + "cancel", + "change", + "command", + "correction", + "curved", + "cycle", + "delete", + "editing", + "error", + "fix", + "go back", + "history", + "left", + "mail", + "mistake", + "operation", + "previous", + "redo", + "remove", + "repeat", + "restore", + "retrograde", + "return", + "reversal", + "revert", + "revise", + "rollback", + "rotate", + "step back", + "un-do", + "undo" + ], + "popularity": 37627 + }, + "UNFOLD_LESS": { + "tags": [ + "arrow", + "arrows", + "chevron", + "close", + "collapse", + "collapse content", + "compact", + "compress", + "condense", + "contract", + "detail", + "direction", + "expand", + "expand less", + "expandable", + "fold", + "fold content", + "group", + "hide", + "inward", + "item", + "less", + "list", + "minimize", + "narrow", + "navigation", + "reduce", + "retract", + "section", + "shorter", + "shrink", + "smaller", + "switch", + "toggle", + "unfold", + "unfold less", + "up", + "view less" + ], + "popularity": 13689 + }, + "UNFOLD_LESS_DOUBLE": { + "tags": [ + "arrow", + "arrows", + "arrows down", + "arrows inward", + "arrows pointing in", + "chevron", + "chevrons", + "close", + "collapse", + "compress", + "contract", + "decrease", + "direction", + "double", + "double arrows", + "expand", + "expandable", + "fold", + "inward", + "less", + "lessen", + "list", + "minimize", + "minimize application", + "minimize window", + "narrow", + "navigation", + "point", + "reduce", + "shrink", + "smaller", + "two arrows", + "unfold", + "up", + "vertical arrows" + ], + "popularity": 1134 + }, + "UNFOLD_MORE": { + "tags": [ + "arrow", + "arrows", + "caret", + "chevron", + "collapse", + "control", + "data", + "direction", + "direction change", + "down", + "expand", + "expand less", + "expand more", + "expandable", + "fold", + "fold less", + "fold more", + "hide", + "hierarchy", + "indicator", + "less", + "list", + "more", + "navigation", + "reveal", + "sort", + "table", + "toggle", + "unfold", + "unfold less", + "up" + ], + "popularity": 35489 + }, + "UNFOLD_MORE_DOUBLE": { + "tags": [ + "action", + "additional", + "arrow", + "arrows", + "button", + "chevron", + "collapse", + "control", + "details", + "direction", + "double", + "down", + "dropdown", + "expand", + "expandable", + "filter", + "hide", + "indication", + "information", + "line", + "list", + "maximize", + "menu", + "minimize", + "more", + "navigation", + "open", + "pointer", + "show", + "sort", + "symbol", + "toggle", + "unfold", + "up", + "vertical" + ], + "popularity": 1689 + }, + "UNPUBLISHED": { + "tags": [ + "analysis", + "analytics", + "approve", + "bar chart", + "bar graph", + "business", + "chart", + "check", + "circle", + "complete", + "dashboard", + "data", + "data visualization", + "disabled", + "done", + "enabled", + "financial", + "graph", + "growth", + "infographic", + "information", + "insights", + "mark", + "marketing", + "metrics", + "off", + "ok", + "on", + "performance", + "presentation", + "progress", + "report", + "results", + "review", + "sales", + "select", + "slash", + "statistics", + "summary", + "tick", + "trends", + "unpublished", + "validate", + "verified", + "visual data", + "yes" + ], + "popularity": 11519 + }, + "UNSUBSCRIBE": { + "tags": [ + "account", + "action", + "cancel", + "circle", + "close", + "communication", + "control", + "cross", + "data", + "delete", + "document", + "email", + "envelop", + "information", + "letters", + "list", + "mail", + "management", + "message", + "newsletter", + "notification", + "off", + "opt out", + "paper", + "preferences", + "remove", + "send", + "service", + "settings", + "shape", + "stop", + "subscribe", + "subscription", + "symbol", + "unsubscribe", + "x" + ], + "popularity": 6011 + }, + "UPCOMING": { + "tags": [ + "agenda", + "alarm", + "anticipation", + "appointment", + "calendar", + "coming", + "coming soon", + "date", + "events", + "events list", + "forecast", + "forthcoming", + "future", + "future events", + "horizon", + "later", + "later date", + "list", + "mail", + "message", + "new events", + "next", + "not yet", + "notification", + "pending", + "plans", + "preview", + "schedule", + "still to come", + "timeline", + "upcoming" + ], + "popularity": 6128 + }, + "UPDATE": { + "tags": [ + "app", + "arrow", + "arrow circle", + "back", + "backwards", + "circle", + "circular", + "clock", + "counter-clockwise", + "cycle", + "data", + "download", + "forward", + "history", + "internet", + "load", + "loading", + "loop", + "process", + "program", + "progress", + "redo", + "refresh", + "reload", + "renewal", + "reverse", + "rotate", + "schedule", + "software", + "spin", + "sync", + "synchronize", + "system", + "technology", + "time", + "undo", + "update", + "upload", + "web" + ], + "popularity": 61712 + }, + "UPDATE_DISABLED": { + "tags": [ + "arrow", + "back", + "backwards", + "blocked", + "cancelled", + "circle", + "clock", + "date", + "diagonal line", + "disabled", + "enabled", + "error", + "forbidden", + "forward", + "history", + "inactive", + "load", + "loading disabled", + "no access", + "no update", + "not available", + "not loading", + "not updating", + "not working", + "off", + "on", + "prohibited", + "refresh", + "refresh disabled", + "refresh off", + "reverse", + "rotate", + "schedule", + "slash", + "stopped", + "sync disabled", + "sync off", + "time", + "unavailable", + "update", + "update disabled" + ], + "popularity": 3497 + }, + "UPGRADE": { + "tags": [ + "above", + "advance", + "arrow", + "ascent", + "better", + "direction", + "elevation", + "enhance", + "export", + "growth", + "higher", + "improve", + "increase", + "instal", + "level up", + "line", + "new version", + "next", + "progress", + "promotion", + "replace", + "rise", + "top", + "up", + "update", + "upgrade", + "upward" + ], + "popularity": 15488 + }, + "UPLOAD": { + "tags": [ + "add", + "arrow", + "arrows", + "attach", + "backup", + "cloud", + "data", + "direction", + "document", + "download", + "drive", + "export", + "file", + "import", + "input", + "internet", + "memory", + "move", + "network", + "open", + "pointer", + "publish", + "save", + "select", + "send", + "server", + "share", + "store", + "submit", + "transfer", + "up", + "upload" + ], + "popularity": 25341 + }, + "UPLOAD_FILE": { + "tags": [ + "action", + "add", + "arrow", + "button", + "cloud", + "data", + "doc", + "document", + "download", + "drive", + "element", + "file", + "folder", + "folders", + "graphic", + "icon", + "import", + "line", + "page", + "paper", + "save", + "send", + "sheet", + "slide", + "store", + "symbol", + "transfer", + "transmit", + "ui", + "up", + "upload", + "writing" + ], + "popularity": 48451 + }, + "USB": { + "tags": [ + "accessory", + "cable", + "computer", + "connection", + "connector", + "data", + "data transfer", + "device", + "drive", + "electronics", + "external device", + "flash drive", + "geometric", + "hardware", + "icon", + "interface", + "line", + "memory", + "peripheral", + "plug", + "plug in", + "port", + "simple", + "stick", + "storage", + "symbol", + "technology", + "transfer", + "universal serial bus", + "usb", + "wire" + ], + "popularity": 5133 + }, + "USB_OFF": { + "tags": [ + "block", + "cable", + "computing", + "connection", + "cross out", + "data transfer", + "device", + "diagonal line", + "disabled", + "disallowed", + "disconnected", + "eject", + "forbidden", + "inactive", + "no connection", + "not active", + "off", + "port", + "remove device", + "safely remove", + "slash", + "stop", + "strike through", + "technology", + "unavailable", + "universal serial bus", + "unplug", + "usb", + "usb off", + "wire" + ], + "popularity": 1188 + }, + "VACCINES": { + "tags": [ + "aid", + "care", + "circle", + "clinic", + "covid", + "cross", + "disease", + "doctor", + "dose", + "drug", + "emergency", + "flu shot", + "health", + "healthcare", + "hospital", + "immunity", + "immunization", + "injection", + "jab", + "line", + "medical", + "medication", + "medicine", + "needle", + "nurse", + "pharmacy", + "plus", + "prevention", + "protection", + "shot", + "sick", + "syringe", + "therapy", + "treatment", + "vaccination", + "vaccine", + "vaccines", + "vial", + "virus" + ], + "popularity": 10703 + }, + "VAPE_FREE": { + "tags": [ + "addiction", + "ban", + "circle", + "diagonal line", + "disabled", + "e-cigarette", + "ecigarette", + "electronic cigarette", + "enabled", + "forbidden", + "forbidden sign", + "forbidden symbol", + "free", + "health", + "health and safety", + "never", + "no", + "no smoking", + "no vaping", + "off", + "on", + "places", + "prevention", + "prohibited", + "quit vaping", + "restriction", + "safety", + "slash", + "smoke", + "smoking", + "smoking ban", + "stop vaping", + "symbol", + "tobacco", + "vape", + "vape free", + "vaping", + "vapor", + "warning", + "wellness", + "zone" + ], + "popularity": 641 + }, + "VAPING_ROOMS": { + "tags": [ + "allowance", + "allowed", + "amenities", + "area", + "building", + "cloud", + "designated", + "e-cigarette", + "electronic cigarette", + "facility", + "indoor", + "location", + "lounge", + "never", + "no", + "permitted", + "place", + "places", + "private", + "prohibited", + "public", + "puff", + "recreation", + "relaxation", + "room", + "service", + "sign", + "smoke", + "smoking", + "symbol", + "tobacco", + "vape", + "vaping", + "vapor", + "warning", + "zone" + ], + "popularity": 815 + }, + "VERIFIED": { + "tags": [ + "accepted", + "accreditation", + "approval", + "approval icon", + "approve", + "authentic", + "authorized", + "badge", + "burst", + "certified", + "check", + "checkmark", + "checkmark in circle", + "complete", + "completed", + "confirmation", + "confirmed", + "credentials", + "done", + "green checkmark", + "identity", + "legitimacy", + "mark", + "official", + "ok", + "registered", + "select", + "stamp of approval", + "star", + "success", + "tick", + "trusted", + "valid", + "validate", + "verified", + "verified account", + "verified user", + "yes" + ], + "popularity": 162576 + }, + "VERIFIED_USER": { + "tags": [ + "approve", + "badge", + "certified", + "check", + "complete", + "confirmation", + "data", + "done", + "endorsed", + "excellent", + "exemption", + "good", + "gpp", + "guard", + "mark", + "ok", + "pass", + "positive", + "privacy", + "private", + "protect", + "protected", + "protection", + "quality", + "safety", + "security", + "select", + "shield", + "success", + "tick", + "trust", + "user", + "valid", + "validate", + "validation", + "verification", + "verified", + "yes" + ], + "popularity": 87777 + }, + "VERTICAL_ALIGN_BOTTOM": { + "tags": [ + "align", + "alignment", + "arrange", + "arrow", + "bottom", + "distribute", + "doc", + "document", + "down", + "edit", + "editing", + "editor", + "formatting", + "layout", + "lines", + "move", + "paragraph", + "position", + "sheet", + "sort", + "spreadsheet", + "stacked", + "text", + "textbox", + "type", + "typography", + "up arrow", + "vertical", + "vertical align bottom", + "visual", + "writing" + ], + "popularity": 8222 + }, + "VERTICAL_ALIGN_CENTER": { + "tags": [ + "align", + "alignment", + "arrange", + "arrow", + "bars", + "center", + "center align", + "centering", + "distribute", + "distribution", + "doc", + "document", + "down", + "edit", + "editing", + "editor", + "evenly", + "formatting", + "justification", + "justify", + "layout", + "line", + "lines", + "middle", + "middle align", + "paragraph", + "paragraph formatting", + "parallel", + "position", + "positioning", + "rectangle", + "sheet", + "spreadsheet", + "square", + "text", + "type", + "up", + "vertical", + "vertical alignment", + "writing" + ], + "popularity": 3463 + }, + "VERTICAL_ALIGN_TOP": { + "tags": [ + "align", + "alignment", + "arrange", + "arrow", + "box", + "doc", + "document", + "down", + "edit", + "editing", + "editor", + "format", + "layout", + "line", + "move", + "object", + "position", + "rectangle", + "sheet", + "sort", + "spreadsheet", + "text", + "top", + "type", + "up", + "vertical", + "vertically", + "writing" + ], + "popularity": 7609 + }, + "VERTICAL_DISTRIBUTE": { + "tags": [ + "align", + "alignment", + "bars", + "design tools", + "direction", + "distribute", + "distribute objects", + "editor", + "elements", + "equal", + "evenly", + "format", + "graphics", + "layout", + "layout tools", + "lines", + "objects", + "order", + "organization", + "paragraph", + "position", + "rearrange", + "rectangular", + "rectangular shapes", + "rule", + "rules", + "space", + "spacing", + "style", + "text", + "up and down", + "vertical", + "vertical alignment" + ], + "popularity": 2176 + }, + "VERTICAL_SHADES": { + "tags": [ + "adjust", + "bars", + "blinds", + "building", + "control", + "cover", + "covering", + "curtain", + "curtains", + "decoration", + "drapery", + "furniture", + "home", + "house", + "interior", + "light", + "lines", + "nest", + "office", + "open", + "parallel", + "pattern", + "privacy", + "rectangular", + "shade", + "shades", + "shutter", + "slats", + "striped", + "sun", + "sunshade", + "vertical", + "vertical blinds", + "window", + "window blinds", + "window shades" + ], + "popularity": 737 + }, + "VERTICAL_SHADES_CLOSED": { + "tags": [ + "barrier", + "blinds", + "closed", + "cover", + "covering", + "curtains", + "domestic", + "home", + "home decor", + "indoor", + "interior design", + "light control", + "nest", + "parallel lines", + "privacy", + "rectangles", + "roller", + "room", + "shade", + "shades", + "shading", + "shield", + "shutter", + "slats", + "strips", + "sun protection", + "sunshade", + "vertical blinds", + "vertical shades", + "window covering", + "window treatment" + ], + "popularity": 738 + }, + "VERTICAL_SPLIT": { + "tags": [ + "arrangement", + "columns", + "content layout", + "design", + "display", + "divide", + "document layout", + "dual view", + "format", + "formatting", + "grid", + "layout", + "page layout", + "panels", + "paragraph", + "partition", + "screen", + "section", + "segment", + "separation", + "side by side", + "side-by-side layout", + "split", + "split view", + "text", + "two columns", + "two panels", + "ui layout", + "vertical", + "vertical split", + "view", + "website", + "window", + "window layout", + "writing" + ], + "popularity": 8202 + }, + "VIBRATION": { + "tags": [ + "alert", + "android", + "audio", + "cell", + "communication", + "control", + "device", + "handheld", + "haptic", + "hardware", + "intensity", + "ios", + "lines", + "mobile", + "mode", + "motion", + "notification", + "off", + "os", + "phone", + "portrait", + "rectangle", + "ring", + "rounded corners", + "settings", + "silence", + "silent", + "smartphone", + "sound", + "switch", + "tablet", + "technology", + "toggle", + "vertical", + "vibrate", + "vibration", + "waves" + ], + "popularity": 4066 + }, + "VIDEO_CALL": { + "tags": [ + "+", + "add", + "audio", + "broadcast", + "call", + "camera", + "chat", + "cinema", + "communication", + "conference", + "distance learning", + "film", + "film strip", + "filming", + "group call", + "hardware", + "image", + "live", + "media", + "meeting", + "motion", + "movie", + "multimedia", + "new", + "online meeting", + "picture", + "plus", + "record", + "remote communication", + "remote work", + "streaming", + "symbol", + "telehealth", + "video", + "video chat", + "video conferencing", + "videocall", + "videography", + "virtual meeting", + "webcam" + ], + "popularity": 14661 + }, + "VIDEO_CAMERA_BACK": { + "tags": [ + "back", + "camera", + "capture", + "electronic device", + "entertainment", + "film", + "image", + "landscape", + "lens", + "media", + "mountain", + "mountains", + "movie", + "multimedia", + "photo", + "photography", + "picture", + "rear", + "record", + "recording", + "recording device", + "rectangle", + "reverse", + "rounded corners", + "technology", + "video", + "video capture" + ], + "popularity": 3821 + }, + "VIDEO_CAMERA_FRONT": { + "tags": [ + "account", + "broadcast", + "camera", + "capture", + "communication", + "face", + "film", + "film recording", + "filming", + "front", + "front camera", + "human", + "image", + "lens", + "live stream", + "media", + "movie", + "movie recording", + "multimedia", + "online meeting", + "people", + "person", + "photo", + "photography", + "picture", + "profile", + "record", + "recording", + "selfie", + "shutter", + "social media", + "streaming", + "user", + "video", + "video call", + "video conference", + "video recording", + "videography", + "virtual meeting", + "vlogging", + "webcam" + ], + "popularity": 10839 + }, + "VIDEO_CHAT": { + "tags": [ + "avatar", + "bubble", + "call", + "cam", + "camera", + "chat", + "comment", + "communicate", + "communication", + "conference", + "conversation", + "dialogue", + "display", + "facetime", + "feedback", + "head", + "live", + "meeting", + "message", + "network", + "online", + "person", + "profile", + "remote", + "screen", + "speech", + "speech bubble", + "talking", + "technology", + "video", + "video call", + "video chat", + "virtual", + "voice", + "web conferencing", + "webcam" + ], + "popularity": 874 + }, + "VIDEO_FILE": { + "tags": [ + "camera", + "doc", + "document", + "document type", + "extension", + "file", + "file type", + "film", + "filming", + "format", + "format type", + "hardware", + "image", + "media", + "media format", + "media player", + "motion", + "movie", + "movie file", + "multimedia", + "multimedia file", + "picture", + "play", + "play symbol", + "rectangle", + "square", + "triangle", + "video", + "video file", + "video player", + "videography", + "view", + "view file", + "watch", + "watch file" + ], + "popularity": 2646 + }, + "VIDEO_LABEL": { + "tags": [ + "category", + "cinematic", + "classification", + "clip", + "content", + "digital", + "editing", + "editor", + "entertainment", + "file", + "film", + "footage", + "format", + "icon", + "label", + "media", + "motion picture", + "movie", + "multimedia", + "play", + "player", + "production", + "recording", + "rectangle", + "screen", + "symbol", + "tag", + "type", + "video", + "visual", + "window" + ], + "popularity": 2050 + }, + "VIDEO_LIBRARY": { + "tags": [ + "archive", + "arrow", + "category", + "collection", + "content", + "document", + "education", + "entertainment", + "file", + "film", + "folder", + "gallery", + "group", + "library", + "list", + "media", + "movie", + "multimedia", + "multiple", + "organized", + "play", + "rectangle", + "shape", + "square", + "stack", + "storage", + "symbol", + "video", + "visual" + ], + "popularity": 17828 + }, + "VIDEO_SETTINGS": { + "tags": [ + "adjust", + "change", + "cogwheel", + "configuration", + "control", + "details", + "digital video", + "film settings", + "gear", + "info", + "information", + "media settings", + "movie settings", + "multimedia settings", + "options", + "play", + "playback settings", + "preferences", + "screen", + "service", + "setting", + "settings", + "setup", + "streaming settings", + "video", + "video adjust", + "video cogwheel", + "video configuration", + "video control", + "video gear", + "video options", + "video preferences", + "video settings", + "video setup", + "window" + ], + "popularity": 5353 + }, + "VIDEO_STABLE": { + "tags": [ + "abstract", + "alignment", + "anti-shake", + "balance", + "camera", + "capture", + "digital", + "film", + "filming", + "geometry", + "gyroscope", + "horizontal", + "level", + "line", + "media", + "motion", + "movie", + "multimedia", + "recording", + "rectangle", + "setting", + "shake", + "smooth", + "square", + "stability", + "stable", + "steady", + "taping", + "technology", + "vertical", + "video", + "video stable", + "visual" + ], + "popularity": 1272 + }, + "VIDEOCAM": { + "tags": [ + "broadcast", + "broadcasting", + "cam", + "camera", + "capture", + "conference", + "electronic", + "film", + "filming", + "hardware", + "image", + "lens", + "live", + "media", + "motion", + "movie", + "picture", + "playback", + "record", + "recording", + "shutter", + "stream", + "streaming", + "technology", + "video", + "video recording", + "videocam", + "videography" + ], + "popularity": 69529 + }, + "VIDEOCAM_OFF": { + "tags": [ + "blocked", + "broadcasting", + "call", + "cam", + "camera", + "capture", + "collaboration", + "communication", + "conference", + "crossed out", + "diagonal", + "disabled", + "enabled", + "film", + "filming", + "forbidden", + "hardware", + "image", + "lens", + "line", + "media", + "meeting", + "motion", + "multimedia", + "mute", + "off", + "offline", + "on", + "picture", + "recording", + "rectangle", + "remote work", + "screen sharing", + "slash", + "stopped", + "stream", + "unavailable", + "video", + "video call", + "videography", + "web conferencing" + ], + "popularity": 9719 + }, + "VIDEOGAME_ASSET": { + "tags": [ + "asset", + "button", + "console", + "control", + "controller", + "d-pad", + "device", + "electronic device", + "electronics", + "entertainment", + "esports", + "gadget", + "game", + "gamepad", + "gaming", + "google", + "handheld", + "hardware", + "hobby", + "input device", + "joystick", + "leisure", + "leisure activity", + "leisure time", + "media", + "online", + "peripheral", + "play", + "playstation", + "recreation", + "recreational", + "rectangle", + "remote", + "shape", + "simple", + "social", + "sports", + "stadia", + "technology", + "video", + "video game", + "videogame", + "xbox" + ], + "popularity": 9585 + }, + "VIDEOGAME_ASSET_OFF": { + "tags": [ + "asset", + "buttons", + "console", + "control", + "controller", + "cross", + "delete", + "denied", + "device", + "diagonal line", + "disable", + "disabled", + "enabled", + "entertainment", + "esports", + "fun", + "game", + "gamepad", + "gaming", + "google", + "handheld", + "hardware", + "hidden", + "hobby", + "inaccessible", + "inactive", + "joystick", + "leisure", + "media", + "not allowed", + "not found", + "not visible", + "off", + "on", + "online", + "playstation", + "rectangle", + "remote", + "remove", + "slash", + "social", + "sports", + "stadia", + "unavailable", + "video", + "video game", + "videogame", + "xbox" + ], + "popularity": 1069 + }, + "VIEW_AGENDA": { + "tags": [ + "agenda", + "agenda view", + "arrange", + "blocks", + "calendar", + "cards", + "checklist", + "data", + "design", + "display", + "entries", + "format", + "grid", + "information", + "items", + "layout", + "lines", + "list", + "list format", + "list view", + "management", + "multiple items", + "order", + "organization", + "plan", + "project", + "rectangles", + "schedule", + "stacked", + "stacked list", + "tasks", + "timeline", + "vertical list", + "view", + "view agenda", + "website" + ], + "popularity": 12196 + }, + "VIEW_ARRAY": { + "tags": [ + "arrange", + "arrangement", + "array", + "blocks", + "columns", + "content", + "data", + "design", + "display", + "format", + "grid", + "grouping", + "horizontal", + "layout", + "list", + "multiple", + "order", + "organize", + "presentation", + "rows", + "section", + "segment", + "structure", + "vertical", + "view", + "view array", + "visual", + "website" + ], + "popularity": 2925 + }, + "VIEW_CAROUSEL": { + "tags": [ + "cards", + "carousel", + "collection", + "content", + "design", + "display", + "elements", + "exhibition", + "format", + "gallery", + "grid", + "horizontal", + "image", + "images", + "items", + "layout", + "media", + "multiple", + "navigation", + "next", + "objects", + "photos", + "picture", + "pictures", + "present", + "presentation", + "previous", + "scrolling", + "sequence", + "show", + "slide", + "view", + "website" + ], + "popularity": 9023 + }, + "VIEW_COLUMN": { + "tags": [ + "alignment", + "arrangement", + "column", + "columns", + "data", + "data display", + "design", + "display", + "divide", + "division", + "format", + "grid", + "grid view", + "information display", + "layout", + "organize", + "pane", + "panel", + "part", + "presentation", + "section", + "segment", + "split", + "structure", + "table", + "table layout", + "table view", + "vertical", + "view", + "view column", + "view display", + "website", + "window" + ], + "popularity": 13978 + }, + "VIEW_COMFY": { + "tags": [ + "arrange", + "blocks", + "boxes", + "cells", + "collection", + "comfy", + "content", + "dashboard", + "data", + "display", + "elements", + "gallery", + "grid", + "information", + "items", + "layout", + "matrix", + "organise", + "organization", + "overview", + "pattern", + "presentation", + "squares", + "structure", + "summary", + "table", + "thumbnail", + "tiles", + "view" + ], + "popularity": 5620 + }, + "VIEW_COMFY_ALT": { + "tags": [ + "alt", + "area", + "arrangement", + "blocks", + "boxes", + "collection", + "comfortable", + "comfy", + "compartments", + "cozy", + "design", + "display", + "format", + "grid", + "group", + "items", + "layout", + "mode", + "mosaic", + "neat", + "options", + "organized", + "panels", + "pattern", + "presentation", + "section", + "square", + "squares", + "structured", + "tidy", + "tiling", + "view", + "view comfy alt", + "web" + ], + "popularity": 1784 + }, + "VIEW_COMPACT": { + "tags": [ + "alignment", + "arrange", + "array", + "blocks", + "boxes", + "columns", + "compact", + "dashboard", + "display", + "element.", + "format", + "grid", + "layout", + "matrix", + "mosaic", + "organize", + "overview", + "panels", + "pattern", + "presentation", + "rectangles", + "rows", + "section", + "shape", + "squares", + "structure", + "tile", + "view", + "windows" + ], + "popularity": 4241 + }, + "VIEW_COMPACT_ALT": { + "tags": [ + "alt", + "alternate", + "arrange", + "blocks", + "box", + "columns", + "compact", + "content", + "customize", + "data", + "design", + "display", + "filter", + "format", + "grid", + "layout", + "layout dense", + "options", + "organize", + "panel", + "presentation", + "rectangle", + "rows", + "sections", + "settings", + "sort", + "square", + "structure", + "view", + "view mode", + "web", + "windows" + ], + "popularity": 1662 + }, + "VIEW_COZY": { + "tags": [ + "arrangement", + "boxes", + "close", + "clustered", + "comfy", + "compact", + "content", + "cozy", + "data", + "dense", + "design", + "display", + "elements", + "format", + "grid", + "grid view", + "grouped", + "information", + "items", + "layout", + "list", + "list view", + "organization", + "packed", + "pattern", + "presentation", + "rectangles", + "structure", + "tight", + "view", + "view cozy", + "view options", + "visual", + "web" + ], + "popularity": 2124 + }, + "VIEW_DAY": { + "tags": [ + "appointment", + "arrangement", + "bar", + "blocks", + "calendar", + "cards", + "carousel", + "columns", + "date", + "day", + "design", + "display", + "event", + "format", + "grid", + "horizontal", + "layout", + "narrow", + "organization", + "panels", + "planning", + "presentation", + "schedule", + "strip", + "time", + "timeline", + "view", + "website" + ], + "popularity": 5219 + }, + "VIEW_HEADLINE": { + "tags": [ + "area", + "arrangement", + "article", + "bars", + "block", + "component", + "content", + "design", + "display", + "document", + "element", + "format", + "formatting", + "grid", + "grouping", + "heading", + "headline", + "layout", + "lines", + "list", + "order", + "organization", + "paragraph", + "presentation", + "screen", + "section", + "structure", + "text", + "title", + "topic", + "view", + "visual", + "website", + "window" + ], + "popularity": 22976 + }, + "VIEW_IN_AR": { + "tags": [ + "3d", + "3d model", + "ar", + "ar experience", + "augmented", + "augmented reality", + "box", + "cube", + "daydream", + "digital", + "display", + "future", + "headset", + "hologram", + "immersive", + "immersive view", + "in", + "overlay", + "perspective", + "real world", + "reality", + "reality view", + "science fiction", + "scifi", + "screen", + "spatial", + "square", + "technology", + "three dimensional", + "view", + "view in", + "view in ar", + "virtual reality", + "virtual_reality", + "vr" + ], + "popularity": 37036 + }, + "VIEW_KANBAN": { + "tags": [ + "agile", + "blocks", + "board", + "cards", + "column", + "grid", + "kanban", + "kanban board", + "layout", + "lines", + "list", + "management", + "organization", + "pattern", + "productivity", + "progress", + "project", + "project management", + "rectangular", + "squares", + "status", + "structure", + "task", + "task board", + "view", + "view options", + "visual board", + "workflow", + "workflow management" + ], + "popularity": 2609 + }, + "VIEW_LIST": { + "tags": [ + "arrangement", + "bulleted", + "catalog", + "compact", + "content", + "data", + "design", + "directory", + "display", + "document", + "filter", + "format", + "grid", + "index", + "information", + "inventory", + "items", + "layout", + "lines", + "list", + "menu", + "navigation", + "numbered", + "options", + "order", + "organization", + "presentation", + "rows", + "sequence", + "sort", + "stacked", + "structure", + "view", + "website" + ], + "popularity": 71837 + }, + "VIEW_MODULE": { + "tags": [ + "arrange", + "arrangement", + "blocks", + "collection", + "components", + "content", + "dashboard", + "data", + "design", + "display", + "format", + "gallery", + "grid", + "grouping", + "groups", + "information", + "items", + "layout", + "module", + "organization", + "organize", + "overview", + "pattern", + "presentation", + "rectangle", + "representation", + "sections", + "square", + "squares", + "stacked", + "structure", + "tiles", + "view", + "visual", + "website" + ], + "popularity": 19332 + }, + "VIEW_QUILT": { + "tags": [ + "arrangement", + "blocks", + "columns", + "composition", + "dashboard", + "design", + "divisions", + "format", + "gallery", + "grid", + "layout", + "mosaic", + "multiple views", + "options", + "organization", + "panels", + "pattern", + "quilt", + "rectangles", + "rows", + "sections", + "segments", + "selection", + "separation", + "square", + "squares", + "stacked", + "structure", + "tiles", + "view", + "website", + "windows" + ], + "popularity": 9018 + }, + "VIEW_SIDEBAR": { + "tags": [ + "area", + "bar", + "collapse", + "column", + "content", + "control", + "data", + "design", + "display", + "expand", + "format", + "grid", + "hide", + "information", + "interface", + "layout", + "list", + "menu", + "navigation", + "navigation panel", + "options", + "options panel", + "panel", + "rectangle", + "screen", + "section", + "settings", + "show", + "sidebar", + "toggle", + "vertical", + "view", + "web", + "window" + ], + "popularity": 8408 + }, + "VIEW_STREAM": { + "tags": [ + "arrangement", + "block view", + "blocks", + "columns", + "content", + "content blocks", + "data", + "design", + "display", + "divided", + "feed", + "format", + "gallery", + "grid", + "horizontal", + "information", + "layout", + "lines", + "list", + "mode", + "multiple items", + "organization", + "presentation", + "rectangles", + "rows", + "sectioned", + "stacked", + "stream", + "stream view", + "view", + "view layout", + "view options", + "website" + ], + "popularity": 7541 + }, + "VIEW_TIMELINE": { + "tags": [ + "analytics", + "chart", + "chronological", + "data", + "diagram", + "display", + "event", + "flow", + "graph", + "grid", + "history", + "horizontal", + "layout", + "line", + "milestone", + "monitoring", + "overview", + "pattern", + "period", + "presentation", + "progress", + "record", + "report", + "schedule", + "sequence", + "squares", + "time", + "timeline", + "tracking", + "vertical", + "view", + "visualization" + ], + "popularity": 5963 + }, + "VIEW_WEEK": { + "tags": [ + "agenda", + "agenda view", + "appointment", + "appointments", + "bars", + "calendar", + "calendar view", + "chronicle", + "chronicle view", + "columns", + "daily view", + "date", + "dates", + "day", + "day view", + "days of the week", + "design", + "display", + "event", + "events", + "format", + "grid", + "layout", + "list", + "organize", + "planning", + "record", + "schedule", + "seven days", + "time", + "timeline", + "view", + "website", + "week", + "weekly" + ], + "popularity": 10806 + }, + "VIGNETTE": { + "tags": [ + "adjustment", + "border", + "button", + "camera", + "circle", + "corner", + "dark", + "edge", + "edit", + "editing", + "effect", + "enhancement", + "fade", + "filter", + "frame", + "gradient", + "graphic", + "icon", + "image", + "lens", + "photo", + "photography", + "post processing", + "radial", + "round", + "setting", + "symbol", + "ui element", + "vignette", + "visual" + ], + "popularity": 1214 + }, + "VILLA": { + "tags": [ + "accommodation", + "architecture", + "beach", + "building", + "city", + "country", + "dwelling", + "estate", + "holiday", + "home", + "hotel", + "house", + "housing", + "lodging", + "maps", + "place", + "property", + "real", + "real estate", + "residence", + "residential", + "structure", + "tourism", + "town", + "travel", + "traveling", + "urban", + "vacation", + "vacation stay", + "villa" + ], + "popularity": 5336 + }, + "VISIBILITY": { + "tags": [ + "display", + "eye", + "glance", + "hidden", + "hidden text", + "insight", + "look", + "observe", + "on", + "optic", + "password visibility", + "peek", + "perspective", + "private", + "public", + "reveal", + "security", + "see", + "show", + "sighted", + "spy", + "stare", + "toggle visibility", + "unhide", + "view", + "visibility", + "visible", + "visual", + "watch" + ], + "popularity": 330301 + }, + "VISIBILITY_OFF": { + "tags": [ + "conceal", + "crossed out eye", + "diagonal line", + "disabled", + "disabled view", + "enabled", + "eye", + "form", + "hidden", + "hide", + "input", + "invisible", + "line through", + "masked", + "not visible", + "obscured", + "off", + "on", + "password", + "password field", + "privacy", + "private", + "reveal", + "secret", + "security", + "see", + "show", + "show/hide", + "slash", + "surveillance", + "toggle", + "toggle button", + "unviewable", + "unwatch", + "view", + "visibility", + "watch" + ], + "popularity": 134536 + }, + "VOICE_CHAT": { + "tags": [ + "audio", + "audio call", + "audio chat", + "bubble", + "cam", + "camera", + "chat", + "comment", + "communicate", + "communication", + "conversation", + "dialog", + "discussion", + "facetime", + "feedback", + "instant messaging", + "internet call", + "message", + "messaging app", + "online chat", + "phone call", + "social media", + "sound", + "speech", + "speech bubble", + "talk", + "talk bubble", + "video", + "voice", + "voice call", + "voice chat", + "voice message" + ], + "popularity": 4087 + }, + "VOICE_OVER_OFF": { + "tags": [ + "accessibility", + "accessibility feature", + "accessibility off", + "account", + "assistance disabled", + "audio disabled", + "audio off", + "blocked", + "cancelled", + "circle with slash", + "disabled", + "disabled feature", + "enabled", + "face", + "human", + "line through", + "mute", + "narration off", + "no audio", + "no sound", + "no voice", + "off", + "on", + "over", + "people", + "person", + "profile", + "recording", + "screen reader disabled", + "screen reader off", + "silence", + "slash", + "sound icon", + "sound off", + "speak", + "speaking", + "speaking off", + "speech", + "speech off", + "text to speech off", + "transcript", + "turned off", + "user", + "voice", + "voice icon", + "voice over disabled", + "voice over off", + "volume off" + ], + "popularity": 3331 + }, + "VOICEMAIL": { + "tags": [ + "alert", + "alert icon", + "audio", + "audio message", + "call", + "circle", + "circle with exclamation", + "communication", + "device", + "exclamation point", + "inbox", + "listening", + "mail", + "message", + "message icon", + "missed", + "mobile", + "new", + "notification", + "notification icon", + "phone", + "play", + "playback", + "receive", + "recording", + "sound", + "sound message", + "telephone", + "unread", + "voice", + "voice message", + "voicemail" + ], + "popularity": 3441 + }, + "VOLCANO": { + "tags": [ + "alert", + "ash", + "cone", + "crisis", + "danger", + "disaster", + "earth", + "emergency", + "environment", + "eruption", + "explosive", + "fire", + "geography", + "geological", + "geology", + "hazard", + "hot", + "landscape", + "lava", + "magma", + "mountain", + "natural", + "natural disaster", + "nature", + "outdoor", + "peak", + "science", + "smoke", + "steam", + "volcano", + "warning" + ], + "popularity": 876 + }, + "VOLUME_DOWN": { + "tags": [ + "acoustic", + "audio", + "audio adjustment", + "audio control", + "audio level", + "audio settings", + "control", + "curved lines", + "decrease volume", + "diminish", + "down", + "less", + "listen", + "lower volume", + "media player", + "multimedia", + "music", + "mute", + "noise", + "playback control", + "quieter", + "reduce", + "silence", + "sound", + "sound level", + "speaker", + "speaker cone", + "speaker symbol", + "tv", + "volume", + "volume control", + "volume down", + "waves" + ], + "popularity": 10132 + }, + "VOLUME_MUTE": { + "tags": [ + "audio", + "audio off", + "cancel", + "control", + "diagonal line", + "disabled", + "icon", + "media controls", + "music", + "mute", + "no audio", + "no sound", + "off", + "playback", + "quiet", + "settings", + "silence", + "silent", + "slash", + "sound", + "sound off", + "speaker", + "speaker off", + "stop", + "symbol", + "tv", + "volume", + "x mark" + ], + "popularity": 14792 + }, + "VOLUME_OFF": { + "tags": [ + "accessibility", + "audio", + "audio control", + "audio off", + "control", + "cross out", + "diagonal line", + "disabled", + "enabled", + "forbidden", + "hearing", + "low", + "media control", + "multimedia", + "music", + "mute", + "no sound", + "off", + "off state", + "on", + "prohibited", + "quiet", + "silent", + "slash", + "sound", + "sound off", + "speaker", + "speaker off", + "triangle", + "tv", + "volume", + "volume control", + "volume off" + ], + "popularity": 34336 + }, + "VOLUME_UP": { + "tags": [ + "acoustic", + "adjust volume", + "amplify", + "audio", + "audio bars", + "audio control", + "audio output", + "control", + "controls", + "decibels", + "hearing", + "high volume", + "icon", + "increase volume", + "listen", + "loud", + "media", + "multimedia", + "music", + "playback", + "settings", + "sound", + "sound bars", + "sound levels", + "sound setting", + "sound wave", + "speaker", + "symbol", + "tv", + "up", + "video", + "volume", + "volume control", + "volume up" + ], + "popularity": 62808 + }, + "VOLUNTEER_ACTIVISM": { + "tags": [ + "activism", + "aid", + "assistance", + "care", + "cause", + "charity", + "community", + "compassion", + "contribution", + "donate", + "donation", + "donation box", + "fingers", + "fund", + "funding", + "gesture", + "giving", + "good", + "hand", + "hands", + "heart", + "helping", + "helping hand", + "humanity", + "kindness", + "love", + "non-profit", + "organization", + "philanthropy", + "sharing", + "social", + "support", + "volunteer" + ], + "popularity": 38907 + }, + "VPN_KEY": { + "tags": [ + "access", + "authenticate", + "authentication", + "authorization", + "authorize", + "closed", + "code", + "connection", + "data", + "digital", + "door", + "encrypted", + "encryption", + "entry", + "internet", + "key", + "lock", + "login", + "network", + "passcode", + "password", + "privacy", + "private", + "protection", + "safety", + "secret", + "secure", + "security", + "shield", + "sign in", + "technology", + "unlock", + "vpn" + ], + "popularity": 49428 + }, + "VPN_KEY_OFF": { + "tags": [ + "access", + "account", + "authentication", + "blocked", + "closed", + "code", + "connection", + "credential", + "data", + "denied", + "disabled", + "disconnect", + "door", + "enabled", + "entry", + "internet", + "key", + "lock", + "login", + "network", + "no access", + "off", + "offline", + "on", + "passcode", + "password", + "privacy", + "private", + "protected", + "restricted", + "security", + "shield", + "sign in", + "slash", + "unavailable", + "unlock", + "vpn" + ], + "popularity": 1235 + }, + "VPN_LOCK": { + "tags": [ + "access", + "connection", + "cyber security", + "data protection", + "digital security", + "earth", + "globe", + "internet", + "internet security", + "lock", + "lock icon", + "locked", + "network", + "network security", + "online", + "padlock", + "password", + "privacy", + "privacy lock", + "private", + "protected", + "protected access", + "protection", + "restricted access", + "safe", + "safety", + "secure", + "secure connection", + "security", + "shield", + "virtual", + "virtual private network", + "vpn", + "vpn active", + "vpn connection", + "vpn status", + "world" + ], + "popularity": 7277 + }, + "VRPANO": { + "tags": [ + "360", + "angle", + "camera", + "circle", + "digital", + "experience", + "globe", + "image", + "immersive", + "landscape", + "lens", + "media", + "mountain", + "mountains", + "pano", + "panorama", + "panoramic", + "perspective", + "photo", + "photography", + "picture", + "reality", + "rounded", + "sensor", + "sphere", + "technology", + "view", + "virtual", + "visual", + "vr", + "vrpano", + "wide" + ], + "popularity": 2675 + }, + "WALLET": { + "tags": [ + "account", + "banking", + "budget", + "business", + "cash", + "commerce", + "credit", + "currency", + "debit", + "digital wallet", + "expenses", + "finance", + "folded", + "funds", + "investment", + "mobile wallet", + "money", + "online payment", + "payment", + "pocketbook", + "purchasing", + "rectangle", + "savings", + "spending", + "transaction", + "wallet", + "wealth" + ], + "popularity": 6890 + }, + "WALLPAPER": { + "tags": [ + "abstract", + "background", + "clouds", + "customize", + "dash", + "dashed", + "display", + "graphic", + "hills", + "horizon", + "icon", + "illustration", + "image", + "landscape", + "mountains", + "natural", + "nature", + "outdoors", + "pattern", + "personalize", + "photo", + "photography", + "picture", + "scene", + "scenery", + "screen", + "settings", + "sky", + "sun", + "theme", + "view", + "wallpaper" + ], + "popularity": 7858 + }, + "WAREHOUSE": { + "tags": [ + "architecture", + "building", + "business", + "cargo", + "commercial", + "delivery", + "depot", + "distribution", + "export", + "facility", + "factory", + "fulfillment", + "garage", + "goods", + "import", + "industrial", + "industry", + "inventory", + "logistics", + "manufacturing", + "materials", + "production", + "shed", + "shipping", + "stock", + "storage", + "store", + "structure", + "supply chain", + "transport", + "warehouse" + ], + "popularity": 11376 + }, + "WARNING": { + "tags": [ + "!", + "alert", + "app", + "attention", + "caution", + "danger", + "error", + "exclamation", + "flag", + "hazard", + "important", + "interface", + "issue", + "mark", + "message", + "notification", + "problem", + "risk", + "security", + "shield", + "sign", + "signal", + "status", + "symbol", + "system", + "triangle", + "ui", + "urgent", + "ux", + "warning", + "website" + ], + "popularity": 130297 + }, + "WARNING_AMBER": { + "tags": [ + "!", + "alert", + "amber", + "app", + "attention", + "caution", + "danger", + "error", + "exclamation", + "flag", + "hazard", + "important", + "interface", + "issue", + "mark", + "message", + "notification", + "problem", + "risk", + "security", + "shield", + "sign", + "signal", + "status", + "symbol", + "system", + "triangle", + "ui", + "urgent", + "ux", + "warning", + "website" + ], + "popularity": 57611 + }, + "WASH": { + "tags": [ + "appliance", + "bathroom", + "care", + "chores", + "clean", + "cleaning", + "cleanse", + "clothes", + "cycle", + "delicate", + "detergent", + "dirt", + "fabric", + "fingers", + "garment", + "gesture", + "hand", + "heavy", + "home", + "hygiene", + "laundry", + "machine", + "refresh", + "regular", + "remove", + "rinse", + "sanitize", + "service", + "soap", + "spin", + "stain", + "tumble", + "wash", + "water", + "wc" + ], + "popularity": 3674 + }, + "WATCH": { + "tags": [ + "accessory", + "alert", + "analog", + "band", + "circle", + "clock", + "device", + "digital", + "display", + "face", + "fitness", + "futuristic", + "gadget", + "hands", + "health", + "notification", + "pointers", + "retro", + "rounded corners", + "screen", + "smart", + "square", + "strap", + "technology", + "time", + "timepiece", + "tracking", + "watch", + "wearable", + "wearables", + "web", + "wrist", + "wristwatch" + ], + "popularity": 7096 + }, + "WATCH_LATER": { + "tags": [ + "alarm", + "appointment", + "calendar", + "chronometer", + "clock", + "countdown", + "date", + "deadline", + "delay", + "duration", + "event", + "future", + "history", + "hour", + "later", + "minute", + "organize", + "past", + "pending", + "period", + "plan", + "present", + "reminder", + "schedule", + "second", + "stopwatch", + "time", + "timer", + "upcoming", + "waiting", + "watch" + ], + "popularity": 63250 + }, + "WATCH_OFF": { + "tags": [ + "alarm", + "alert", + "band", + "block", + "cancel", + "clear", + "clock", + "close", + "deactivate", + "diagonal line", + "disable", + "do not disturb", + "exclude", + "forbidden", + "mute", + "notification", + "off", + "pause", + "prohibition", + "reminder", + "remove", + "restriction", + "shut", + "silent", + "slash", + "stop", + "strap", + "time", + "timer", + "watch", + "watch off", + "wearables", + "web", + "wrist", + "wristwatch" + ], + "popularity": 760 + }, + "WATER": { + "tags": [ + "abstract", + "aqua", + "basic", + "beach", + "clean", + "drip", + "drop", + "droplet", + "element", + "environment", + "fluid", + "humidity", + "hydration", + "lake", + "liquid", + "minimal", + "moisture", + "natural", + "ocean", + "outline", + "purify", + "rain", + "refresh", + "river", + "shape", + "simple", + "single drop", + "symbol", + "tear", + "tear drop", + "water", + "water drop", + "waves", + "weather", + "wet", + "wetness" + ], + "popularity": 10069 + }, + "WATER_DAMAGE": { + "tags": [ + "alert", + "architecture", + "building", + "caution", + "ceiling", + "damage", + "damp", + "disaster", + "drip", + "droop", + "drop", + "droplet", + "emergency", + "estate", + "flood", + "floor", + "hazard", + "home", + "house", + "issue", + "leak", + "liquid", + "maintenance", + "mark", + "moisture", + "pipe", + "plumbing", + "problem", + "property", + "puddle", + "real", + "repair", + "residence", + "residential", + "shelter", + "stain", + "storm", + "wall", + "warning", + "water", + "water damage", + "weather", + "wet" + ], + "popularity": 3242 + }, + "WATER_DROP": { + "tags": [ + "adjustments", + "aqua", + "blob", + "concentration", + "conservation", + "density", + "drink", + "drip", + "drop", + "droplet", + "eco", + "ecology", + "element", + "environment", + "filter", + "fluid", + "humidity", + "hydration", + "liquid", + "moisture", + "nature", + "ocean", + "oval", + "point", + "purification", + "rain", + "resource", + "settings", + "social", + "tear", + "teardrop", + "water", + "weather", + "wet" + ], + "popularity": 36032 + }, + "WATERFALL_CHART": { + "tags": [ + "analysis", + "analytics", + "bar", + "bars", + "breakdown", + "bridge", + "business", + "chart", + "columns", + "data", + "decrease", + "decrement", + "diagram", + "finance", + "financial", + "gain", + "graph", + "increase", + "increment", + "infographic", + "loss", + "measure", + "metrics", + "negative", + "positive", + "progress", + "report", + "stacked", + "statistics", + "summary", + "tracking", + "vertical", + "visualization", + "waterfall", + "waterfall chart" + ], + "popularity": 5320 + }, + "WAVES": { + "tags": [ + "audio", + "audio bars", + "audio control", + "audio icon", + "audio level", + "audio signal", + "audio visualizer", + "bar graph", + "beach", + "equalizer", + "equalizer icon", + "frequency", + "lake", + "level indicator", + "lines", + "media", + "music", + "music icon", + "music player", + "ocean", + "pool", + "river", + "sea", + "signal", + "signal icon", + "sound", + "sound control", + "sound level", + "sound signal", + "sound waves", + "spectrum", + "swim", + "visualizer", + "volume", + "volume icon", + "water", + "wave", + "waveform", + "waves" + ], + "popularity": 9170 + }, + "WAVING_HAND": { + "tags": [ + "acknowledgement", + "activity", + "availability", + "avatar", + "body part", + "bye", + "chat", + "communication", + "emoji", + "fingers", + "friendly", + "gesture", + "goodbye", + "greeting", + "greetings", + "hand", + "hello", + "hi", + "human", + "icon", + "interaction", + "palm", + "person", + "presence", + "profile", + "social", + "speak", + "status", + "symbol", + "wave", + "waving", + "waving hand", + "welcome" + ], + "popularity": 11859 + }, + "WB_AUTO": { + "tags": [ + "a", + "adjust", + "alphabet", + "ambient light", + "auto", + "auto brightness", + "auto light", + "auto settings", + "automatic", + "automatic mode", + "balance", + "bright", + "brightness", + "bulb", + "camera", + "character", + "control", + "detection", + "edit", + "editing", + "environment", + "exposure", + "font", + "illumination", + "image", + "image adjustment", + "lamp", + "letters", + "light bulb", + "lighting", + "mode", + "option", + "photo", + "photography", + "sensor", + "settings", + "symbol", + "text", + "type", + "w", + "wb", + "white", + "white balance", + "wp" + ], + "popularity": 884 + }, + "WB_CLOUDY": { + "tags": [ + "air", + "atmosphere", + "balance", + "climate", + "cloud", + "cloudy", + "edit", + "editing", + "environment", + "filled", + "forecast", + "graphic", + "icon", + "meteorology", + "minimal", + "nature", + "outline", + "overcast", + "rain", + "round", + "rounded", + "shape", + "simple", + "sky", + "snow", + "solid", + "symbol", + "temperature", + "ui", + "ui element", + "weather", + "white", + "wp" + ], + "popularity": 6809 + }, + "WB_INCANDESCENT": { + "tags": [ + "balance", + "base", + "bright", + "bulb", + "edit", + "editing", + "electric", + "electricity", + "energy", + "filament", + "glass", + "glow", + "hint", + "idea", + "illumination", + "incandescent", + "innovation", + "intelligent", + "invention", + "knowledge", + "lamp", + "light", + "lightbulb", + "lighting", + "power", + "screw", + "setting", + "settings", + "shine", + "socket", + "solution", + "suggestion", + "sáng tạo", + "thinking", + "white", + "wisdom", + "wp" + ], + "popularity": 7385 + }, + "WB_IRIDESCENT": { + "tags": [ + "adjustments", + "balance", + "bright", + "brightness", + "camera", + "edit", + "editing", + "effects", + "electric", + "electricity", + "energy", + "filter", + "fluorescent", + "gleam", + "glow", + "illumination", + "image", + "incandescent", + "indoor", + "iridescent", + "lamp", + "light", + "light bulb", + "lightbulb", + "lighting", + "photo", + "photography", + "picture", + "power", + "setting", + "settings", + "shimmer", + "sparkle", + "tungsten", + "wb", + "white", + "white balance", + "wp" + ], + "popularity": 1621 + }, + "WB_SHADE": { + "tags": [ + "adjust", + "area", + "balance", + "blind", + "building", + "control", + "cover", + "curtains", + "darkness", + "dim", + "geometry", + "home", + "horizontal", + "house", + "interior", + "light", + "light control", + "lighting", + "lines", + "object", + "privacy", + "rectangle", + "settings", + "shade", + "shutter", + "slats", + "space", + "sunlight", + "symbol", + "toggle", + "wb", + "white", + "window", + "window blind", + "window shade" + ], + "popularity": 1231 + }, + "WB_SUNNY": { + "tags": [ + "balance", + "beams", + "bright", + "celestial", + "circle", + "climate", + "day", + "daylight", + "environment", + "evening", + "forecast", + "heat", + "light", + "lighting", + "lines", + "morning", + "nature", + "noon", + "orb", + "outdoors", + "rays", + "season", + "sky", + "solar", + "star", + "summer", + "sun", + "sunny", + "temperature", + "warm", + "wb", + "weather", + "white" + ], + "popularity": 23771 + }, + "WB_TWILIGHT": { + "tags": [ + "ambient", + "ambient light", + "astronomy", + "atmosphere", + "balance", + "calm", + "celestial", + "darkness", + "dawn", + "dim", + "dimming", + "dusk", + "environmental", + "fade", + "fading", + "gradient", + "horizon", + "landscape", + "light", + "lighting", + "mood", + "natural", + "noon", + "peaceful", + "scenery", + "serene", + "sky", + "sun", + "sunrise", + "sunset", + "transition", + "twilight", + "view", + "wb", + "weather", + "white" + ], + "popularity": 3415 + }, + "WC": { + "tags": [ + "accessibility", + "amenities", + "bathroom", + "closet", + "destination", + "facilities", + "facility", + "female", + "gender", + "hygiene", + "international", + "lavatory", + "location", + "male", + "man", + "mapping", + "men's room", + "public restroom", + "restroom", + "room", + "sanitary", + "service", + "sign", + "symbol", + "toilet", + "travel", + "unisex", + "universal", + "wash", + "washroom", + "water", + "water closet", + "wc", + "women", + "women's room" + ], + "popularity": 11906 + }, + "WEB": { + "tags": [ + "address", + "browser", + "destination", + "direction", + "earth", + "find us", + "geolocation", + "geotag", + "global", + "globe", + "internet", + "location", + "location marker", + "location pin", + "map", + "map marker", + "map pin", + "marker", + "navigate", + "navigation", + "network", + "online", + "page", + "pinpoint", + "place", + "point", + "position", + "screen", + "site", + "sphere", + "spot", + "spot marker", + "web", + "website", + "where", + "world", + "www" + ], + "popularity": 18295 + }, + "WEB_ASSET": { + "tags": [ + "app", + "application", + "application desktop", + "asset", + "border", + "box", + "browser", + "browser window", + "coding", + "computer screen", + "content area", + "design", + "development", + "digital", + "display", + "download", + "frame", + "image", + "interface", + "internet", + "layout", + "media", + "monitor", + "online", + "page", + "programming", + "rectangle", + "screen", + "site", + "software", + "square", + "ui", + "ux", + "video", + "view", + "web", + "web asset", + "website", + "window", + "www" + ], + "popularity": 9067 + }, + "WEB_ASSET_OFF": { + "tags": [ + "alert", + "asset", + "blocked", + "browser", + "computer", + "connection", + "desktop", + "diagonal", + "disabled", + "enabled", + "error", + "failure", + "forbidden", + "icon", + "internet", + "line", + "network", + "no", + "not supported", + "off", + "on", + "page", + "problem", + "screen", + "slash", + "status", + "symbol", + "technology", + "unavailable", + "warning", + "web", + "webpage", + "website", + "window", + "windows", + "www", + "x" + ], + "popularity": 1592 + }, + "WEB_STORIES": { + "tags": [ + "column", + "communication", + "content", + "divide", + "feed", + "frames", + "google", + "images", + "logo", + "media", + "multiple panels", + "navigation", + "next", + "playback", + "previous", + "progress", + "reel", + "section", + "segment", + "separator", + "sequence", + "short video", + "slideshow", + "social media", + "stories", + "story", + "timeline", + "vertical video", + "video", + "view", + "watching", + "web", + "web stories" + ], + "popularity": 3116 + }, + "WEBHOOK": { + "tags": [ + "alert", + "api", + "arrow", + "automation", + "backend", + "box", + "code", + "communication", + "connection", + "data", + "developer", + "development", + "enterprise", + "event", + "integration", + "interface", + "line", + "link", + "message", + "notification", + "programming", + "rectangle", + "service", + "software", + "square", + "system", + "trigger", + "up arrow", + "update", + "webhook" + ], + "popularity": 5573 + }, + "WEEKEND": { + "tags": [ + "bag", + "baggage", + "baggage claim", + "briefcase", + "buckle", + "business trip", + "carry-on", + "chair", + "container", + "couch", + "furniture", + "handle", + "holiday", + "home", + "journey", + "leisure travel", + "living", + "lounge", + "luggage", + "overnight bag", + "packed", + "packing", + "packing list", + "rectangle", + "relax", + "room", + "storage", + "strap", + "suitcase", + "travel", + "travel bag", + "travel goods", + "travel plans", + "trip", + "vacation", + "vacation planning", + "weekend", + "weekender" + ], + "popularity": 6626 + }, + "WEST": { + "tags": [ + "arrow", + "away", + "back", + "chevron", + "direction", + "directional", + "exit", + "guide", + "indicator", + "journey", + "left", + "map", + "maps", + "move", + "navigation", + "orientation", + "path", + "point", + "pointer", + "previous", + "retreat", + "return", + "route", + "signage", + "travel", + "triangle", + "undo", + "voyage", + "way", + "west", + "withdraw" + ], + "popularity": 27465 + }, + "WHATSHOT": { + "tags": [ + "alert", + "alerts", + "arrow", + "blaze", + "burning", + "circle", + "dangerous", + "direction", + "energy", + "excitement", + "fiery", + "fire", + "flame", + "frames", + "hazard", + "heat", + "hot", + "ignition", + "important", + "inferno", + "intense", + "new", + "news", + "notification", + "passion", + "popular", + "round", + "significant", + "spicy", + "trending", + "updates", + "vital", + "warmth", + "warning", + "whatshot" + ], + "popularity": 17285 + }, + "WHEELCHAIR_PICKUP": { + "tags": [ + "accessibility", + "accessible", + "assistance", + "auto", + "body", + "car", + "disability", + "disabled", + "drive", + "dropoff", + "handicap", + "handicapped", + "health", + "help", + "human", + "icon", + "medical", + "mobility", + "person", + "pickup", + "ride", + "seat", + "sign", + "silhouette", + "special assistance", + "symbol", + "taxi", + "transport", + "transportation", + "travel", + "vehicle", + "wheelchair", + "wheels" + ], + "popularity": 2315 + }, + "WHERE_TO_VOTE": { + "tags": [ + "address", + "approve", + "ballot", + "campaign", + "candidate", + "check", + "citizen", + "civic", + "community", + "complete", + "democracy", + "destination", + "direction", + "directions", + "done", + "duty", + "election", + "elections", + "find", + "government", + "location", + "map", + "maps", + "mark", + "navigate", + "ok", + "participate", + "participation", + "pin", + "place", + "political", + "politics", + "poll", + "polling", + "precinct", + "register", + "registration", + "right", + "search", + "select", + "stop", + "tick", + "to", + "validate election", + "verified", + "vote", + "voting", + "where", + "yes" + ], + "popularity": 9595 + }, + "WIDGETS": { + "tags": [ + "add", + "app", + "arrange", + "blocks", + "box", + "boxes", + "components", + "customize", + "dashboard", + "display", + "elements", + "grid", + "layout", + "menu", + "modules", + "mosaic", + "options", + "organize", + "panels", + "personalize", + "rearrange", + "rectangles", + "remove", + "sections", + "setting", + "settings", + "squares", + "ui", + "view", + "widgets" + ], + "popularity": 29870 + }, + "WIDTH_FULL": { + "tags": [ + "action", + "arrows", + "button", + "columns", + "content", + "control", + "display", + "expand", + "extend", + "fill", + "full width", + "grid", + "horizontal", + "indicator", + "layout", + "left arrow", + "lines", + "maximize", + "menu", + "pointer", + "presentation", + "right arrow", + "scale", + "screen", + "sidebar", + "stretch", + "toggle", + "view", + "width" + ], + "popularity": 1102 + }, + "WIDTH_NORMAL": { + "tags": [ + "adjust size", + "adjust width", + "alignment", + "boundaries", + "canvas size", + "content width", + "contract", + "controls", + "dimensions", + "display width", + "document", + "editing", + "expand", + "horizontal", + "image size", + "layout", + "limits", + "measurement", + "normal width", + "page", + "proportions", + "resize", + "ruler", + "scale", + "settings", + "size", + "spacing", + "video size", + "width", + "window size" + ], + "popularity": 1010 + }, + "WIDTH_WIDE": { + "tags": [ + "adjust", + "aspect ratio", + "bar", + "cinema", + "dimension", + "display", + "enlarge", + "expand", + "film", + "format", + "full screen", + "horizontal", + "landscape", + "layout", + "maximize", + "measure", + "monitor", + "movie", + "panoramic", + "player", + "rectangle", + "scale", + "screen", + "size", + "stretch", + "video", + "view", + "wide", + "width wide", + "zoom" + ], + "popularity": 954 + }, + "WIFI": { + "tags": [ + "access point", + "antenna", + "bars", + "broadcast", + "communication", + "computer", + "connection", + "connectivity", + "data", + "device", + "hotspot", + "indicator", + "internet", + "network", + "online", + "phone", + "reception", + "scan", + "service", + "signal", + "status", + "strength", + "symbol", + "technology", + "waves", + "wifi", + "wireless" + ], + "popularity": 54006 + }, + "WIFI_1_BAR": { + "tags": [ + "1", + "1 bar", + "arc", + "bar", + "bars", + "broadcast", + "cell", + "cellular", + "communication", + "computer", + "connection", + "connectivity", + "curved", + "data", + "device", + "icon", + "internet", + "low signal", + "mobile", + "network", + "one bar", + "phone", + "radio", + "reception", + "scan", + "service", + "signal", + "status", + "strength", + "symbol", + "technology", + "wave", + "weak signal", + "wifi", + "wireless" + ], + "popularity": 1076 + }, + "WIFI_2_BAR": { + "tags": [ + "2", + "access", + "bar", + "bars", + "bars indicator", + "cell", + "cellular", + "communication", + "connection", + "connection status", + "connectivity", + "data", + "digital", + "indicator", + "internet", + "internet access", + "internet status", + "level", + "mobile", + "network", + "network status", + "partial signal", + "phone", + "scan", + "service", + "signal", + "signal strength", + "status", + "strength", + "technology", + "two bars", + "weak signal", + "wifi", + "wifi signal", + "wireless", + "wireless network" + ], + "popularity": 1202 + }, + "WIFI_CALLING": { + "tags": [ + "arcs", + "broadcast", + "call", + "calling", + "cell", + "cell service", + "communication", + "connect", + "connection", + "connectivity", + "contact", + "data", + "device", + "hardware", + "internet", + "internet calling", + "lines", + "mobile", + "network", + "phone", + "phone call", + "radial", + "reception", + "signal", + "talk", + "technology", + "telecommunications", + "telephone", + "voice", + "waves", + "wifi", + "wifi signal", + "wireless", + "wireless call" + ], + "popularity": 1871 + }, + "WIFI_CALLING_3": { + "tags": [ + "3", + "audio", + "calling", + "cell", + "cellular", + "communication", + "connection", + "connectivity", + "data", + "device", + "digital", + "indicator", + "internet", + "level", + "mobile", + "network", + "phone", + "signal", + "speed", + "status", + "symbol", + "technology", + "telephone", + "telephony", + "three lines", + "voice", + "waves", + "wifi", + "wireless" + ], + "popularity": 3028 + }, + "WIFI_CHANNEL": { + "tags": [ + "adjust", + "arc", + "arcs", + "broadcast", + "cellular", + "channel", + "communication", + "configure", + "connection", + "connectivity", + "curved lines", + "data", + "frequency", + "full signal", + "increasing signal", + "internet", + "line", + "lines", + "mobile", + "network", + "network channel", + "scan", + "service", + "setting", + "signal", + "spectrum", + "strong signal", + "technology", + "three lines", + "wave", + "waves", + "wifi", + "wifi channel", + "wireless", + "wireless channel" + ], + "popularity": 959 + }, + "WIFI_FIND": { + "tags": [ + "access point", + "antenna", + "arc", + "arch", + "bars", + "broadcast", + "cellular", + "communications", + "connection", + "curved lines", + "data", + "detect", + "discover", + "dots", + "find", + "hotspot", + "internet", + "locate", + "look", + "magnifying glass", + "mobile", + "network", + "notice", + "points", + "radio", + "rays", + "scan", + "search", + "service", + "signal", + "technology", + "waves", + "wifi", + "wireless" + ], + "popularity": 1404 + }, + "WIFI_LOCK": { + "tags": [ + "access", + "authentication", + "bars", + "cellular", + "connect", + "connection", + "connectivity", + "data", + "encrypted", + "four bars", + "full signal", + "internet", + "lock", + "locked", + "maximum signal", + "mobile", + "network", + "network access.", + "password", + "privacy", + "private", + "protected", + "protection", + "safe", + "safety", + "secure", + "security", + "service", + "signal", + "strength", + "wifi", + "wireless" + ], + "popularity": 1906 + }, + "WIFI_OFF": { + "tags": [ + "connection", + "connection off", + "data", + "diagonal line", + "disabled", + "disconnected", + "enabled", + "internet", + "internet off", + "network", + "network off", + "network symbol", + "no network", + "no signal", + "no wifi", + "no wireless", + "not connected", + "off", + "offline", + "on", + "outage", + "scan", + "service", + "signal", + "signal disabled", + "signal off", + "signal symbol", + "slash", + "unavailable", + "unavailable connection", + "unavailable network", + "unavailable signal", + "unavailable wifi", + "unavailable wireless", + "wifi", + "wifi off", + "wifi symbol", + "wireless", + "wireless off", + "wireless symbol" + ], + "popularity": 14937 + }, + "WIFI_PASSWORD": { + "tags": [ + "access", + "access code", + "authentication", + "authorization", + "cellular", + "connect", + "connection", + "connectivity", + "credentials", + "data", + "encryption", + "internet", + "internet access", + "key", + "lock", + "login", + "mobile", + "network", + "network security", + "passcode", + "password", + "privacy", + "private network", + "protection", + "scan", + "secure", + "secure network", + "security", + "service", + "signal", + "unlock", + "wifi", + "wifi signal", + "wireless", + "wireless network", + "wireless security" + ], + "popularity": 1696 + }, + "WIFI_PROTECTED_SETUP": { + "tags": [ + "access", + "around", + "arrow", + "arrows", + "authenticate", + "broadcast", + "configuration", + "connect", + "connection", + "establish", + "internet", + "link", + "network", + "network setup", + "protect", + "protected", + "protected setup", + "radio waves", + "rotate", + "secure connection", + "secured", + "security", + "setup", + "signal", + "signal strength", + "three arcs", + "three lines", + "wifi", + "wireless", + "wireless network", + "wps" + ], + "popularity": 5913 + }, + "WIFI_TETHERING": { + "tags": [ + "access point", + "cell", + "cellular", + "cellular data", + "connection", + "connectivity", + "data", + "data share", + "hotspot", + "internet", + "internet access", + "internet connection", + "link", + "mobile", + "mobile network", + "network", + "personal hotspot", + "phone", + "phone connection", + "phone hotspot", + "portable hotspot", + "portable wifi", + "scan", + "service", + "share", + "sharing internet", + "signal", + "speed", + "tethering", + "wifi", + "wifi share", + "wireless", + "wireless network" + ], + "popularity": 6652 + }, + "WIFI_TETHERING_ERROR": { + "tags": [ + "!", + "alert", + "attention", + "broken", + "caution", + "cell", + "cellular", + "communication", + "connection", + "danger", + "data", + "device", + "devices", + "disconnected", + "error", + "exclamation", + "failure", + "hotspot", + "icon", + "important", + "interface", + "internet", + "interrupted", + "issue", + "mark", + "mobile", + "network", + "notification", + "phone", + "problem", + "rounded", + "scan", + "service", + "share", + "sharing", + "signal", + "speed", + "symbol", + "tethering", + "unavailable", + "warning", + "wifi", + "wireless" + ], + "popularity": 1114 + }, + "WIFI_TETHERING_OFF": { + "tags": [ + "cell", + "cellular", + "connection", + "connection disabled", + "connection off", + "crossed out", + "data", + "data off", + "disabled", + "disconnected", + "enabled", + "hotspot off", + "internet", + "internet off", + "line", + "mobile", + "mobile hotspot off", + "network", + "network disabled", + "network off", + "no connection", + "no internet", + "no network", + "no wifi", + "off", + "offline", + "on", + "phone", + "portable hotspot off", + "portable wifi off", + "scan", + "service", + "sharing off", + "signal", + "signal disabled", + "signal off", + "slash", + "speed", + "tethering", + "tethering disabled", + "tethering off", + "unavailable", + "wifi", + "wifi disabled", + "wifi off", + "wireless" + ], + "popularity": 1562 + }, + "WIND_POWER": { + "tags": [ + "abstract", + "air flow", + "alternative energy", + "blades", + "clean energy", + "climate", + "eco", + "eco-friendly", + "electricity", + "energy", + "environment", + "generation", + "graphic", + "icon", + "lines", + "motion", + "nest", + "power", + "propeller", + "renewable energy", + "resources", + "spinning", + "sustainable", + "swirl", + "symbol", + "three lines", + "turbine", + "vortex", + "weather", + "wind", + "wind power", + "wind turbine", + "windy" + ], + "popularity": 2514 + }, + "WINDOW": { + "tags": [ + "aperture", + "app", + "application", + "application window", + "basic shape", + "border", + "browser window", + "close", + "computer window", + "container", + "desktop", + "display", + "element", + "frame", + "glass", + "grid", + "home", + "house", + "interior", + "layer", + "layout", + "modal window", + "opening", + "outline", + "outside", + "pane", + "panel", + "pop-up", + "program", + "program window", + "rectangle", + "screen", + "shape", + "software", + "square", + "view", + "window" + ], + "popularity": 7973 + }, + "WINE_BAR": { + "tags": [ + "alcohol", + "alcohol consumption", + "bar", + "bar icon", + "beverage", + "cafe", + "celebration", + "cheers", + "cocktail", + "cup", + "dining", + "drink", + "drink icon", + "drinking", + "entertainment", + "establishment", + "glass", + "glass icon", + "leisure", + "liquor", + "nightlife", + "pub", + "restaurant", + "restaurant icon", + "toast", + "wine", + "wine bar", + "wineglass", + "wineglass icon" + ], + "popularity": 6267 + }, + "WOMAN": { + "tags": [ + "account", + "avatar", + "character", + "circle", + "contact", + "female", + "female avatar", + "female identity", + "female person", + "female profile", + "female user", + "feminine", + "figure", + "gender", + "girl", + "head", + "human", + "identity", + "individual", + "lady", + "member", + "people", + "person", + "portrait", + "profile", + "shoulders", + "silhouette", + "social", + "symbol", + "user", + "woman", + "woman's", + "womanly", + "women" + ], + "popularity": 6179 + }, + "WOMAN_2": { + "tags": [ + "abstract", + "account", + "avatar", + "bust", + "female", + "figure", + "gender", + "girl", + "head", + "human", + "icon", + "identity", + "lady", + "outline", + "person", + "profile", + "representation", + "shoulders", + "silhouette", + "social", + "symbol", + "torso", + "user", + "woman", + "women" + ], + "popularity": 968 + }, + "WORK": { + "tags": [ + "achievement", + "bag", + "baggage", + "briefcase", + "business", + "career", + "case", + "commerce", + "corporate", + "deal", + "document", + "duty", + "economy", + "employee", + "employer", + "employment", + "executive", + "financial", + "folder", + "job", + "manager", + "occupation", + "office", + "portfolio", + "professional", + "projects", + "responsibility", + "success", + "suitcase", + "tasks", + "transaction", + "work" + ], + "popularity": 70338 + }, + "WORK_HISTORY": { + "tags": [ + "activity log", + "archive", + "back", + "backwards", + "bag", + "baggage", + "briefcase", + "business", + "career", + "case", + "clock", + "cv", + "data", + "date", + "document", + "employment", + "experience", + "history", + "history log", + "job", + "journal", + "list", + "log", + "paper", + "past", + "past jobs", + "pending", + "previous", + "professional", + "recent", + "record", + "resume", + "schedule", + "suitcase", + "task history", + "time", + "timeline", + "updates", + "work", + "work history", + "work record" + ], + "popularity": 7079 + }, + "WORK_OFF": { + "tags": [ + "bag", + "baggage", + "blocked", + "briefcase", + "business", + "business travel", + "cancelled", + "career", + "case", + "closed", + "cross out", + "diagonal line", + "disabled", + "document", + "employment", + "enabled", + "inactive", + "job", + "line through", + "luggage", + "not available", + "off", + "on", + "portfolio", + "productivity", + "restricted", + "slash", + "stopped", + "strike through", + "suitcase", + "travel", + "unavailable", + "work", + "working" + ], + "popularity": 3846 + }, + "WORK_OUTLINE": { + "tags": [ + "achievement", + "bag", + "baggage", + "briefcase", + "business", + "career", + "case", + "commerce", + "corporate", + "deal", + "document", + "duty", + "economy", + "employee", + "employer", + "employment", + "executive", + "financial", + "folder", + "job", + "manager", + "occupation", + "office", + "portfolio", + "professional", + "projects", + "responsibility", + "success", + "suitcase", + "tasks", + "transaction", + "work" + ], + "popularity": 34248 + }, + "WORKSPACE_PREMIUM": { + "tags": [ + "achievement", + "approval", + "authentic", + "authority", + "award", + "badge", + "certification", + "circle", + "degree", + "ecommerce", + "emblem", + "excellence", + "geometric", + "guarantee", + "honor", + "mark", + "medal", + "medallion", + "official", + "permit", + "points", + "premium", + "quality", + "recognition", + "reward", + "ribbon", + "seal", + "shape", + "stamp", + "star", + "status", + "symbol", + "verification", + "verified", + "winner", + "workspace" + ], + "popularity": 32693 + }, + "WORKSPACES": { + "tags": [ + "application", + "arrangement", + "circles", + "collaboration", + "computer", + "dashboard", + "desktop", + "display", + "documents", + "dot", + "files", + "filled", + "grid", + "group", + "interface", + "layers", + "layout", + "management", + "multiple", + "organization", + "outline", + "overview", + "panels", + "perspective", + "productivity", + "projects", + "screens", + "software", + "space", + "stacking", + "tabs", + "team", + "view", + "windows", + "work", + "workspaces" + ], + "popularity": 11517 + }, + "WRAP_TEXT": { + "tags": [ + "adjust", + "align", + "alignment", + "arrangement", + "arrow writing", + "box", + "content", + "doc", + "document", + "edit", + "editing", + "editor", + "flow", + "formatting", + "layout", + "line break", + "lines", + "multiple lines", + "page", + "paragraph", + "rectangle", + "shape", + "sheet", + "spreadsheet", + "square", + "straight lines", + "text", + "text layout", + "type", + "typography", + "word wrap", + "wrap", + "wrap text", + "write", + "writing" + ], + "popularity": 1795 + }, + "WRONG_LOCATION": { + "tags": [ + "address", + "alert", + "cancel", + "caution", + "clear", + "close", + "cross", + "denied", + "destination", + "deviation", + "direction", + "error", + "exit", + "failure", + "gps", + "incorrect", + "invalid", + "issue", + "location", + "lost", + "map", + "maps", + "marker", + "misplacement", + "navigation", + "no", + "not found", + "pin", + "place", + "position", + "problem", + "quit", + "remove", + "restricted", + "route", + "stop", + "unavailable", + "warning", + "wrong", + "x" + ], + "popularity": 3714 + }, + "WYSIWYG": { + "tags": [ + "basic editor", + "composer", + "composition", + "content creation", + "document", + "document editing", + "document editor", + "document formatting", + "editing", + "editor", + "formatting", + "input field", + "layout", + "lines", + "mode", + "page", + "paragraphs", + "plain text editor", + "rich text editor", + "screen", + "simple editor", + "site", + "software", + "styling", + "system", + "text", + "text area", + "text editing", + "text editor", + "text entry", + "text formatting", + "view", + "visibility", + "web", + "website", + "what you see is what you get", + "window", + "writing", + "wysiwyg" + ], + "popularity": 16682 + }, + "YARD": { + "tags": [ + "area", + "backyard", + "building", + "compound", + "dwelling", + "estate", + "exterior", + "flower", + "front yard", + "garden", + "green space", + "grounds", + "home", + "house", + "land", + "landscape", + "lawn", + "location", + "lot", + "nature", + "open space", + "outdoor", + "parcel", + "pettle", + "plants", + "plot", + "property", + "real estate", + "region", + "residence", + "space", + "territory", + "yard" + ], + "popularity": 10333 + }, + "YOUTUBE_SEARCHED_FOR": { + "tags": [ + "analysis", + "analytics", + "arrow", + "back", + "backwards", + "discover", + "entertainment", + "examine", + "explore", + "find", + "focus", + "glass", + "handle", + "history", + "inprogress", + "inspect", + "investigation", + "load", + "loading", + "locate", + "look", + "magnify", + "magnifying", + "magnifying glass", + "media", + "online", + "platform", + "query", + "recent", + "refresh", + "renew", + "research", + "restore", + "reverse", + "rotate", + "search", + "searched", + "see", + "service", + "video", + "youtube", + "zoom" + ], + "popularity": 10359 + }, + "ZOOM_IN": { + "tags": [ + "action", + "add", + "big", + "bigger", + "button", + "circle", + "command", + "control", + "cross", + "detail", + "enlarge", + "find", + "function", + "glass", + "grow", + "in", + "increase", + "input", + "interface tool", + "lens", + "line", + "look", + "magnifier", + "magnify", + "magnifying", + "magnifying glass", + "plus", + "positive", + "scale", + "search", + "see", + "size", + "tool", + "ui tool", + "view", + "zoom", + "zoom in" + ], + "popularity": 44051 + }, + "ZOOM_IN_MAP": { + "tags": [ + "add", + "arrow", + "arrows", + "cartography", + "center", + "close up", + "destination", + "detail", + "direction", + "enlarge", + "expand", + "explore", + "find", + "geography", + "in", + "increase", + "increase size", + "locate", + "location", + "magnify", + "magnifying glass", + "map", + "maps", + "middle", + "move", + "navigation", + "pinpoint", + "place", + "plus", + "position", + "search", + "stop", + "survey", + "travel", + "view", + "zoom", + "zoom in" + ], + "popularity": 4533 + }, + "ZOOM_OUT": { + "tags": [ + "action", + "adjust", + "button", + "control", + "decrease", + "decrease size", + "discover", + "document view", + "enlarge", + "explore", + "find", + "glass", + "image view", + "investigate", + "lens", + "look", + "loupe", + "magnify", + "magnifying", + "map view", + "minus", + "negative", + "out", + "pull back", + "reduce view", + "scale", + "scale down", + "search", + "see", + "setting", + "shrink", + "size", + "small", + "smaller", + "telescopic", + "tool", + "view", + "visual", + "zoom", + "zoom out" + ], + "popularity": 17726 + }, + "ZOOM_OUT_MAP": { + "tags": [ + "area", + "arrow", + "arrows", + "box", + "button", + "center", + "compass", + "contract", + "control", + "corner", + "destination", + "direction", + "exit full screen", + "expand", + "full screen", + "globe", + "location", + "map", + "maps", + "marker", + "middle", + "minimize", + "move", + "navigation", + "out", + "place", + "pointer", + "rectangle", + "scale", + "shape", + "shrink", + "square", + "stop", + "view", + "world", + "zoom", + "zoom out map" + ], + "popularity": 15102 + } + } +} diff --git a/sdk/python/packages/flet-mcp/src/flet_mcp/db.py b/sdk/python/packages/flet-mcp/src/flet_mcp/db.py new file mode 100644 index 0000000000..c02b8fcbc5 --- /dev/null +++ b/sdk/python/packages/flet-mcp/src/flet_mcp/db.py @@ -0,0 +1,42 @@ +"""SQLite helpers for the MCP server.""" + +import importlib.resources +from pathlib import Path + + +def get_db_path() -> Path: + """Return filesystem path to the bundled mcp.db.""" + ref = importlib.resources.files("flet_mcp").joinpath("data/mcp.db") + # For installed packages, this returns a real path + return Path(str(ref)) + + +def snippet(text: str, query: str, length: int = 200) -> str: + """Extract a snippet around the first match of query tokens in text.""" + if not text or not query: + return text[:length] if text else "" + + query_tokens = query.lower().split() + text_lower = text.lower() + + # Find the earliest match position + best_pos = len(text) + for token in query_tokens: + pos = text_lower.find(token) + if pos != -1 and pos < best_pos: + best_pos = pos + + if best_pos == len(text): + return text[:length] + + # Center snippet around match + start = max(0, best_pos - length // 4) + end = min(len(text), start + length) + + result = text[start:end] + if start > 0: + result = "..." + result + if end < len(text): + result = result + "..." + + return result diff --git a/sdk/python/packages/flet-mcp/src/flet_mcp/icons_store.py b/sdk/python/packages/flet-mcp/src/flet_mcp/icons_store.py new file mode 100644 index 0000000000..801b41068f --- /dev/null +++ b/sdk/python/packages/flet-mcp/src/flet_mcp/icons_store.py @@ -0,0 +1,141 @@ +"""In-memory icon search across Material and Cupertino icon sets. + +Icon names come from the bundled api.json enums; Material synonym tags +and popularity come from the committed `data/icons.json` (Google's own +fonts.google.com search metadata, refreshed via +`python -m flet_mcp.build.icons`). No runtime dependency on the flet +package — flet-mcp consumers install only the MCP runtime. +""" + +from __future__ import annotations + +from collections import defaultdict +from collections.abc import Iterable + + +class IconStore: + def __init__( + self, + material: Iterable[str], + cupertino: Iterable[str], + material_meta: dict[str, dict] | None = None, + ): + """`material` / `cupertino` are icon member names (ADD, TRASH, …). + `material_meta` maps NAME -> {"tags": [...], "popularity": int} + (the icons.json payload); missing/empty degrades gracefully to + name-token search.""" + self._material: list[str] = list(material) + self._cupertino: list[str] = list(cupertino) + self._meta: dict[str, dict] = material_meta or {} + + # Inverted index: keyword -> set of (family, icon_name). Name + # tokens and synonym tags land in the same index and score the + # same — popularity does the ranking (Google's tags are their + # search index; a tag hit on ADD must beat a name hit on the + # obscure ONE_K_PLUS). + self._index: dict[str, set[tuple[str, str]]] = defaultdict(set) + + self._build_index() + + def _build_index(self): + for icon_name in self._material: + self._index_icon("material", icon_name) + for icon_name in self._cupertino: + self._index_icon("cupertino", icon_name) + + def _popularity(self, family: str, icon_name: str) -> int: + if family != "material": + return 0 + meta = self._meta.get(icon_name) or self._meta.get(_base_name(icon_name)) + return int(meta.get("popularity", 0)) if meta else 0 + + def _index_icon(self, family: str, icon_name: str): + entry = (family, icon_name) + for token in icon_name.lower().split("_"): + if token: + self._index[token].add(entry) + + if family != "material": + return + # Tags are recorded for base names; style variants + # (_OUTLINED/_ROUNDED/_SHARP) inherit their base icon's tags. + meta = self._meta.get(icon_name) or self._meta.get(_base_name(icon_name)) + for tag in (meta or {}).get("tags", []): + for word in str(tag).lower().split(): + if word: + self._index[word].add(entry) + + def find( + self, + query: str, + family: str | None = None, + limit: int = 10, + ) -> list[str]: + """Search icons by query string. + + Args: + query: Space-separated search terms. + family: Optional filter — "material" or "cupertino". + limit: Maximum number of results to return. + + Returns: + List of qualified icon names like "Icons.ARROW_BACK" + or "CupertinoIcons.BACK". + """ + query_tokens = [t for t in query.lower().split() if t] + if not query_tokens: + return [] + + # Collect all candidate icons that match at least one token + candidates: dict[tuple[str, str], float] = defaultdict(float) + + for token in query_tokens: + for entry in self._index.get(token, set()): + fam, icon_name = entry + if family and fam != family: + continue + candidates[entry] += 10 + + # Bonus for exact full-name match + query_as_name = "_".join(query_tokens).upper() + for entry in list(candidates): + if entry[1] == query_as_name: + candidates[entry] += 100 + + # Deterministic order: score, then Google's popularity (common + # icons like ADD outrank obscure ones), then shorter names, then + # alphabetical — set iteration order must not decide what the + # model sees. + sorted_results = sorted( + candidates.items(), + key=lambda x: ( + -x[1], + -self._popularity(*x[0]), + len(x[0][1]), + x[0][1], + ), + ) + + results: list[str] = [] + for (fam, icon_name), _score in sorted_results: + if len(results) >= limit: + break + # Collapse Material style variants (_OUTLINED/_ROUNDED/_SHARP) + # when their base icon is also a candidate — one icon should + # not spend several result slots. + base = _base_name(icon_name) + if base != icon_name and (fam, base) in candidates: + continue + if fam == "material": + results.append(f"Icons.{icon_name}") + else: + results.append(f"CupertinoIcons.{icon_name}") + + return results + + +def _base_name(icon_name: str) -> str: + for suffix in ("_OUTLINED", "_ROUNDED", "_SHARP"): + if icon_name.endswith(suffix): + return icon_name[: -len(suffix)] + return icon_name diff --git a/sdk/python/packages/flet-mcp/src/flet_mcp/server.py b/sdk/python/packages/flet-mcp/src/flet_mcp/server.py new file mode 100644 index 0000000000..1102d6a80e --- /dev/null +++ b/sdk/python/packages/flet-mcp/src/flet_mcp/server.py @@ -0,0 +1,538 @@ +import json +import os +import sqlite3 +from typing import Optional, Union + +from fastmcp import FastMCP + +from flet_mcp.api_store import ApiStore, render_text +from flet_mcp.db import get_db_path +from flet_mcp.icons_store import IconStore + + +def _enabled(name: str, default: str = "0") -> bool: + return os.getenv(f"FLET_MCP_ENABLE_{name}", default).lower() in ("1", "true", "yes") + + +# Tool groups can be toggled at server startup via FLET_MCP_ENABLE_*. +# Defaults focus on the hallucination-reduction starter set (API + icons). +_API_ON = _enabled("API", default="1") +_ICONS_ON = _enabled("ICONS", default="1") +_EXAMPLES_ON = _enabled("EXAMPLES", default="0") +_DOCS_ON = _enabled("DOCS", default="0") +_CLI_ON = _enabled("CLI", default="0") + +# Single-response size budgets (chars). Tool output lands in the calling +# agent's conversation history where it is re-sent (and re-billed) on every +# subsequent LLM call, so oversized payloads are paged/truncated with a +# drill-down hint instead of returned whole. The largest bundled example is +# ~111k chars; doc sections are unbounded. +_EXAMPLE_CHARS_BUDGET = 24_000 +_DOC_CHARS_BUDGET = 12_000 + + +_enabled_groups = [ + name + for name, on in ( + ("API", _API_ON), + ("icons", _ICONS_ON), + ("examples", _EXAMPLES_ON), + ("docs", _DOCS_ON), + ("CLI", _CLI_ON), + ) + if on +] + + +mcp = FastMCP( + "flet-mcp", + instructions=( + "Flet MCP server provides tools for building Flet applications. " + f"Enabled tool groups in this session: {', '.join(_enabled_groups) or 'none'}. " + "When you have a class name in mind (any control, service, dataclass, " + "or event), call get_api(name) first — it is the cheapest verifier and " + "a 'not found' result is definitive. Methods marked `\"async\": true` " + "in the response must be awaited; the calling event handler must be " + '`async def`. The response also carries a `"package"` field — if it ' + 'is anything other than `"flet"`, that pip package must be added to ' + "the consuming project before the import will resolve. Use " + "list_controls only to browse, and enum tools for enum lookups. If " + "examples or docs tools are enabled, search first and retrieve full " + "content with the matching get_* tool. Other groups can be toggled " + "via FLET_MCP_ENABLE_{API,ICONS,EXAMPLES,DOCS,CLI}=1." + ), +) + +_api_store: Optional[ApiStore] = None +_icon_store: Optional[IconStore] = None + + +def _get_api_store() -> ApiStore: + global _api_store + if _api_store is None: + _api_store = ApiStore() + return _api_store + + +def _get_icon_store() -> IconStore: + global _icon_store + if _icon_store is None: + # Icon names come from the bundled api.json enums, not the flet + # package — flet is not installed on runtime-only consumers. + # Synonym tags/popularity come from the committed data/icons.json + # (Google's icon search metadata); absent, search degrades to + # name tokens only. + import importlib.resources + + api = _get_api_store() + meta: dict = {} + try: + ref = importlib.resources.files("flet_mcp").joinpath("data/icons.json") + meta = json.loads(ref.read_text(encoding="utf-8")).get("material", {}) + except (FileNotFoundError, json.JSONDecodeError): + pass + _icon_store = IconStore( + material=api.enum_member_names("Icons"), + cupertino=api.enum_member_names("CupertinoIcons"), + material_meta=meta, + ) + return _icon_store + + +def _get_db() -> sqlite3.Connection: + db_path = get_db_path() + conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True) + conn.row_factory = sqlite3.Row + return conn + + +# ── Examples ────────────────────────────────────────────────────────────── + + +if _EXAMPLES_ON: + + @mcp.tool() + def search_examples( + query: str, platform: Optional[str] = None, limit: int = 5 + ) -> list[dict]: + """Search Flet example projects by keyword. + + Returns a ranked list of examples with id, title, description, and snippet. + Use get_example() to retrieve full source code. + + Args: + query: Search keywords (e.g. "counter", "form validation", "navigation"). + platform: Optional platform filter (web, ios, android, macos, windows, + linux). + limit: Maximum number of results to return. + """ + conn = _get_db() + try: + table_check = conn.execute( + "SELECT name FROM sqlite_master " + "WHERE type='table' AND name='examples_fts'" + ).fetchone() + if not table_check: + return [] + + # BM25 weights: title=8, description=5, tags=4, controls=5, + # layout_pattern=6, features=4, search_text=2, code=1 + rows = conn.execute( + """ + SELECT e.id, e.location, e.metadata, + snippet(examples_fts, 6, '**', '**', '...', 40) AS snip, + bm25( + examples_fts, + 8.0, 5.0, 4.0, 5.0, 6.0, 4.0, 2.0, 1.0 + ) AS rank + FROM examples_fts + JOIN examples e ON examples_fts.rowid = e.rowid + WHERE examples_fts MATCH ? + ORDER BY rank + LIMIT ? + """, + (query, limit), + ).fetchall() + + results = [] + for row in rows: + meta = json.loads(row["metadata"]) + if platform and platform.lower() not in [ + p.lower() for p in meta.get("platforms", []) + ]: + continue + results.append( + { + "id": row["id"], + "title": meta.get("title", ""), + "description": meta.get("description", ""), + "controls": meta.get("controls", []), + "complexity": meta.get("complexity", ""), + "snippet": row["snip"] or "", + } + ) + return results + finally: + conn.close() + + @mcp.tool() + def get_example(example_id: str, filename: Optional[str] = None) -> dict: + """Get full source code and metadata for a specific example. + + Small examples are returned whole. For large multi-file examples the + response lists every file with its size but inlines contents only up + to a budget — fetch the remaining files one at a time via `filename`. + + Args: + example_id: The example ID returned by search_examples(). + filename: Optional single file to fetch in full. + """ + conn = _get_db() + try: + table_check = conn.execute( + "SELECT name FROM sqlite_master WHERE type='table' AND name='examples'" + ).fetchone() + if not table_check: + return {"error": "No examples indexed"} + + row = conn.execute( + "SELECT id, location, metadata FROM examples WHERE id = ?", + (example_id,), + ).fetchone() + if not row: + return {"error": f"Example '{example_id}' not found"} + + files = conn.execute( + "SELECT filename, content FROM example_files WHERE example_id = ?", + (example_id,), + ).fetchall() + + if filename is not None: + for f in files: + if f["filename"] == filename: + return { + "id": row["id"], + "filename": filename, + "content": f["content"], + } + return { + "error": f"Example '{example_id}' has no file '{filename}'", + "available_files": [f["filename"] for f in files], + } + + meta = json.loads(row["metadata"]) + contents: dict[str, str] = {} + omitted: list[str] = [] + budget = _EXAMPLE_CHARS_BUDGET + for f in files: + content = f["content"] + if len(content) <= budget: + contents[f["filename"]] = content + budget -= len(content) + else: + omitted.append(f["filename"]) + result = { + "id": row["id"], + "location": row["location"], + **meta, + "file_sizes": {f["filename"]: len(f["content"]) for f in files}, + "files": contents, + } + if omitted: + result["note"] = ( + "Large example — contents omitted for " + f"{omitted}; call get_example({example_id!r}, " + "filename=) to fetch each in full." + ) + return result + finally: + conn.close() + + +# ── Documentation ───────────────────────────────────────────────────────── + + +if _DOCS_ON: + + @mcp.tool() + def search_docs(query: str, limit: int = 5) -> list[dict]: + """Search Flet documentation by keyword. + + Returns ranked results with title, location, and snippet. + Use get_doc() to retrieve full content. + + Args: + query: Search keywords (e.g. "TextField validation", "routing", "theme"). + limit: Maximum number of results to return. + """ + conn = _get_db() + try: + table_check = conn.execute( + "SELECT name FROM sqlite_master WHERE type='table' AND name='docs_fts'" + ).fetchone() + if not table_check: + return [] + + # BM25 weights: title=6, location_text=4, content=1 + rows = conn.execute( + """ + SELECT d.location, d.title, + snippet(docs_fts, 2, '**', '**', '...', 40) AS snip, + bm25(docs_fts, 6.0, 4.0, 1.0) AS rank + FROM docs_fts + JOIN docs d ON docs_fts.rowid = d.rowid + WHERE docs_fts MATCH ? + ORDER BY rank + LIMIT ? + """, + (query, limit), + ).fetchall() + + return [ + { + "title": row["title"], + "location": row["location"], + "snippet": row["snip"] or "", + } + for row in rows + ] + finally: + conn.close() + + @mcp.tool() + def get_doc(location: str) -> dict: + """Get full content of a documentation section by its location path. + + Args: + location: The location path returned by search_docs() + (e.g. "controls/textfield/", "controls/textfield/#validation"). + """ + conn = _get_db() + try: + table_check = conn.execute( + "SELECT name FROM sqlite_master WHERE type='table' AND name='docs'" + ).fetchone() + if not table_check: + return {"error": "No docs indexed"} + + row = conn.execute( + "SELECT location, title, content FROM docs WHERE location = ?", + (location,), + ).fetchone() + if not row: + return {"error": f"Document '{location}' not found"} + content = row["content"] + result = { + "location": row["location"], + "title": row["title"], + "content": content[:_DOC_CHARS_BUDGET], + } + if len(content) > _DOC_CHARS_BUDGET: + result["note"] = ( + f"Truncated at {_DOC_CHARS_BUDGET:,} of {len(content):,} " + "chars — search_docs() with a narrower query to land on a " + "more specific section (e.g. a '#fragment' location)." + ) + return result + finally: + conn.close() + + +# ── API Reference ───────────────────────────────────────────────────────── + + +if _API_ON: + + @mcp.tool() + def list_controls( + category: Optional[str] = None, + kind: Optional[str] = None, + limit: int = 50, + ) -> list[dict]: + """List available Flet controls and services. + + Args: + category: Optional category filter (e.g. "input", "layout", "navigation"). + kind: Optional kind filter - "control" for visual controls, + "service" for non-visual services (Audio, FilePicker, sensors, etc.). + limit: Maximum number of results to return. + """ + store = _get_api_store() + return store.list_controls(category=category, kind=kind, limit=limit) + + @mcp.tool() + def get_api( + name: str, + member: Optional[str] = None, + query: Optional[str] = None, + format: str = "text", + ) -> Union[str, dict]: + """Get the API reference for any Flet symbol by name. + + Looks across visual controls, non-visual services, dataclass types + (ButtonStyle, Padding, TextStyle, Border, Theme, ColorScheme, ...), + event classes, and enums (MainAxisAlignment, TextAlign, Icons, ...). + + This is the primary verification tool — when you have a name in mind, + call this first. A "not found" response is a definitive negative: the + name does not exist in this Flet version. + + The default response is compact text, one line per member: + + Page (control) — High-level root control for an app view. + bases: AdaptiveControl + properties: + bgcolor: ColorValue? — Background color of the page. + multi_views: list[MultiView] = [] — The list of multi-views... + events: + on_route_change(RouteChangeEvent) — Called when route changes. + methods: + async push_route(route, kwargs) -> None — Pushes a new route... + + Layout conventions: + * `(control)` / `(service)` / `(type)` / `(event)` / `(enum)` after + the symbol name says which bucket matched. + * `?` suffix on a property type = optional (may be None). + * `on_x(SomeEvent)` — the handler receives a `SomeEvent` argument. + * `async ` prefix — the method must be awaited (so the event handler + calling it must be `async def`). + * A `package: ` line means the class lives in that pip package, + which must be added to the project's dependencies before importing + it — surface this to the user. No line = core `flet`, always + available. + * `DEPRECATED: ` — do not use; pick the replacement named in + the reason. + * Member docstrings are trimmed to their first sentence; the `note:` + line reminds you how to drill down. + + Drill-down / filtering: + * `member="push_route"` — one member's full, untrimmed docstring and + exact type. + * `query="border"` — only members whose name contains the substring + (case-insensitive). `member` wins if both are passed. + * A few names are shared by multiple classes (e.g. the Text control + vs the canvas Text shape) — the primary one is returned and the + `note:` line lists the others with a dotted name that selects + them, e.g. `get_api("canvas.Text")`. + * Neither applies to enums — use search_enum_members / + enum_has_member / find_icon there. Large enums (Icons, + CupertinoIcons) are always truncated to a sample. + + Errors are returned as JSON objects (`{"error": ...}`), sometimes + with `available_members`/`available_files` hints. + + Args: + name: Symbol name (e.g. "Button", "Window", "AlertDialog", "Audio", + "ButtonStyle", "TapEvent", "MainAxisAlignment", "Icons"). + member: Optional property/event/method name (e.g. "on_scroll", + "push_route") to fetch with its full, untrimmed docstring. + query: Optional case-insensitive substring to filter member names. + format: "text" (default, compact) or "json" (structured dicts, + full raw type strings; for programmatic consumers). + """ + store = _get_api_store() + result = store.get(name, member=member, query=query) + if result is None: + return {"error": f"'{name}' not found"} + if "error" in result or format == "json": + return result + return render_text(result) + + @mcp.tool() + def get_enum(name: str) -> dict: + """Get enum definition. + + For small enums (< 50 members), returns all members. + For large enums (Icons, CupertinoIcons), returns metadata and sample members. + Use search_enum_members() for large enum lookup. + + Args: + name: Enum class name (e.g. "TextAlign", "Icons", "CupertinoIcons"). + """ + store = _get_api_store() + result = store.get_enum(name) + if result is None: + return {"error": f"Enum '{name}' not found"} + return result + + @mcp.tool() + def search_enum_members(name: str, query: str, limit: int = 10) -> dict: + """Search enum members by name substring (ranked: exact, prefix, + then substring matches). + + For finding an *icon by concept* ("delete", "user", "back") + prefer find_icon — it is synonym-aware. This tool matches member + names literally, which suits other large enums and verifying + specific icon names. Material style variants + (_OUTLINED/_ROUNDED/_SHARP) are collapsed into their base icon; + append a suffix to any base name to use a variant. + + Args: + name: Enum class name (e.g. "Icons", "CupertinoIcons"). + query: Search pattern (e.g. "arrow", "settings", "home"). + limit: Maximum number of results to return. + """ + store = _get_api_store() + members = store.search_enum_members(name, query, limit=limit) + return {"enum": name, "matches": members} + + @mcp.tool() + def enum_has_member(name: str, member: str) -> dict: + """Check if an enum has a specific member. + + Use this to verify that an enum value exists before using it in code. + + Args: + name: Enum class name (e.g. "Icons", "TextAlign"). + member: Member name to check (e.g. "ARROW_BACK", "CENTER"). + """ + store = _get_api_store() + return { + "enum": name, + "member": member, + "exists": store.enum_has_member(name, member), + } + + +# ── Icons ───────────────────────────────────────────────────────────────── + + +if _ICONS_ON: + + @mcp.tool() + def find_icon(query: str, family: Optional[str] = None, limit: int = 10) -> dict: + """Search Material and Cupertino icons by keyword. + + Supports synonym matching (e.g. "user" finds "account_circle"). + + Args: + query: Descriptive keywords (e.g. "back arrow", "settings", "user profile"). + family: Optional icon family filter - "material" or "cupertino". + limit: Maximum number of results to return. + """ + store = _get_icon_store() + return {"icons": store.find(query, family=family, limit=limit)} + + +# ── CLI Help ────────────────────────────────────────────────────────────── + + +if _CLI_ON: + + @mcp.tool() + def get_cli_help(command: Optional[str] = None) -> dict: + """Get Flet CLI usage and options. + + Without arguments, returns an overview of all available commands. + With a command name, returns detailed flags and options. + + Args: + command: Optional command name (e.g. "run", "build", "publish", "create"). + """ + store = _get_api_store() + result = store.get_cli_help(command) + if command is None: + return {"commands": result} + if result is None: + return {"error": f"Unknown command: {command}"} + return result diff --git a/sdk/python/packages/flet-mcp/tests/test_api_store.py b/sdk/python/packages/flet-mcp/tests/test_api_store.py new file mode 100644 index 0000000000..425ae8cee7 --- /dev/null +++ b/sdk/python/packages/flet-mcp/tests/test_api_store.py @@ -0,0 +1,413 @@ +"""Unit tests for ApiStore: docstring compaction, member drill-down, +query filtering, and the text rendering used by the default `get_api` +response. Uses a small synthetic api.json payload — no built data files.""" + +import pytest + +from flet_mcp.api_store import ( + ApiStore, + first_sentence, + render_text, +) + +LONG_DOC = ( + "Pushes a new navigation route to the browser history stack.\n" + "Changing route will fire the on_route_change event.\n\n" + "Example:\n ```python\n page.push_route('/settings')\n ```" +) + +RAW = { + "controls": [ + { + "name": "Page", + "module": "flet.page", + "package": "flet", + "kind": "control", + "summary": "High-level root control.", + "bases": ["AdaptiveControl"], + "properties": [ + { + "name": "bgcolor", + "type": "Optional[ColorValue]", + "default": "None", + "docstring": "Background color of the page. Uses theme otherwise.", + }, + { + "name": "views", + "type": "list[View]", + "default": "field(default_factory=list)", + "docstring": "The list of views.", + }, + ], + "events": [ + { + "name": "on_route_change", + "type": "Optional[EventHandler[RouteChangeEvent[Page]]]", + "default": "None", + "docstring": "Called when page route changes.", + }, + { + "name": "on_login", + "type": "SomethingExotic[Weird]", + "default": "None", + "docstring": "Called on login.", + }, + ], + "methods": [ + { + "name": "push_route", + "params": [{"name": "route"}, {"name": "kwargs"}], + "return_type": "None", + "async": True, + "docstring": LONG_DOC, + }, + ], + }, + { + "name": "AdaptiveControl", + "module": "flet.adaptive", + "package": "flet", + "kind": "control", + "summary": "Base for adaptive controls.", + "bases": [], + "properties": [ + { + "name": "adaptive_border", + "type": "Optional[Border]", + "default": "None", + "docstring": "Platform-adaptive border.", + } + ], + }, + { + "name": "Text", + "module": "flet.controls.core.text", + "package": "flet", + "kind": "control", + "summary": "Display text with a single style.", + "properties": [ + { + "name": "value", + "type": "str", + "default": "''", + "docstring": "The text displayed.", + } + ], + }, + { + "name": "Text", + "module": "flet.controls.core.canvas.text", + "package": "flet", + "kind": "control", + "summary": "Draws :attr:`value` with :attr:`style` at the given point.", + "bases": ["Shape"], + "properties": [ + { + "name": "style", + "type": "Optional[TextStyle]", + "default": "None", + "docstring": "The style to draw with. See :class:`TextStyle`.", + } + ], + }, + { + "name": "Audio", + "module": "flet_audio", + "package": "flet-audio", + "kind": "service", + "summary": "Plays audio.", + "deprecated": {"reason": "Use AudioPlayer instead."}, + "properties": [ + { + "name": "volume", + "type": "float", + "default": "1.0", + "docstring": "Playback volume.", + } + ], + }, + ], + "events": [], + "types": [ + { + "name": "TextStyle", + "module": "flet.types", + "package": "flet", + "docstring": "A style describing how to format text.", + "fields": [ + { + "name": "size", + "type": "Optional[Number]", + "default": "None", + "docstring": "The size of glyphs. In logical pixels.", + }, + { + "name": "weight", + "type": "Optional[FontWeight]", + "default": "None", + "docstring": "The typeface thickness.", + }, + { + "name": "kind", + "type": "Optional[PointerDeviceType]", + "default": "field(default=None, metadata={'data_field': 'k'})", + "docstring": "Device kind.", + }, + ], + } + ], + "enums": [ + { + "name": "TextAlign", + "module": "flet.types", + "package": "flet", + "docstring": "Text alignment.", + "members": [ + { + "name": "LEFT", + "value": "'left'", + "docstring": "Align left. More words here about it.", + } + ], + }, + { + "name": "Icons", + "module": "flet.icons", + "package": "flet", + "kind": "large_enum", + "members": [ + {"name": "BOOKMARK_REMOVE"}, + {"name": "BOOKMARK_REMOVE_OUTLINED"}, + {"name": "GROUP_REMOVE"}, + {"name": "REMOVE"}, + {"name": "REMOVE_CIRCLE"}, + {"name": "REMOVE_OUTLINED"}, + {"name": "REMOVE_ROUNDED"}, + {"name": "REMOVE_SHARP"}, + ], + }, + ], +} + + +@pytest.fixture +def store() -> ApiStore: + s = ApiStore() + s._raw = RAW + s._controls = {c["name"]: c for c in RAW["controls"]} + s._events = {e["name"]: e for e in RAW["events"]} + s._types = {t["name"]: t for t in RAW["types"]} + s._enums = {e["name"]: e for e in RAW["enums"]} + s._by_name = {} + for bucket in ("controls", "types", "events", "enums"): + for e in RAW[bucket]: + s._by_name.setdefault(e["name"], []).append((bucket, e)) + return s + + +# ---------- first_sentence ---------- + + +def test_first_sentence_short_text_unchanged(): + assert first_sentence("Short doc.") == "Short doc." + + +def test_first_sentence_cuts_paragraphs_and_lines(): + assert first_sentence(LONG_DOC) == ( + "Pushes a new navigation route to the browser history stack." + ) + + +def test_first_sentence_caps_length(): + out = first_sentence("x" * 500) + assert len(out) <= 160 and out.endswith("…") + + +# ---------- compaction + note ---------- + + +def test_note_present_and_leading_when_trimmed(store): + hit = store.get("Page") + assert list(hit.keys())[0] == "note" + assert "member=" in hit["note"] and "query=" in hit["note"] + method = hit["methods"][0] + assert method["docstring"] == ( + "Pushes a new navigation route to the browser history stack." + ) + + +def test_no_note_when_nothing_trimmed(store): + hit = store.get("Audio") + assert "note" not in hit + + +# ---------- text rendering ---------- + + +def test_render_text_grammar(store): + text = render_text(store.get("Page")) + assert text.startswith("Page (control) — High-level root control.") + assert "bases: AdaptiveControl" in text + assert " bgcolor: ColorValue? — Background color of the page." in text + assert " views: list[View] = [] — The list of views." in text + # Recognized handler unwrapped; unrecognized falls back to raw type. + assert " on_route_change(RouteChangeEvent) — " in text + assert " on_login: SomethingExotic[Weird] — Called on login." in text + assert " async push_route(route, kwargs) -> None — " in text + # No package line for core flet. + assert "package:" not in text + + +def test_render_text_deprecated_and_package(store): + text = render_text(store.get("Audio")) + assert "DEPRECATED: Use AudioPlayer instead." in text + assert "package: flet-audio" in text + + +def test_render_text_type_fields(store): + # Dataclass types keep members under "fields" — they must render, + # compact, and drill down like control properties. + text = render_text(store.get("TextStyle")) + assert text.startswith("TextStyle (type)") + assert "fields:" in text + assert " size: Number? — The size of glyphs." in text + # field(default=None, metadata=...) is plumbing — no default shown. + assert " kind: PointerDeviceType? — Device kind." in text + + hit = store.get("TextStyle", member="weight") + assert hit["member_kind"] == "field" + assert hit["member"]["docstring"] == "The typeface thickness." + + hit = store.get("TextStyle", query="wei") + assert [e["name"] for e in hit["fields"]] == ["weight"] + + +def test_render_text_enum(store): + text = render_text(store.get("TextAlign")) + assert text.startswith("TextAlign (enum)") + assert " LEFT = 'left' — Align left." in text + + +# ---------- member drill-down ---------- + + +def test_member_full_docstring(store): + hit = store.get("Page", member="push_route") + assert hit["member_kind"] == "method" + assert hit["member"]["docstring"] == LONG_DOC + text = render_text(hit) + assert text.startswith("Page.push_route (method)") + assert "```python" in text # full doc, untrimmed + + +def test_member_unknown_lists_available(store): + hit = store.get("Page", member="nope") + assert "error" in hit + assert "bgcolor" in hit["available_members"] + + +# ---------- query filtering ---------- + + +def test_query_filters_members(store): + hit = store.get("Page", query="route") + names = [e["name"] for e in hit["events"]] + [e["name"] for e in hit["methods"]] + assert names == ["on_route_change", "push_route"] + assert hit["properties"] == [] + assert "matching 'route'" in hit["note"] + + +def test_query_searches_inherited_members(store): + # 'adaptive_border' lives on the base AdaptiveControl, not Page itself. + hit = store.get("Page", query="adaptive_border") + assert hit["properties"] == [] and hit["events"] == [] + block = hit["inherited"][0] + assert block["from"] == "AdaptiveControl" + assert block["properties"][0]["name"] == "adaptive_border" + text = render_text(hit) + assert "from AdaptiveControl:" in text + assert " adaptive_border: Border? — Platform-adaptive border." in text + + +def test_query_no_match_error_mentions_bases(store): + hit = store.get("Page", query="zzz") + assert "error" in hit and "bgcolor" in hit["available_members"] + assert "AdaptiveControl" in hit["error"] + + +def test_member_wins_over_query(store): + hit = store.get("Page", member="push_route", query="zzz") + assert hit["member"]["name"] == "push_route" + + +def test_enum_rejects_member_and_query(store): + assert "error" in store.get("TextAlign", query="left") + assert "error" in store.get("TextAlign", member="LEFT") + + +# ---------- enum member search ranking ---------- + + +def test_enum_search_exact_first_variants_collapsed(store): + out = store.search_enum_members("Icons", "remove", limit=5) + # Exact match first, prefix matches next, substring last; the + # _OUTLINED/_ROUNDED/_SHARP variants of REMOVE are collapsed. + assert out == [ + "REMOVE", + "REMOVE_CIRCLE", + "GROUP_REMOVE", + "BOOKMARK_REMOVE", + ] + + +def test_enum_search_variant_kept_when_base_not_matching(store): + # BOOKMARK_REMOVE_OUTLINED collapses because BOOKMARK_REMOVE matches; + # querying the suffix itself still finds variants. + out = store.search_enum_members("Icons", "outlined", limit=5) + assert "BOOKMARK_REMOVE_OUTLINED" in out or "REMOVE_OUTLINED" in out + + +# ---------- name collisions ---------- + + +def test_bare_name_prefers_non_canvas(store): + hit = store.get("Text") + assert hit["module"] == "flet.controls.core.text" + # The response advertises the shadowed alternative + how to fetch it. + assert "canvas.Text" in hit["note"] + assert list(hit.keys())[0] == "note" + + +def test_qualified_name_reaches_canvas_shape(store): + hit = store.get("canvas.Text") + assert hit["module"] == "flet.controls.core.canvas.text" + assert hit["bases"] == ["Shape"] + + +def test_qualified_name_with_no_match(store): + assert store.get("nowhere.Text") is None + + +# ---------- RST role cleanup ---------- + + +def test_rst_roles_stripped_in_render(store): + text = render_text(store.get("canvas.Text")) + assert "Draws `value` with `style` at the given point." in text + assert ":attr:" not in text and ":class:" not in text + assert "The style to draw with. See `TextStyle`." not in text # trimmed + assert "The style to draw with." in text + + +# ---------- json passthrough / misc ---------- + + +def test_unknown_symbol_none(store): + assert store.get("Nope") is None + + +def test_json_shape_keeps_raw_types(store): + hit = store.get("Page") + assert hit["events"][0]["type"] == ( + "Optional[EventHandler[RouteChangeEvent[Page]]]" + ) diff --git a/sdk/python/packages/flet-mcp/tests/test_icons_store.py b/sdk/python/packages/flet-mcp/tests/test_icons_store.py new file mode 100644 index 0000000000..c5899b8ccd --- /dev/null +++ b/sdk/python/packages/flet-mcp/tests/test_icons_store.py @@ -0,0 +1,113 @@ +"""Unit tests for IconStore: constructor takes plain name lists plus the +icons.json tag metadata (no flet package dependency), ranked +deterministic search, variant collapse, synonym tags, and a golden query +set against the committed Google metadata.""" + +import json +from pathlib import Path + +import pytest + +from flet_mcp.icons_store import IconStore + +MATERIAL = [ + "ADD", + "ADD_A_PHOTO", + "ADD_A_PHOTO_OUTLINED", + "ADD_BOX", + "REMOVE", + "REMOVE_OUTLINED", + "REMOVE_ROUNDED", + "GROUP_REMOVE", + "DELETE", +] +CUPERTINO = ["ADD", "TRASH", "MINUS"] + +META = { + "ADD": {"tags": ["plus", "create", "new"], "popularity": 50000}, + "ADD_BOX": {"tags": ["plus"], "popularity": 900}, + "REMOVE": {"tags": ["minus", "negative", "delete"], "popularity": 20000}, + "DELETE": {"tags": ["trash", "bin", "garbage"], "popularity": 40000}, +} + +ICONS_JSON = ( + Path(__file__).resolve().parents[1] / "src" / "flet_mcp" / "data" / "icons.json" +) + + +def _store() -> IconStore: + return IconStore(material=MATERIAL, cupertino=CUPERTINO, material_meta=META) + + +def test_exact_match_first_and_deterministic(): + out = _store().find("remove", limit=5) + assert out[0] == "Icons.REMOVE" + assert out == _store().find("remove", limit=5) # stable across instances + + +def test_style_variants_collapsed(): + out = _store().find("remove", limit=10) + assert "Icons.REMOVE_OUTLINED" not in out + assert "Icons.REMOVE_ROUNDED" not in out + assert "Icons.GROUP_REMOVE" in out + + +def test_family_filter(): + out = _store().find("add", family="cupertino", limit=5) + assert out == ["CupertinoIcons.ADD"] + + +def test_synonym_tags_resolve_concepts(): + s = _store() + # An exact name match always wins (CupertinoIcons.MINUS / .TRASH), + # with the synonym-tagged Material icon right behind it... + minus = s.find("minus", limit=3) + assert minus[0] == "CupertinoIcons.MINUS" and "Icons.REMOVE" in minus + trash = s.find("trash", limit=3) + assert trash[0] == "CupertinoIcons.TRASH" and "Icons.DELETE" in trash + # ...and within a family, tags + popularity rank the right icon first. + assert s.find("minus", family="material", limit=3)[0] == "Icons.REMOVE" + assert s.find("trash", family="material", limit=3)[0] == "Icons.DELETE" + + +def test_popularity_breaks_ties(): + # "plus" tag matches ADD (popularity 50000) and ADD_BOX (900). + out = _store().find("plus", limit=3) + assert out.index("Icons.ADD") < out.index("Icons.ADD_BOX") + + +def test_variants_inherit_base_tags(): + # REMOVE_OUTLINED has no meta entry of its own; it inherits REMOVE's + # tags so a tag query still finds it when the base is filtered out. + out = _store().find("minus", family="material", limit=10) + assert "Icons.REMOVE" in out + + +def test_no_meta_degrades_to_name_tokens(): + s = IconStore(material=MATERIAL, cupertino=CUPERTINO) + assert s.find("remove", limit=3)[0] == "Icons.REMOVE" + assert s.find("trash", limit=3) == ["CupertinoIcons.TRASH"] + + +# ---------- golden queries against the committed Google metadata ---------- + + +@pytest.mark.skipif(not ICONS_JSON.exists(), reason="icons.json not present") +@pytest.mark.parametrize( + ("query", "expected"), + [ + ("minus", "Icons.REMOVE"), + ("plus", "Icons.ADD"), + ("trash", "Icons.DELETE"), + ("garbage", "Icons.DELETE"), + ("magnify", "Icons.SEARCH"), + ("gear", "Icons.SETTINGS"), + ("pencil", "Icons.EDIT"), + ("user", "Icons.PERSON"), + ], +) +def test_golden_queries(query: str, expected: str): + meta = json.loads(ICONS_JSON.read_text(encoding="utf-8"))["material"] + store = IconStore(material=list(meta), cupertino=[], material_meta=meta) + top3 = store.find(query, family="material", limit=3) + assert expected in top3, f"{query!r} -> {top3}" diff --git a/sdk/python/packages/flet-permission-handler/CHANGELOG.md b/sdk/python/packages/flet-permission-handler/CHANGELOG.md index 452535c259..85895490bf 100644 --- a/sdk/python/packages/flet-permission-handler/CHANGELOG.md +++ b/sdk/python/packages/flet-permission-handler/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## 0.86.0 + +### Bug fixes + +* Removed platform restriction - `PermissionHandler` can now be used on `PagePlatform.ANDROID_TV`. Not officially supported by the underlying flutter `permission_handler` package, but most functionality works reliably across a wide range of Android TV builds. ([#6667](https://github.com/flet-dev/flet/pull/6667)). + ## 0.80.0 ## Added diff --git a/sdk/python/packages/flet-permission-handler/src/flet_permission_handler/permission_handler.py b/sdk/python/packages/flet-permission-handler/src/flet_permission_handler/permission_handler.py index 06f8d7a169..ec1d6571cf 100644 --- a/sdk/python/packages/flet-permission-handler/src/flet_permission_handler/permission_handler.py +++ b/sdk/python/packages/flet-permission-handler/src/flet_permission_handler/permission_handler.py @@ -27,6 +27,7 @@ def before_update(self): or self.page.platform in [ ft.PagePlatform.ANDROID, + ft.PagePlatform.ANDROID_TV, ft.PagePlatform.IOS, ft.PagePlatform.WINDOWS, ] diff --git a/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/pubspec.yaml b/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/pubspec.yaml index eb1322748e..5ce4ae2f4d 100644 --- a/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/pubspec.yaml +++ b/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: flutter: sdk: flutter - flutter_secure_storage: 10.0.0 + flutter_secure_storage: 10.3.1 flet: path: ../../../../../../../packages/flet diff --git a/sdk/python/packages/flet-spinkit/CHANGELOG.md b/sdk/python/packages/flet-spinkit/CHANGELOG.md index 621a0dbdaa..e4ad0d7398 100644 --- a/sdk/python/packages/flet-spinkit/CHANGELOG.md +++ b/sdk/python/packages/flet-spinkit/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog -## 0.1.0 +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## 0.86.0 - Initial release. diff --git a/sdk/python/packages/flet-spinkit/src/flutter/flet_spinkit/lib/src/boot_screen.dart b/sdk/python/packages/flet-spinkit/src/flutter/flet_spinkit/lib/src/boot_screen.dart new file mode 100644 index 0000000000..43cb934158 --- /dev/null +++ b/sdk/python/packages/flet-spinkit/src/flutter/flet_spinkit/lib/src/boot_screen.dart @@ -0,0 +1,151 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +import 'spinkit.dart'; + +/// Canonical `SpinKit…` control type names, used to resolve the `spinner` +/// option (which is written without the `SpinKit` prefix, e.g. `Wave`). +const _spinKitTypes = [ + "SpinKitRotatingPlain", + "SpinKitDoubleBounce", + "SpinKitWave", + "SpinKitWanderingCubes", + "SpinKitFadingFour", + "SpinKitFadingCube", + "SpinKitPulse", + "SpinKitChasingDots", + "SpinKitThreeBounce", + "SpinKitCircle", + "SpinKitCubeGrid", + "SpinKitFadingCircle", + "SpinKitRotatingCircle", + "SpinKitFoldingCube", + "SpinKitPumpingHeart", + "SpinKitHourGlass", + "SpinKitPouringHourGlass", + "SpinKitPouringHourGlassRefined", + "SpinKitFadingGrid", + "SpinKitRing", + "SpinKitRipple", + "SpinKitDualRing", + "SpinKitSpinningCircle", + "SpinKitSpinningLines", + "SpinKitSquareCircle", + "SpinKitThreeInOut", + "SpinKitDancingSquare", + "SpinKitPianoWave", + "SpinKitPulsingGrid", + "SpinKitWaveSpinner", +]; + +const _defaultSpinner = "SpinKitWanderingCubes"; + +/// Resolves a `spinner` option value to a canonical `SpinKit…` type string. +/// +/// Accepts the short control name (e.g. `WanderingCubes`, `Wave`) — matching +/// the Python control classes — case-insensitively. The full `SpinKit…` form +/// is also accepted. Unknown values fall back to [_defaultSpinner]. +String _resolveSpinnerType(String? name) { + var key = (name ?? "").trim().toLowerCase(); + if (key.startsWith("spinkit")) { + key = key.substring("spinkit".length); + } + if (key.isEmpty) return _defaultSpinner; + for (final type in _spinKitTypes) { + if (type.toLowerCase() == "spinkit$key") return type; + } + return _defaultSpinner; +} + +/// A boot screen that shows an animated `flutter_spinkit` loader while a Flet +/// app boots. Selected with `[tool.flet.boot_screen] name = "spinkit"`. +/// +/// Supported [options] (all optional): +/// - `theme_mode`: `auto` (default) | `light` | `dark` +/// - `bgcolor_light`, `bgcolor_dark` +/// - `spinner`: SpinKit animation name without the `SpinKit` prefix +/// (e.g. `Wave`, `FadingCube`); defaults to `WanderingCubes` +/// - `spinner_color_light`, `spinner_color_dark` +/// - `spinner_size` +/// - `text_color_light`, `text_color_dark` +/// - `prepare_message`, `startup_message` (empty/absent → no message) +class SpinKitBootScreen extends StatelessWidget { + final Map options; + final ValueListenable status; + + const SpinKitBootScreen( + {super.key, required this.options, required this.status}); + + bool _isDark(BuildContext context) { + switch ((options["theme_mode"] as String?)?.toLowerCase()) { + case "dark": + return true; + case "light": + return false; + default: + return MediaQuery.platformBrightnessOf(context) == Brightness.dark; + } + } + + Color? _color(String key, bool dark) { + final value = options[dark ? "${key}_dark" : "${key}_light"] as String?; + return HexColor.fromString(null, value); + } + + @override + Widget build(BuildContext context) { + final dark = _isDark(context); + // Follow Flet's default theme (not the bare bootstrap MaterialApp theme) so + // unset colors match what the app itself will use. + final theme = + parseTheme(null, context, dark ? Brightness.dark : Brightness.light); + final bgcolor = _color("bgcolor", dark); + final spinnerColor = + _color("spinner_color", dark) ?? theme.colorScheme.primary; + final textColor = _color("text_color", dark) ?? theme.colorScheme.onSurface; + final size = parseDouble(options["spinner_size"], 60)!; + final type = _resolveSpinnerType(options["spinner"] as String?); + + return Theme( + data: theme, + child: ValueListenableBuilder( + valueListenable: status, + builder: (context, boot, _) { + final Widget child; + if (boot.error != null) { + child = Padding( + padding: const EdgeInsets.all(24), + child: Text( + boot.error!, + textAlign: TextAlign.center, + style: TextStyle(color: theme.colorScheme.error), + ), + ); + } else { + final message = boot.stage == BootStage.preparing + ? options["prepare_message"] as String? + : options["startup_message"] as String?; + final children = [ + createSpinKit(type, color: spinnerColor, size: size), + ]; + if (message != null && message.isNotEmpty) { + children.add(const SizedBox(height: 16)); + children.add(Text(message, style: TextStyle(color: textColor))); + } + child = Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + return Scaffold( + // null → Flet theme's scaffold background. + backgroundColor: bgcolor, + body: Center(child: child), + ); + }, + ), + ); + } +} diff --git a/sdk/python/packages/flet-spinkit/src/flutter/flet_spinkit/lib/src/extension.dart b/sdk/python/packages/flet-spinkit/src/flutter/flet_spinkit/lib/src/extension.dart index 50f1e02500..5aabd4e516 100644 --- a/sdk/python/packages/flet-spinkit/src/flutter/flet_spinkit/lib/src/extension.dart +++ b/sdk/python/packages/flet-spinkit/src/flutter/flet_spinkit/lib/src/extension.dart @@ -1,9 +1,19 @@ import 'package:flet/flet.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'boot_screen.dart'; import 'spinkit.dart'; class Extension extends FletExtension { + @override + Widget? createBootScreen(String name, Map options, + ValueListenable status) { + return name == "spinkit" + ? SpinKitBootScreen(options: options, status: status) + : null; + } + @override Widget? createWidget(Key? key, Control control) { switch (control.type) { diff --git a/sdk/python/packages/flet-spinkit/src/flutter/flet_spinkit/lib/src/spinkit.dart b/sdk/python/packages/flet-spinkit/src/flutter/flet_spinkit/lib/src/spinkit.dart index e1d93a8753..1d7e823c69 100644 --- a/sdk/python/packages/flet-spinkit/src/flutter/flet_spinkit/lib/src/spinkit.dart +++ b/sdk/python/packages/flet-spinkit/src/flutter/flet_spinkit/lib/src/spinkit.dart @@ -27,234 +27,230 @@ class _SpinKitControlState extends State { final waveType = parseEnum(SpinKitWaveType.values, widget.control.getString("wave_type"), SpinKitWaveType.start)!; - Widget spinner; - - switch (widget.control.type) { - case "SpinKitRotatingPlain": - spinner = SpinKitRotatingPlain( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - ); - break; - case "SpinKitDoubleBounce": - spinner = SpinKitDoubleBounce( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 2000), - ); - break; - case "SpinKitWave": - spinner = SpinKitWave( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - itemCount: itemCount ?? 5, - type: waveType, - ); - break; - case "SpinKitWanderingCubes": - spinner = SpinKitWanderingCubes( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1800), - ); - break; - case "SpinKitFadingFour": - spinner = SpinKitFadingFour( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - ); - break; - case "SpinKitFadingCube": - spinner = SpinKitFadingCube( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - ); - break; - case "SpinKitPulse": - spinner = SpinKitPulse( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1000), - ); - break; - case "SpinKitChasingDots": - spinner = SpinKitChasingDots( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 2000), - ); - break; - case "SpinKitThreeBounce": - spinner = SpinKitThreeBounce( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1400), - ); - break; - case "SpinKitCircle": - spinner = SpinKitCircle( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - ); - break; - case "SpinKitCubeGrid": - spinner = SpinKitCubeGrid( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - ); - break; - case "SpinKitFadingCircle": - spinner = SpinKitFadingCircle( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - ); - break; - case "SpinKitRotatingCircle": - spinner = SpinKitRotatingCircle( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - ); - break; - case "SpinKitFoldingCube": - spinner = SpinKitFoldingCube( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 2400), - ); - break; - case "SpinKitPumpingHeart": - spinner = SpinKitPumpingHeart( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1000), - ); - break; - case "SpinKitHourGlass": - spinner = SpinKitHourGlass( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - ); - break; - case "SpinKitPouringHourGlass": - spinner = SpinKitPouringHourGlass( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 2400), - ); - break; - case "SpinKitPouringHourGlassRefined": - spinner = SpinKitPouringHourGlassRefined( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 2400), - ); - break; - case "SpinKitFadingGrid": - spinner = SpinKitFadingGrid( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - ); - break; - case "SpinKitRing": - spinner = SpinKitRing( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - lineWidth: lineWidth ?? 7.0, - ); - break; - case "SpinKitRipple": - spinner = SpinKitRipple( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1800), - borderWidth: borderWidth ?? 6.0, - ); - break; - case "SpinKitDualRing": - spinner = SpinKitDualRing( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - lineWidth: lineWidth ?? 7.0, - ); - break; - case "SpinKitSpinningCircle": - spinner = SpinKitSpinningCircle( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - ); - break; - case "SpinKitSpinningLines": - spinner = SpinKitSpinningLines( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - lineWidth: lineWidth ?? 2.0, - ); - break; - case "SpinKitSquareCircle": - spinner = SpinKitSquareCircle( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 500), - ); - break; - case "SpinKitThreeInOut": - spinner = SpinKitThreeInOut( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1500), - ); - break; - case "SpinKitDancingSquare": - spinner = SpinKitDancingSquare( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - ); - break; - case "SpinKitPianoWave": - spinner = SpinKitPianoWave( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - itemCount: itemCount ?? 5, - ); - break; - case "SpinKitPulsingGrid": - spinner = SpinKitPulsingGrid( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - ); - break; - case "SpinKitWaveSpinner": - spinner = SpinKitWaveSpinner( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - ); - break; - default: - spinner = SpinKitRotatingCircle( - color: color, - size: size, - duration: duration ?? const Duration(milliseconds: 1200), - ); - } + final spinner = createSpinKit( + widget.control.type, + color: color, + size: size, + duration: duration, + lineWidth: lineWidth, + borderWidth: borderWidth, + itemCount: itemCount, + waveType: waveType, + ); return LayoutControl(control: widget.control, child: spinner); } } + +/// Builds a `flutter_spinkit` spinner widget for the given [type] (a +/// `SpinKit…` control type string). +/// +/// Shared by [SpinKitControl] and the SpinKit boot screen. Falls back to +/// [SpinKitRotatingCircle] for unknown types. Per-spinner defaults match the +/// `flutter_spinkit` recommendations. +Widget createSpinKit( + String type, { + required Color color, + required double size, + Duration? duration, + double? lineWidth, + double? borderWidth, + int? itemCount, + SpinKitWaveType waveType = SpinKitWaveType.start, +}) { + switch (type) { + case "SpinKitRotatingPlain": + return SpinKitRotatingPlain( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + ); + case "SpinKitDoubleBounce": + return SpinKitDoubleBounce( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 2000), + ); + case "SpinKitWave": + return SpinKitWave( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + itemCount: itemCount ?? 5, + type: waveType, + ); + case "SpinKitWanderingCubes": + return SpinKitWanderingCubes( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1800), + ); + case "SpinKitFadingFour": + return SpinKitFadingFour( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + ); + case "SpinKitFadingCube": + return SpinKitFadingCube( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + ); + case "SpinKitPulse": + return SpinKitPulse( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1000), + ); + case "SpinKitChasingDots": + return SpinKitChasingDots( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 2000), + ); + case "SpinKitThreeBounce": + return SpinKitThreeBounce( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1400), + ); + case "SpinKitCircle": + return SpinKitCircle( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + ); + case "SpinKitCubeGrid": + return SpinKitCubeGrid( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + ); + case "SpinKitFadingCircle": + return SpinKitFadingCircle( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + ); + case "SpinKitRotatingCircle": + return SpinKitRotatingCircle( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + ); + case "SpinKitFoldingCube": + return SpinKitFoldingCube( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 2400), + ); + case "SpinKitPumpingHeart": + return SpinKitPumpingHeart( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1000), + ); + case "SpinKitHourGlass": + return SpinKitHourGlass( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + ); + case "SpinKitPouringHourGlass": + return SpinKitPouringHourGlass( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 2400), + ); + case "SpinKitPouringHourGlassRefined": + return SpinKitPouringHourGlassRefined( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 2400), + ); + case "SpinKitFadingGrid": + return SpinKitFadingGrid( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + ); + case "SpinKitRing": + return SpinKitRing( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + lineWidth: lineWidth ?? 7.0, + ); + case "SpinKitRipple": + return SpinKitRipple( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1800), + borderWidth: borderWidth ?? 6.0, + ); + case "SpinKitDualRing": + return SpinKitDualRing( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + lineWidth: lineWidth ?? 7.0, + ); + case "SpinKitSpinningCircle": + return SpinKitSpinningCircle( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + ); + case "SpinKitSpinningLines": + return SpinKitSpinningLines( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + lineWidth: lineWidth ?? 2.0, + ); + case "SpinKitSquareCircle": + return SpinKitSquareCircle( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 500), + ); + case "SpinKitThreeInOut": + return SpinKitThreeInOut( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1500), + ); + case "SpinKitDancingSquare": + return SpinKitDancingSquare( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + ); + case "SpinKitPianoWave": + return SpinKitPianoWave( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + itemCount: itemCount ?? 5, + ); + case "SpinKitPulsingGrid": + return SpinKitPulsingGrid( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + ); + case "SpinKitWaveSpinner": + return SpinKitWaveSpinner( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + ); + default: + return SpinKitRotatingCircle( + color: color, + size: size, + duration: duration ?? const Duration(milliseconds: 1200), + ); + } +} diff --git a/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_app.py b/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_app.py index 2c920c5b02..1bbde15bde 100644 --- a/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_app.py +++ b/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_app.py @@ -96,6 +96,11 @@ def __init__( self.__upload_endpoint_path = upload_endpoint_path self.__secret_key = secret_key + # DataChannel mux registry keyed by channel_id minted on the Dart + # side. Populated lazily on the first Control.get_data_channel(id) + # call. Frames for unknown ids are silently dropped. + self._data_channels: dict[int, Any] = {} + app_id = self.__id weakref.finalize( self, lambda: logger.info(f"FletApp was garbage collected: {app_id}") @@ -214,6 +219,11 @@ async def __receive_loop(self): """ Receive binary frames from WebSocket and dispatch decoded client messages. + Wire format: each WebSocket binary frame is one packet — + `[type:u8][payload]`. type=0x00 is a MsgPack-encoded Flet protocol + frame; type=0x01 is a raw DataChannel frame + (`[channel_id:u32 LE][bytes]`). + On disconnect/error, terminates send loop via queue sentinel when a session is active. """ @@ -222,9 +232,23 @@ async def __receive_loop(self): try: while True: data = await self.__websocket.receive_bytes() - await self.__on_message( - msgpack.unpackb(data, ext_hook=decode_ext_from_msgpack) - ) + if not data: + continue + ptype = data[0] + if ptype == 0x00: + await self.__on_message( + msgpack.unpackb(data[1:], ext_hook=decode_ext_from_msgpack) + ) + elif ptype == 0x01: + if len(data) < 5: + logger.debug("Dropping malformed data-channel frame.") + continue + channel_id = int.from_bytes(data[1:5], "little", signed=False) + channel = self._data_channels.get(channel_id) + if channel is not None: + channel._deliver(data[5:]) + else: + logger.debug("Dropping packet with unknown type 0x%02x", ptype) except Exception as e: if not isinstance(e, WebSocketDisconnect): logger.warning(f"Receive loop error: {e}", exc_info=True) @@ -383,16 +407,42 @@ def send_message(self, message: ClientMessage): """ Serialize and enqueue a server message for transport to the client. + Wire format: one packet per `send_bytes` call — + `[0x00][msgpack body]`. WebSocket preserves message boundaries so + no length prefix is needed. + Args: message: Outbound protocol message. """ transport_log.debug(f"send_message: {message}") - m = msgpack.packb( + body = msgpack.packb( [message.action, message.body], default=configure_encode_object_for_msgpack(BaseControl), ) - self.__send_queue.put_nowait(m) + self.__send_queue.put_nowait(b"\x00" + body) + + def send_data_channel_frame(self, channel_id: int, payload: bytes) -> None: + """Send a raw DataChannel frame `[0x01][channel_id:u32 LE][bytes]` + over the WebSocket. Called by `_ProtocolMuxedDataChannel.send`.""" + if self.__send_queue is None: + return # client disconnected — the frame is moot + header = b"\x01" + channel_id.to_bytes(4, "little", signed=False) + self.__send_queue.put_nowait(header + payload) + + def data_channel_for(self, channel_id: int): + """Resolve or construct the muxed DataChannel for `channel_id`.""" + from flet.data_channel import _ProtocolMuxedDataChannel + + existing = self._data_channels.get(channel_id) + if existing is not None: + return existing + channel = _ProtocolMuxedDataChannel(channel_id, self) + self._data_channels[channel_id] = channel + return channel + + def unregister_data_channel(self, channel_id: int) -> None: + self._data_channels.pop(channel_id, None) def get_upload_url(self, file_name: str, expires: int) -> str: """ diff --git a/sdk/python/packages/flet-web/src/flet_web/patch_index.py b/sdk/python/packages/flet-web/src/flet_web/patch_index.py index af8bca4dcc..0e206cd5a3 100644 --- a/sdk/python/packages/flet-web/src/flet_web/patch_index.py +++ b/sdk/python/packages/flet-web/src/flet_web/patch_index.py @@ -15,6 +15,7 @@ def patch_index_html( pyodide: bool = False, pyodide_pre: bool = False, pyodide_script_path: str = "", + pyodide_version: Optional[str] = None, web_renderer: WebRenderer = WebRenderer.AUTO, route_url_strategy: RouteUrlStrategy = RouteUrlStrategy.PATH, no_cdn: bool = False, @@ -61,6 +62,25 @@ def patch_index_html( app_config.append(f"flet.micropipIncludePre = {str(pyodide_pre).lower()};") app_config.append(f'flet.pythonModuleName = "{module_name}";') + # Pin the Pyodide runtime URL for this build. The web client used to fall + # back to a hardcoded CDN URL when not in no-cdn mode; with multi-version + # support that constant is gone, so we always inject the URL here. + # + # `.mjs` is the ES-module variant; python-worker.js (a module worker) + # loads it via dynamic `import()`. We can no longer use `.js` because + # Pyodide >= 0.29 throws "Classic web workers are not supported" inside + # any worker that has `importScripts` available — only classic workers + # have it. All supported Pyodide versions (0.27.7 / 0.29.4 / 314.0.0) + # ship `pyodide.mjs`. + if pyodide_version: + if no_cdn: + pyodide_url = "pyodide/pyodide.mjs" + else: + pyodide_url = ( + f"https://cdn.jsdelivr.net/pyodide/v{pyodide_version}/full/pyodide.mjs" + ) + app_config.append(f'flet.pyodideUrl="{pyodide_url}";') + app_config.append(f"flet.noCdn={str(no_cdn).lower()};") app_config.append(f'flet.webRenderer="{web_renderer.value}";') app_config.append(f'flet.routeUrlStrategy="{route_url_strategy.value}";') diff --git a/sdk/python/packages/flet-webview/pyproject.toml b/sdk/python/packages/flet-webview/pyproject.toml index e9b72025a1..4f0d34a9ad 100644 --- a/sdk/python/packages/flet-webview/pyproject.toml +++ b/sdk/python/packages/flet-webview/pyproject.toml @@ -8,6 +8,7 @@ license = "Apache-2.0" requires-python = ">=3.10" dependencies = [ "flet", + "typing-extensions; python_version < '3.11'", ] [project.urls] diff --git a/sdk/python/packages/flet-webview/src/flet_webview/webview.py b/sdk/python/packages/flet-webview/src/flet_webview/webview.py index 91da17d8df..c35fbbda3e 100644 --- a/sdk/python/packages/flet-webview/src/flet_webview/webview.py +++ b/sdk/python/packages/flet-webview/src/flet_webview/webview.py @@ -1,6 +1,10 @@ +import sys from typing import Optional -from typing_extensions import Self +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self import flet as ft from flet_webview.types import ( diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/clear.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/clear.png new file mode 100644 index 0000000000..bf53d81d71 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/clear.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/fit_contain.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/fit_contain.png new file mode 100644 index 0000000000..33972fcc94 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/fit_contain.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_encoded.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_encoded.png new file mode 100644 index 0000000000..cac7eeeeaf Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_encoded.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_encoded_jpg_file.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_encoded_jpg_file.png new file mode 100644 index 0000000000..70e7b7902c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_encoded_jpg_file.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_encoded_png_file.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_encoded_png_file.png new file mode 100644 index 0000000000..2a9536effe Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_encoded_png_file.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_numpy_rgb.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_numpy_rgb.png new file mode 100644 index 0000000000..9a01168522 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_numpy_rgb.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_pil_alpha.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_pil_alpha.png new file mode 100644 index 0000000000..017fc19cf5 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_pil_alpha.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_rgba.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_rgba.png new file mode 100644 index 0000000000..cac7eeeeaf Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/render_rgba.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/sequential_renders.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/sequential_renders.png new file mode 100644 index 0000000000..cac7eeeeaf Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/raw_image/sequential_renders.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/test_raw_image.py b/sdk/python/packages/flet/integration_tests/controls/core/test_raw_image.py new file mode 100644 index 0000000000..c633b873cb --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/core/test_raw_image.py @@ -0,0 +1,178 @@ +import io +from pathlib import Path +from typing import Optional + +import pytest + +import flet as ft +import flet.testing as ftt + +assets_dir = Path(__file__).resolve().parent / "../../assets" + + +def gradient_rgba(width: int, height: int) -> bytes: + """ + A deterministic opaque test pattern: red rises left to right, + green top to bottom, constant blue. + """ + pixels = bytearray(width * height * 4) + i = 0 + for y in range(height): + g = y * 255 // (height - 1) + for x in range(width): + pixels[i] = x * 255 // (width - 1) + pixels[i + 1] = g + pixels[i + 2] = 64 + pixels[i + 3] = 255 + i += 4 + return bytes(pixels) + + +async def show_raw_image( + flet_app: ftt.FletTestApp, + raw_image: ft.RawImage, + host: Optional[ft.Control] = None, +) -> ft.Screenshot: + """ + Puts `raw_image` (or `host` containing it) on a clean page, wrapped in + a Screenshot, and waits for the widget to mount and open its data + channel so subsequent `render` calls can complete. + """ + flet_app.page.clean() + await flet_app.tester.pump_and_settle() + screenshot = ft.Screenshot(host or raw_image) + flet_app.page.add(screenshot) + await flet_app.tester.pump_and_settle() + return screenshot + + +async def assert_raw_image_screenshot( + flet_app: ftt.FletTestApp, name: str, screenshot: ft.Screenshot +): + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + name, + await screenshot.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_render_rgba(flet_app: ftt.FletTestApp, request): + ri = ft.RawImage(width=100, height=80) + screenshot = await show_raw_image(flet_app, ri) + await ri.render_rgba(100, 80, gradient_rgba(100, 80)) + await assert_raw_image_screenshot(flet_app, request.node.name, screenshot) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_render_pil_alpha(flet_app: ftt.FletTestApp, request): + PILImage = pytest.importorskip("PIL.Image") + from PIL import ImageDraw + + # A semi-transparent white disc: correct premultiplication shows an + # evenly lightened green circle; skipping it would wash out the whole + # square (straight-alpha values uploaded as premultiplied read too + # bright). + img = PILImage.new("RGBA", (100, 100), (0, 0, 0, 0)) + draw = ImageDraw.Draw(img) + draw.ellipse((10, 10, 90, 90), fill=(255, 255, 255, 128)) + + ri = ft.RawImage(width=100, height=100) + screenshot = await show_raw_image( + flet_app, + ri, + host=ft.Container(ri, bgcolor=ft.Colors.GREEN, padding=10), + ) + await ri.render(img) + await assert_raw_image_screenshot(flet_app, request.node.name, screenshot) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_render_encoded(flet_app: ftt.FletTestApp, request): + PILImage = pytest.importorskip("PIL.Image") + buf = io.BytesIO() + PILImage.frombuffer("RGBA", (100, 80), gradient_rgba(100, 80)).save( + buf, format="PNG" + ) + + ri = ft.RawImage(width=100, height=80) + screenshot = await show_raw_image(flet_app, ri) + await ri.render_encoded(buf.getvalue()) + await assert_raw_image_screenshot(flet_app, request.node.name, screenshot) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_render_encoded_png_file(flet_app: ftt.FletTestApp, request): + # A regular PNG file straight from disk — no Pillow involved. + ri = ft.RawImage(width=100, height=100, fit=ft.BoxFit.CONTAIN) + screenshot = await show_raw_image(flet_app, ri) + await ri.render_encoded((assets_dir / "minion.png").read_bytes()) + await assert_raw_image_screenshot(flet_app, request.node.name, screenshot) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_render_encoded_jpg_file(flet_app: ftt.FletTestApp, request): + # A regular JPEG file straight from disk — no Pillow involved. + ri = ft.RawImage(width=100, height=100, fit=ft.BoxFit.CONTAIN) + screenshot = await show_raw_image(flet_app, ri) + await ri.render_encoded((assets_dir / "141-50x50.jpg").read_bytes()) + await assert_raw_image_screenshot(flet_app, request.node.name, screenshot) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_render_numpy_rgb(flet_app: ftt.FletTestApp, request): + np = pytest.importorskip("numpy") + # RGB input (no alpha channel) is padded to opaque RGBA. + arr = np.zeros((60, 90, 3), dtype=np.uint8) + arr[:30, :, 0] = 255 + arr[30:, :, 2] = 255 + + ri = ft.RawImage(width=90, height=60) + screenshot = await show_raw_image(flet_app, ri) + await ri.render(arr) + await assert_raw_image_screenshot(flet_app, request.node.name, screenshot) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_fit_contain(flet_app: ftt.FletTestApp, request): + # A 20x10 frame inscribed into a 100x100 box. + ri = ft.RawImage( + width=100, + height=100, + fit=ft.BoxFit.CONTAIN, + filter_quality=ft.FilterQuality.NONE, + ) + screenshot = await show_raw_image( + flet_app, + ri, + host=ft.Container(ri, bgcolor=ft.Colors.BLUE_GREY_100), + ) + await ri.render_rgba(20, 10, gradient_rgba(20, 10)) + await assert_raw_image_screenshot(flet_app, request.node.name, screenshot) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_clear(flet_app: ftt.FletTestApp, request): + ri = ft.RawImage(width=100, height=80) + screenshot = await show_raw_image( + flet_app, + ri, + host=ft.Container(ri, bgcolor=ft.Colors.AMBER_100), + ) + await ri.render_rgba(100, 80, gradient_rgba(100, 80)) + await ri.clear() + await assert_raw_image_screenshot(flet_app, request.node.name, screenshot) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_sequential_renders(flet_app: ftt.FletTestApp, request): + # Backpressure round-trip: each render resolves on the client's ack, + # so a burst of awaited renders must complete without deadlocking and + # leave the last frame on screen. + ri = ft.RawImage(width=100, height=80) + screenshot = await show_raw_image(flet_app, ri) + solid = bytes([0, 0, 255, 255]) * (100 * 80) + for _ in range(3): + await ri.render_rgba(100, 80, solid) + await ri.render_rgba(100, 80, gradient_rgba(100, 80)) + await assert_raw_image_screenshot(flet_app, request.node.name, screenshot) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_date_picker/locale.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_date_picker/locale.png index 52c139f4a8..d7cc84a8d0 100644 Binary files a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_date_picker/locale.png and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_date_picker/locale.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_picker/locale.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_picker/locale.png index 48c185d151..26ece416de 100644 Binary files a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_picker/locale.png and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_picker/locale.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_range_picker/locale.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_range_picker/locale.png index ac6c92a984..303b513220 100644 Binary files a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_range_picker/locale.png and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_range_picker/locale.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/apps/test_router.py b/sdk/python/packages/flet/integration_tests/examples/apps/test_router.py index 92ede9a6cd..f6f3c53287 100644 --- a/sdk/python/packages/flet/integration_tests/examples/apps/test_router.py +++ b/sdk/python/packages/flet/integration_tests/examples/apps/test_router.py @@ -6,7 +6,6 @@ from examples.apps.router.app_drawer import main as app_drawer from examples.apps.router.auth_dialog import main as auth_dialog from examples.apps.router.auth_page import main as auth_page -from examples.apps.router.basic import main as basic from examples.apps.router.dynamic_segments import main as dynamic_segments from examples.apps.router.featured import main as featured from examples.apps.router.featured_views import main as featured_views @@ -18,6 +17,7 @@ from examples.apps.router.nested_routes import main as nested_routes from examples.apps.router.prefix_routes import main as prefix_routes from examples.apps.router.recursive_routes import main as recursive_routes +from examples.apps.router.routing import main as basic from examples.apps.router.runtime_routes import main as runtime_routes from examples.apps.router.splats import main as splats diff --git a/sdk/python/packages/flet/integration_tests/examples/apps/test_todo.py b/sdk/python/packages/flet/integration_tests/examples/apps/test_todo.py index abd2fc4f15..28255e3bfe 100644 --- a/sdk/python/packages/flet/integration_tests/examples/apps/test_todo.py +++ b/sdk/python/packages/flet/integration_tests/examples/apps/test_todo.py @@ -1,6 +1,6 @@ import pytest -import examples.apps.todo.basic.main as todo_basic +import examples.apps.todo.main as todo_basic import flet as ft import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/raw_image/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/raw_image/image_for_docs.png new file mode 100644 index 0000000000..8ec1d3616c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/raw_image/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_container.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_container.py index f16da8e81d..a56bd4ac04 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_container.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_container.py @@ -1,9 +1,13 @@ import pytest -import examples.controls.core.container.nested_themes_1.main as nested_themes_1 -import examples.controls.core.container.nested_themes_2.main as nested_themes_2 import examples.controls.core.container.size_aware.main as size_aware import flet.testing as ftt +from examples.controls.core.container.inherited_and_overridden_theme import ( + main as nested_themes_1, +) +from examples.controls.core.container.page_dark_and_light_themes import ( + main as nested_themes_2, +) @pytest.mark.parametrize( diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_hero.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_hero.py index 78c4c7742e..2f9aabc20d 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_hero.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_hero.py @@ -2,7 +2,7 @@ import flet as ft import flet.testing as ftt -from examples.controls.core.hero.basic import main as basic +from examples.controls.core.hero.hero import main as basic @pytest.mark.parametrize( diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_pagelet.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_pagelet.py index 0e1cccbcac..415e3ed9d0 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_pagelet.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_pagelet.py @@ -2,7 +2,7 @@ import flet as ft import flet.testing as ftt -from examples.controls.core.pagelet.basic.main import main as basic +from examples.controls.core.pagelet.pagelet.main import main as basic @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_placeholder.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_placeholder.py index fbd33b72ea..c09834faba 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_placeholder.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_placeholder.py @@ -2,7 +2,7 @@ import flet as ft import flet.testing as ftt -from examples.controls.core.placeholder.basic.main import main as basic +from examples.controls.core.placeholder.placeholder.main import main as basic @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_raw_image.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_raw_image.py new file mode 100644 index 0000000000..090d3cdbe4 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_raw_image.py @@ -0,0 +1,21 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.core.raw_image.plasma.main import plasma_frame + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + raw_image = ft.RawImage(width=320, height=200) + screenshot = ft.Screenshot(raw_image) + flet_app_function.page.add(screenshot) + await flet_app_function.tester.pump_and_settle() + # A plasma frame at a fixed timestamp is fully deterministic. + await raw_image.render(plasma_frame(320, 200, 2.5), premultiplied=True) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + request.node.name, + await screenshot.capture(pixel_ratio=flet_app_function.screenshots_pixel_ratio), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_responsive_row.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_responsive_row.py index f148e6b155..064570d1c5 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_responsive_row.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_responsive_row.py @@ -4,10 +4,10 @@ import flet as ft import flet.testing as ftt -from examples.controls.core.responsive_row.basic.main import main as basic from examples.controls.core.responsive_row.custom_breakpoint.main import ( main as custom_breakpoint, ) +from examples.controls.core.responsive_row.responsive_row.main import main as basic @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_rotated_box.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_rotated_box.py index 88f6717431..75391519b5 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_rotated_box.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_rotated_box.py @@ -1,7 +1,7 @@ import pytest import flet.testing as ftt -from examples.controls.core.rotated_box.basic.main import main as basic +from examples.controls.core.rotated_box.rotated_box.main import main as basic @pytest.mark.parametrize( diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_shimmer.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_shimmer.py index bf04598528..0da0b7515b 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_shimmer.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_shimmer.py @@ -1,9 +1,11 @@ import pytest -import examples.controls.core.shimmer.basic_placeholder.main as basic_placeholder import examples.controls.core.shimmer.custom_gradient.main as custom_gradient import flet as ft import flet.testing as ftt +from examples.controls.core.shimmer.shimmer_basic_placeholder import ( + main as basic_placeholder, +) @pytest.mark.skip(reason="The test is flaky on CI") diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_vertical_divider.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_vertical_divider.py index f5cd7a9072..34c021b7bc 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_vertical_divider.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_vertical_divider.py @@ -1,6 +1,6 @@ import pytest -import examples.controls.core.vertical_divider.basic.main as basic +import examples.controls.core.vertical_divider.vertical_divider.main as basic import flet as ft import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_timer_picker.py b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_timer_picker.py index 58e4b96be8..2e550aa236 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_timer_picker.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_timer_picker.py @@ -1,8 +1,10 @@ import pytest -import examples.controls.cupertino.cupertino_timer_picker.basic.main as basic import flet as ft import flet.testing as ftt +from examples.controls.cupertino.cupertino_timer_picker.cupertino_timer_picker import ( + main as basic, +) @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_picker/custom_locale.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_picker/custom_locale.png index 60cc9f42c2..9707d04f92 100644 Binary files a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_picker/custom_locale.png and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_picker/custom_locale.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_range_picker/custom_locale.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_range_picker/custom_locale.png index 98f4143da1..d70cca7124 100644 Binary files a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_range_picker/custom_locale.png and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_range_picker/custom_locale.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_auto_complete.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_auto_complete.py index a6c03d3132..20672364ee 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_auto_complete.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_auto_complete.py @@ -1,7 +1,7 @@ import pytest import flet.testing as ftt -from examples.controls.material.auto_complete.basic import main as basic +from examples.controls.material.auto_complete.auto_complete import main as basic @pytest.mark.parametrize( diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_badge.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_badge.py index a15a01ecf6..b8542f93f7 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_badge.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_badge.py @@ -1,6 +1,6 @@ import pytest -import examples.controls.material.badge.basic.main as basic +import examples.controls.material.badge.badge.main as basic import flet as ft import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_banner.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_banner.py index 2863d50e56..efd8926592 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_banner.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_banner.py @@ -2,7 +2,7 @@ import flet as ft import flet.testing as ftt -from examples.controls.material.banner.basic import main as basic +from examples.controls.material.banner.banner import main as basic @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_bottom_sheet.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_bottom_sheet.py index 4b3ff641db..2ea619d6be 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_bottom_sheet.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_bottom_sheet.py @@ -1,6 +1,6 @@ import pytest -import examples.controls.material.bottom_sheet.basic.main as basic +import examples.controls.material.bottom_sheet.bottom_sheet.main as basic import examples.controls.material.bottom_sheet.fullscreen.main as fullscreen import flet as ft import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_button.py index cc6b68a756..f2a717eda7 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_button.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_button.py @@ -1,7 +1,7 @@ import pytest import examples.controls.material.button.animate_on_hover.main as animate_on_hover -import examples.controls.material.button.basic.main as basic +import examples.controls.material.button.button.main as basic import examples.controls.material.button.button_shapes.main as button_shapes import examples.controls.material.button.custom_content.main as custom_content import examples.controls.material.button.handling_clicks.main as handling_clicks diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_checkbox.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_checkbox.py index bc51199ab2..40069e49d8 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_checkbox.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_checkbox.py @@ -1,6 +1,6 @@ import pytest -import examples.controls.material.checkbox.basic.main as basic +import examples.controls.material.checkbox.checkbox.main as basic import examples.controls.material.checkbox.handling_events.main as handling_events import examples.controls.material.checkbox.styled.main as styled import flet as ft diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_datatable.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_datatable.py index 50647fd3e9..7f9a6bf62a 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_datatable.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_datatable.py @@ -5,7 +5,7 @@ from examples.controls.material.data_table.adaptive_row_heights import ( main as adaptive_row_heights, ) -from examples.controls.material.data_table.basic import main as basic +from examples.controls.material.data_table.data_table import main as basic from examples.controls.material.data_table.handling_events import ( main as handling_events, ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_date_picker.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_date_picker.py index a0f8c1b2ce..b5480c617b 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_date_picker.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_date_picker.py @@ -2,8 +2,8 @@ import pytest -import examples.controls.material.date_picker.basic.main as basic import examples.controls.material.date_picker.custom_locale.main as custom_locale +import examples.controls.material.date_picker.date_picker.main as basic import flet as ft import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_date_range_picker.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_date_range_picker.py index c15a68c653..91e00a0780 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_date_range_picker.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_date_range_picker.py @@ -2,8 +2,8 @@ import pytest -import examples.controls.material.date_range_picker.basic.main as basic import examples.controls.material.date_range_picker.custom_locale.main as custom_locale +import examples.controls.material.date_range_picker.date_range_picker.main as basic import flet as ft import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_divider.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_divider.py index 64b7acdb40..2abc54551c 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_divider.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_divider.py @@ -1,6 +1,6 @@ import pytest -import examples.controls.material.divider.basic.main as basic +import examples.controls.material.divider.divider.main as basic import flet as ft import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_panel_list.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_panel_list.py index 85133eb149..2caf641355 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_panel_list.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_panel_list.py @@ -2,7 +2,9 @@ import flet as ft import flet.testing as ftt -from examples.controls.material.expansion_panel_list.basic import main as basic +from examples.controls.material.expansion_panel_list.expansion_panel_list import ( + main as basic, +) from examples.controls.material.expansion_panel_list.scrollable import ( main as scrollable, ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_tile.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_tile.py index 1f844a853f..ce6329ec82 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_tile.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_tile.py @@ -2,11 +2,11 @@ import flet as ft import flet.testing as ftt -from examples.controls.material.expansion_tile.basic import main as basic from examples.controls.material.expansion_tile.borders import main as borders from examples.controls.material.expansion_tile.custom_animations import ( main as custom_animations, ) +from examples.controls.material.expansion_tile.expansion_tile import main as basic from examples.controls.material.expansion_tile.programmatic_expansion import ( main as programmatic_expansion, ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_button.py index 1c3def9627..8ce6b8dd5b 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_button.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_button.py @@ -2,7 +2,7 @@ import flet as ft import flet.testing as ftt -from examples.controls.material.filled_button.basic import main as basic +from examples.controls.material.filled_button.filled_button import main as basic @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_tonal_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_tonal_button.py index a2cc355d93..a3195d4379 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_tonal_button.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_tonal_button.py @@ -2,7 +2,9 @@ import flet as ft import flet.testing as ftt -from examples.controls.material.filled_tonal_button.basic import main as basic +from examples.controls.material.filled_tonal_button.filled_tonal_button import ( + main as basic, +) @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_list_tile.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_list_tile.py index 68ebec6a0f..6d5bbbdeae 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_list_tile.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_list_tile.py @@ -2,7 +2,7 @@ import flet as ft import flet.testing as ftt -from examples.controls.material.list_tile.basic import main as basic +from examples.controls.material.list_tile.list_tile import main as basic @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_menu_item_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_menu_item_button.py index 4be7b7353f..712bdafc01 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_menu_item_button.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_menu_item_button.py @@ -2,7 +2,7 @@ import flet as ft import flet.testing as ftt -from examples.controls.material.menu_item_button.basic import main as basic +from examples.controls.material.menu_item_button.menu_item_button import main as basic @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_bar.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_bar.py index 51e9469da9..c15ca1b15c 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_bar.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_bar.py @@ -2,7 +2,7 @@ import flet as ft import flet.testing as ftt -from examples.controls.material.navigation_bar.basic.main import main as basic +from examples.controls.material.navigation_bar.navigation_bar.main import main as basic @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_rail.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_rail.py index 02d597b9c4..4ea83a61a5 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_rail.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_rail.py @@ -2,7 +2,9 @@ import flet as ft import flet.testing as ftt -from examples.controls.material.navigation_rail.basic.main import main as basic +from examples.controls.material.navigation_rail.navigation_rail.main import ( + main as basic, +) @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_outlined_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_outlined_button.py index 0565913ffa..d3425775ae 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_outlined_button.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_outlined_button.py @@ -2,7 +2,6 @@ import flet as ft import flet.testing as ftt -from examples.controls.material.outlined_button.basic.main import main as basic from examples.controls.material.outlined_button.custom_content.main import ( main as custom_content, ) @@ -10,6 +9,9 @@ main as handling_clicks, ) from examples.controls.material.outlined_button.icons.main import main as icons +from examples.controls.material.outlined_button.outlined_button.main import ( + main as basic, +) @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_popup_menu_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_popup_menu_button.py index 191985b7ce..6dceba4df6 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_popup_menu_button.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_popup_menu_button.py @@ -2,7 +2,9 @@ import flet as ft import flet.testing as ftt -from examples.controls.material.popup_menu_button.basic.main import main as basic +from examples.controls.material.popup_menu_button.popup_menu_button.main import ( + main as basic, +) @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_radio.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_radio.py index 41450aef3d..cf39f13539 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_radio.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_radio.py @@ -2,10 +2,10 @@ import flet as ft import flet.testing as ftt -from examples.controls.material.radio.basic.main import main as basic from examples.controls.material.radio.handling_selection_changes.main import ( main as handling_selection_changes, ) +from examples.controls.material.radio.radio.main import main as basic from examples.controls.material.radio.styled.main import main as styled diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_range_slider.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_range_slider.py index 7ecf08d0c3..59446a617b 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_range_slider.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_range_slider.py @@ -2,10 +2,10 @@ import flet as ft import flet.testing as ftt -from examples.controls.material.range_slider.basic.main import main as basic from examples.controls.material.range_slider.handling_change_events.main import ( main as handling_change_events, ) +from examples.controls.material.range_slider.range_slider.main import main as basic @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_reorderable_drag_handle.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_reorderable_drag_handle.py index dc2e70f640..5bdce04368 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_reorderable_drag_handle.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_reorderable_drag_handle.py @@ -2,7 +2,9 @@ import flet as ft import flet.testing as ftt -from examples.controls.material.reorderable_drag_handle.basic.main import main as basic +from examples.controls.material.reorderable_drag_handle.custom_drag_handle.main import ( + main as basic, +) @pytest.mark.asyncio(loop_scope="function") diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_search_bar.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_search_bar.py index e3d37a26c2..8ee14c9e86 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_search_bar.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_search_bar.py @@ -1,6 +1,6 @@ import pytest -import examples.controls.material.search_bar.basic.main as basic +import examples.controls.material.search_bar.search_bar.main as basic import flet as ft import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_selection_area.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_selection_area.py index f8d883f6e6..1ea39c3aec 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_selection_area.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_selection_area.py @@ -1,6 +1,6 @@ import pytest -import examples.controls.material.selection_area.basic.main as basic +import examples.controls.material.selection_area.selection_area.main as basic import flet as ft import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_slider.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_slider.py index e649f5065d..544444bc08 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_slider.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_slider.py @@ -1,8 +1,8 @@ import pytest -import examples.controls.material.slider.basic.main as basic import examples.controls.material.slider.custom_label.main as custom_label import examples.controls.material.slider.handling_events.main as handling_events +import examples.controls.material.slider.slider.main as basic import flet as ft import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_snack_bar.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_snack_bar.py index 591e605d9a..e1342a1be8 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_snack_bar.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_snack_bar.py @@ -1,8 +1,8 @@ import pytest import examples.controls.material.snack_bar.action.main as action -import examples.controls.material.snack_bar.basic.main as basic import examples.controls.material.snack_bar.counter.main as counter +import examples.controls.material.snack_bar.snack_bar.main as basic import flet as ft import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_submenu_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_submenu_button.py index 7197403852..c31c8efbce 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_submenu_button.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_submenu_button.py @@ -1,7 +1,7 @@ import pytest -import examples.controls.material.submenu_button.basic.main as basic import examples.controls.material.submenu_button.standalone.main as standalone +import examples.controls.material.submenu_button.submenu_button.main as basic import flet as ft import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_switch.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_switch.py index 48a1c484b8..b28d0398e2 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_switch.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_switch.py @@ -1,7 +1,7 @@ import pytest -import examples.controls.material.switch.basic.main as basic import examples.controls.material.switch.handling_events.main as handling_events +import examples.controls.material.switch.switch.main as basic import flet as ft import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_tabs.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_tabs.py index 7595678088..5815afe56b 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_tabs.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_tabs.py @@ -1,6 +1,6 @@ import pytest -import examples.controls.material.tabs.basic.main as basic +import examples.controls.material.tabs.tabs.main as basic import flet as ft import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_text_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_text_button.py index 2bba34c9e6..b5fec2838c 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_text_button.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_text_button.py @@ -1,9 +1,9 @@ import pytest -import examples.controls.material.text_button.basic.main as basic import examples.controls.material.text_button.custom_content.main as custom_content import examples.controls.material.text_button.handling_clicks.main as handling_clicks import examples.controls.material.text_button.icons.main as icons +import examples.controls.material.text_button.text_button.main as basic import flet as ft import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_textfield.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_textfield.py index e79a4f5eb7..b5de3d0a61 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_textfield.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_textfield.py @@ -1,6 +1,6 @@ import pytest -import examples.controls.material.text_field.basic.main as basic +import examples.controls.material.text_field.text_field.main as basic import flet as ft import flet.testing as ftt from examples.controls.material.text_field.handling_change_events.main import ( diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_time_picker.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_time_picker.py index 18d23b2b60..4e96305d88 100644 --- a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_time_picker.py +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_time_picker.py @@ -2,9 +2,9 @@ import pytest -import examples.controls.material.time_picker.basic.main as basic import examples.controls.material.time_picker.custom_locale.main as custom_locale import examples.controls.material.time_picker.hour_formats.main as hour_formats +import examples.controls.material.time_picker.time_picker.main as basic import flet as ft import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/test_code_editor.py b/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/test_code_editor.py index 433c34bdb7..1c701712f4 100644 --- a/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/test_code_editor.py +++ b/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/test_code_editor.py @@ -1,8 +1,8 @@ import pytest -import examples.extensions.code_editor.example_1.main as example_1 -import examples.extensions.code_editor.example_2.main as example_2 -import examples.extensions.code_editor.example_3.main as example_3 +import examples.extensions.code_editor.code_editor.main as example_1 +import examples.extensions.code_editor.folding_and_initial_selection.main as example_3 +import examples.extensions.code_editor.selection_handling.main as example_2 import flet.testing as ftt diff --git a/sdk/python/packages/flet/integration_tests/extensions/spinkit/test_spinkit.py b/sdk/python/packages/flet/integration_tests/extensions/spinkit/test_spinkit.py index dc9c2d2c5c..3ca4e1e041 100644 --- a/sdk/python/packages/flet/integration_tests/extensions/spinkit/test_spinkit.py +++ b/sdk/python/packages/flet/integration_tests/extensions/spinkit/test_spinkit.py @@ -138,10 +138,19 @@ async def test_all_controls_render(flet_app: ftt.FletTestApp): ] flet_app.page.clean() flet_app.page.add( - ft.Row( - wrap=True, - key="row", - controls=[cls(color=ft.Colors.BLUE, size=40) for cls in controls], + # The wrapped row of all spinners is much taller than the test window; + # host it in a scrollable column so the page doesn't overflow (an + # overflow error fails the Flutter test process). + ft.Column( + scroll=ft.ScrollMode.AUTO, + expand=True, + controls=[ + ft.Row( + wrap=True, + key="row", + controls=[cls(color=ft.Colors.BLUE, size=40) for cls in controls], + ) + ], ) ) await flet_app.tester.pump(duration=ft.Duration(milliseconds=500)) diff --git a/sdk/python/packages/flet/pyproject.toml b/sdk/python/packages/flet/pyproject.toml index 55539efe6e..9fb0df02f5 100644 --- a/sdk/python/packages/flet/pyproject.toml +++ b/sdk/python/packages/flet/pyproject.toml @@ -32,10 +32,23 @@ desktop = [ "flet-desktop", ] web = ["flet-web"] +# Dependencies needed to run integration tests written with `flet.testing` +# (the `flet test` command / the pytest plugin). Pillow/numpy/scikit-image +# back screenshot and GIF comparison. +test = [ + "pytest >=7.2.0", + "pytest-asyncio >=1.1.0", + "numpy >=2.2.0", + "pillow >=10.3.0", + "scikit-image >=0.25.2", +] [project.scripts] flet = "flet.cli:main" +[project.entry-points.pytest11] +flet = "flet.pytest_plugin" + [dependency-groups] extensions = [ "flet-ads", diff --git a/sdk/python/packages/flet/src/flet/__init__.py b/sdk/python/packages/flet/src/flet/__init__.py index ee854e7b27..c534e26a23 100644 --- a/sdk/python/packages/flet/src/flet/__init__.py +++ b/sdk/python/packages/flet/src/flet/__init__.py @@ -1,576 +1,627 @@ from typing import TYPE_CHECKING -from flet.app import AppCallable, app, app_async, run, run_async -from flet.components.component import Component -from flet.components.component_decorator import component -from flet.components.hooks.use_callback import use_callback -from flet.components.hooks.use_context import ( - ContextProvider, - create_context, - use_context, -) -from flet.components.hooks.use_dialog import use_dialog -from flet.components.hooks.use_effect import ( - on_mounted, - on_unmounted, - on_updated, - use_effect, -) -from flet.components.hooks.use_memo import use_memo -from flet.components.hooks.use_ref import use_ref -from flet.components.hooks.use_state import use_state -from flet.components.memo import memo -from flet.components.observable import Observable, observable -from flet.components.public_utils import unwrap_component -from flet.components.router import ( - LocationInfo, - Route, - Router, - is_route_active, - use_route_loader_data, - use_route_location, - use_route_outlet, - use_route_params, - use_view_path, -) -from flet.controls import alignment, border, border_radius, margin, padding -from flet.controls.adaptive_control import AdaptiveControl -from flet.controls.alignment import Alignment, Axis -from flet.controls.animation import ( - Animation, - AnimationCurve, - AnimationStyle, - AnimationValue, -) -from flet.controls.base_control import BaseControl, Value, control, value -from flet.controls.base_page import BasePage, PageMediaData, PageResizeEvent -from flet.controls.blur import ( - Blur, - BlurTileMode, - BlurValue, -) -from flet.controls.border import ( - Border, - BorderSide, - BorderSideStrokeAlign, - BorderSideStrokeAlignValue, - BorderStyle, -) -from flet.controls.border_radius import ( - BorderRadius, - BorderRadiusValue, -) -from flet.controls.box import ( - BlurStyle, - BoxConstraints, - BoxDecoration, - BoxFit, - BoxShadow, - BoxShadowValue, - BoxShape, - ColorFilter, - DecorationImage, - FilterQuality, -) -from flet.controls.buttons import ( - BeveledRectangleBorder, - ButtonStyle, - CircleBorder, - ContinuousRectangleBorder, - OutlinedBorder, - RoundedRectangleBorder, - ShapeBorder, - StadiumBorder, -) -from flet.controls.colors import Colors -from flet.controls.context import Context, context -from flet.controls.control import Control -from flet.controls.control_event import ( - ControlEvent, - ControlEventHandler, - Event, - EventControlType, - EventHandler, -) -from flet.controls.control_state import ( - ControlState, - ControlStateValue, -) -from flet.controls.core.animated_switcher import ( - AnimatedSwitcher, - AnimatedSwitcherTransition, -) -from flet.controls.core.autofill_group import ( - AutofillGroup, - AutofillGroupDisposeAction, - AutofillHint, -) -from flet.controls.core.column import Column -from flet.controls.core.dismissible import ( - Dismissible, - DismissibleDismissEvent, - DismissibleUpdateEvent, -) -from flet.controls.core.drag_target import ( - DragTarget, - DragTargetEvent, - DragTargetLeaveEvent, - DragWillAcceptEvent, -) -from flet.controls.core.draggable import Draggable -from flet.controls.core.flet_app import FletApp, FletAppOutputEvent -from flet.controls.core.gesture_detector import GestureDetector -from flet.controls.core.grid_view import GridView -from flet.controls.core.hero import Hero -from flet.controls.core.icon import Icon -from flet.controls.core.image import Image -from flet.controls.core.interactive_viewer import InteractiveViewer -from flet.controls.core.keyboard_listener import ( - KeyboardListener, - KeyDownEvent, - KeyRepeatEvent, - KeyUpEvent, -) -from flet.controls.core.list_view import ListView -from flet.controls.core.markdown import ( - Markdown, - MarkdownCodeTheme, - MarkdownCustomCodeTheme, - MarkdownExtensionSet, - MarkdownStyleSheet, -) -from flet.controls.core.merge_semantics import MergeSemantics -from flet.controls.core.page_view import PageView -from flet.controls.core.pagelet import Pagelet -from flet.controls.core.placeholder import Placeholder -from flet.controls.core.reorderable_drag_handle import ReorderableDragHandle -from flet.controls.core.responsive_row import ResponsiveRow -from flet.controls.core.rotated_box import RotatedBox -from flet.controls.core.row import Row -from flet.controls.core.safe_area import SafeArea -from flet.controls.core.screenshot import Screenshot -from flet.controls.core.semantics import Semantics -from flet.controls.core.shader_mask import ShaderMask -from flet.controls.core.shimmer import Shimmer, ShimmerDirection -from flet.controls.core.stack import Stack, StackFit -from flet.controls.core.text import ( - Text, - TextAffinity, - TextSelection, - TextSelectionChangeCause, - TextSelectionChangeEvent, -) -from flet.controls.core.text_span import TextSpan -from flet.controls.core.transparent_pointer import TransparentPointer -from flet.controls.core.view import View -from flet.controls.core.window import ( - Window, - WindowEvent, - WindowEventType, - WindowResizeEdge, -) -from flet.controls.core.window_drag_area import WindowDragArea -from flet.controls.cupertino import cupertino_colors -from flet.controls.cupertino.cupertino_action_sheet import CupertinoActionSheet -from flet.controls.cupertino.cupertino_action_sheet_action import ( - CupertinoActionSheetAction, -) -from flet.controls.cupertino.cupertino_activity_indicator import ( - CupertinoActivityIndicator, -) -from flet.controls.cupertino.cupertino_alert_dialog import CupertinoAlertDialog -from flet.controls.cupertino.cupertino_app_bar import CupertinoAppBar -from flet.controls.cupertino.cupertino_bottom_sheet import CupertinoBottomSheet -from flet.controls.cupertino.cupertino_button import ( - CupertinoButton, - CupertinoButtonSize, -) -from flet.controls.cupertino.cupertino_checkbox import CupertinoCheckbox -from flet.controls.cupertino.cupertino_colors import CupertinoColors -from flet.controls.cupertino.cupertino_context_menu import CupertinoContextMenu -from flet.controls.cupertino.cupertino_context_menu_action import ( - CupertinoContextMenuAction, -) -from flet.controls.cupertino.cupertino_date_picker import ( - CupertinoDatePicker, - CupertinoDatePickerDateOrder, - CupertinoDatePickerMode, -) -from flet.controls.cupertino.cupertino_dialog_action import CupertinoDialogAction -from flet.controls.cupertino.cupertino_filled_button import CupertinoFilledButton -from flet.controls.cupertino.cupertino_list_tile import CupertinoListTile -from flet.controls.cupertino.cupertino_navigation_bar import CupertinoNavigationBar -from flet.controls.cupertino.cupertino_picker import CupertinoPicker -from flet.controls.cupertino.cupertino_radio import CupertinoRadio -from flet.controls.cupertino.cupertino_segmented_button import CupertinoSegmentedButton -from flet.controls.cupertino.cupertino_slider import CupertinoSlider -from flet.controls.cupertino.cupertino_sliding_segmented_button import ( - CupertinoSlidingSegmentedButton, -) -from flet.controls.cupertino.cupertino_switch import CupertinoSwitch -from flet.controls.cupertino.cupertino_textfield import ( - CupertinoTextField, - OverlayVisibilityMode, -) -from flet.controls.cupertino.cupertino_timer_picker import ( - CupertinoTimerPicker, - CupertinoTimerPickerMode, -) -from flet.controls.cupertino.cupertino_tinted_button import CupertinoTintedButton -from flet.controls.device_info import ( - AndroidBuildVersion, - AndroidDeviceInfo, - DeviceInfo, - IosDeviceInfo, - IosUtsname, - LinuxDeviceInfo, - MacOsDeviceInfo, - WebBrowserName, - WebDeviceInfo, - WindowsDeviceInfo, -) -from flet.controls.dialog_control import DialogControl -from flet.controls.duration import ( - DateTimeValue, - Duration, - DurationValue, -) -from flet.controls.events import ( - DragDownEvent, - DragEndEvent, - DragStartEvent, - DragUpdateEvent, - ForcePressEvent, - HoverEvent, - LongPressDownEvent, - LongPressEndEvent, - LongPressMoveUpdateEvent, - LongPressStartEvent, - MultiTapEvent, - PointerEvent, - ScaleEndEvent, - ScaleStartEvent, - ScaleUpdateEvent, - ScrollEvent, - TapEvent, - TapMoveEvent, -) -from flet.controls.exceptions import ( - FletException, - FletPageDisconnectedException, - FletUnimplementedPlatformException, - FletUnsupportedPlatformException, -) -from flet.controls.geometry import Rect, Size -from flet.controls.gradients import ( - Gradient, - GradientTileMode, - LinearGradient, - RadialGradient, - SweepGradient, -) -from flet.controls.icon_data import IconData -from flet.controls.id_counter import IdCounter -from flet.controls.keys import Key, KeyValue, ScrollKey, ValueKey -from flet.controls.layout_control import ( - ConstrainedControl, - LayoutControl, - LayoutSizeChangeEvent, -) -from flet.controls.margin import Margin, MarginValue -from flet.controls.material import dropdown, dropdownm2 -from flet.controls.material.alert_dialog import AlertDialog -from flet.controls.material.app_bar import AppBar -from flet.controls.material.auto_complete import ( - AutoComplete, - AutoCompleteSelectEvent, - AutoCompleteSuggestion, -) -from flet.controls.material.badge import Badge, BadgeValue -from flet.controls.material.banner import Banner -from flet.controls.material.bottom_app_bar import BottomAppBar -from flet.controls.material.bottom_sheet import BottomSheet -from flet.controls.material.button import Button -from flet.controls.material.card import Card, CardVariant -from flet.controls.material.checkbox import Checkbox -from flet.controls.material.chip import Chip -from flet.controls.material.circle_avatar import CircleAvatar -from flet.controls.material.container import Container -from flet.controls.material.context_menu import ( - ContextMenu, - ContextMenuDismissEvent, - ContextMenuSelectEvent, - ContextMenuTrigger, -) -from flet.controls.material.datatable import ( - DataCell, - DataColumn, - DataColumnSortEvent, - DataRow, - DataTable, -) -from flet.controls.material.date_picker import ( - DatePicker, - DatePickerEntryMode, - DatePickerEntryModeChangeEvent, - DatePickerMode, -) -from flet.controls.material.date_range_picker import DateRangePicker -from flet.controls.material.divider import Divider -from flet.controls.material.dropdown import Dropdown, DropdownOption -from flet.controls.material.dropdownm2 import DropdownM2 -from flet.controls.material.elevated_button import ElevatedButton -from flet.controls.material.expansion_panel import ( - ExpansionPanel, - ExpansionPanelList, - ExpansionPanelListChangeEvent, -) -from flet.controls.material.expansion_tile import ExpansionTile, TileAffinity -from flet.controls.material.filled_button import FilledButton -from flet.controls.material.filled_tonal_button import FilledTonalButton -from flet.controls.material.floating_action_button import FloatingActionButton -from flet.controls.material.form_field_control import FormFieldControl, InputBorder -from flet.controls.material.icon_button import ( - FilledIconButton, - FilledTonalIconButton, - IconButton, - OutlinedIconButton, -) -from flet.controls.material.list_tile import ( - ListTile, - ListTileStyle, - ListTileTitleAlignment, -) -from flet.controls.material.menu_bar import MenuBar, MenuStyle -from flet.controls.material.menu_item_button import MenuItemButton -from flet.controls.material.navigation_bar import ( - NavigationBar, - NavigationBarDestination, - NavigationBarLabelBehavior, -) -from flet.controls.material.navigation_drawer import ( - NavigationDrawer, - NavigationDrawerDestination, -) -from flet.controls.material.navigation_rail import ( - NavigationRail, - NavigationRailDestination, - NavigationRailLabelType, -) -from flet.controls.material.outlined_button import OutlinedButton -from flet.controls.material.popup_menu_button import ( - PopupMenuButton, - PopupMenuItem, - PopupMenuPosition, -) -from flet.controls.material.progress_bar import ProgressBar -from flet.controls.material.progress_ring import ProgressRing -from flet.controls.material.radio import Radio -from flet.controls.material.radio_group import RadioGroup -from flet.controls.material.range_slider import RangeSlider -from flet.controls.material.reorderable_list_view import ( - OnReorderEvent, - ReorderableListView, -) -from flet.controls.material.search_bar import SearchBar -from flet.controls.material.segmented_button import Segment, SegmentedButton -from flet.controls.material.selection_area import SelectionArea -from flet.controls.material.slider import Slider, SliderInteraction -from flet.controls.material.snack_bar import ( - DismissDirection, - SnackBar, - SnackBarAction, - SnackBarBehavior, -) -from flet.controls.material.submenu_button import SubmenuButton -from flet.controls.material.switch import Switch -from flet.controls.material.tabs import ( - Tab, - TabAlignment, - TabBar, - TabBarHoverEvent, - TabBarIndicatorSize, - TabBarView, - TabIndicatorAnimation, - Tabs, - UnderlineTabIndicator, -) -from flet.controls.material.text_button import TextButton -from flet.controls.material.textfield import ( - InputFilter, - KeyboardType, - NumbersOnlyInputFilter, - TextCapitalization, - TextField, - TextOnlyInputFilter, -) -from flet.controls.material.time_picker import ( - TimePicker, - TimePickerEntryMode, - TimePickerEntryModeChangeEvent, - TimePickerHourFormat, -) -from flet.controls.material.tooltip import Tooltip, TooltipTriggerMode, TooltipValue -from flet.controls.material.vertical_divider import VerticalDivider -from flet.controls.multi_view import MultiView -from flet.controls.padding import Padding, PaddingValue -from flet.controls.page import ( - AppLifecycleStateChangeEvent, - KeyboardEvent, - LocaleChangeEvent, - LoginEvent, - MultiViewAddEvent, - MultiViewRemoveEvent, - Page, - PlatformBrightnessChangeEvent, - RouteChangeEvent, - ViewPopEvent, - ViewsPopUntilEvent, -) -from flet.controls.painting import ( - Paint, - PaintGradient, - PaintingStyle, - PaintLinearGradient, - PaintRadialGradient, - PaintSweepGradient, -) -from flet.controls.query_string import QueryString -from flet.controls.ref import Ref -from flet.controls.scrollable_control import ( - OnScrollEvent, - ScrollableControl, - Scrollbar, - ScrollbarOrientation, - ScrollDirection, - ScrollType, -) -from flet.controls.services.accelerometer import ( - Accelerometer, - AccelerometerReadingEvent, -) -from flet.controls.services.barometer import Barometer, BarometerReadingEvent -from flet.controls.services.battery import ( - Battery, - BatteryState, - BatteryStateChangeEvent, -) -from flet.controls.services.browser_context_menu import BrowserContextMenu -from flet.controls.services.clipboard import Clipboard -from flet.controls.services.connectivity import ( - Connectivity, - ConnectivityChangeEvent, - ConnectivityType, -) -from flet.controls.services.file_picker import ( - FilePicker, - FilePickerFile, - FilePickerFileType, - FilePickerUploadEvent, - FilePickerUploadFile, -) -from flet.controls.services.gyroscope import Gyroscope, GyroscopeReadingEvent -from flet.controls.services.haptic_feedback import HapticFeedback -from flet.controls.services.magnetometer import Magnetometer, MagnetometerReadingEvent -from flet.controls.services.screen_brightness import ( - ScreenBrightness, - ScreenBrightnessChangeEvent, -) -from flet.controls.services.semantics_service import Assertiveness, SemanticsService -from flet.controls.services.sensor_error_event import SensorErrorEvent -from flet.controls.services.service import Service -from flet.controls.services.shake_detector import ShakeDetector -from flet.controls.services.share import ( - Share, - ShareCupertinoActivityType, - ShareFile, - ShareResult, - ShareResultStatus, -) -from flet.controls.services.shared_preferences import SharedPreferences -from flet.controls.services.storage_paths import StoragePaths -from flet.controls.services.url_launcher import ( - BrowserConfiguration, - LaunchMode, - UrlLauncher, - WebViewConfiguration, -) -from flet.controls.services.user_accelerometer import ( - UserAccelerometer, - UserAccelerometerReadingEvent, -) -from flet.controls.services.wakelock import Wakelock -from flet.controls.template_route import TemplateRoute -from flet.controls.text_style import ( - StrutStyle, - TextBaseline, - TextDecoration, - TextDecorationStyle, - TextOverflow, - TextStyle, - TextThemeStyle, -) -from flet.controls.transform import ( - Flip, - Matrix4, - Offset, - OffsetValue, - Rotate, - RotateValue, - Scale, - ScaleValue, - Transform, -) -from flet.controls.types import ( - AppLifecycleState, - AppView, - AutomaticNotchShape, - BlendMode, - Brightness, - CircularRectangleNotchShape, - ClipBehavior, - ColorValue, - CrossAxisAlignment, - DeviceOrientation, - FloatingActionButtonLocation, - FontWeight, - IconDataOrControl, - ImageRepeat, - LabelPosition, - Locale, - LocaleConfiguration, - MainAxisAlignment, - MouseCursor, - NotchShape, - Number, - Orientation, - PagePlatform, - PointerDeviceType, - ResponsiveNumber, - ResponsiveRowBreakpoint, - RouteUrlStrategy, - ScrollMode, - StrokeCap, - StrokeJoin, - StrOrControl, - SupportsStr, - TextAlign, - ThemeMode, - Url, - UrlTarget, - VerticalAlignment, - VisualDensity, - WebRenderer, -) -from flet.pubsub.pubsub_client import PubSubClient -from flet.pubsub.pubsub_hub import PubSubHub +# `__version__` is cheap and frequently accessed — keep it eager. from flet.version import flet_version as __version__ +# The public API is imported lazily (PEP 562). `import flet` no longer executes +# the full ~270-module package; each name is imported on first access and cached +# into module globals. The block below exists only for type checkers / IDEs. if TYPE_CHECKING: - from flet.controls.cupertino import cupertino_icons + from flet.app import ( + AppCallable, + app, + app_async, + run, + run_async, + ) + from flet.components.component import Component + from flet.components.component_decorator import component + from flet.components.hooks.use_callback import use_callback + from flet.components.hooks.use_context import ( + ContextProvider, + create_context, + use_context, + ) + from flet.components.hooks.use_dialog import use_dialog + from flet.components.hooks.use_effect import ( + on_mounted, + on_unmounted, + on_updated, + use_effect, + ) + from flet.components.hooks.use_memo import use_memo + from flet.components.hooks.use_ref import use_ref + from flet.components.hooks.use_state import use_state + from flet.components.memo import memo + from flet.components.observable import ( + Observable, + observable, + ) + from flet.components.public_utils import unwrap_component + from flet.components.router import ( + LocationInfo, + Route, + Router, + is_route_active, + use_route_loader_data, + use_route_location, + use_route_outlet, + use_route_params, + use_view_path, + ) + from flet.controls import ( + alignment, + border, + border_radius, + margin, + padding, + ) + from flet.controls.adaptive_control import AdaptiveControl + from flet.controls.alignment import ( + Alignment, + Axis, + ) + from flet.controls.animation import ( + Animation, + AnimationCurve, + AnimationStyle, + AnimationValue, + ) + from flet.controls.base_control import ( + BaseControl, + Value, + control, + value, + ) + from flet.controls.base_page import ( + BasePage, + PageMediaData, + PageResizeEvent, + ) + from flet.controls.blur import ( + Blur, + BlurTileMode, + BlurValue, + ) + from flet.controls.border import ( + Border, + BorderSide, + BorderSideStrokeAlign, + BorderSideStrokeAlignValue, + BorderStyle, + ) + from flet.controls.border_radius import ( + BorderRadius, + BorderRadiusValue, + ) + from flet.controls.box import ( + BlurStyle, + BoxConstraints, + BoxDecoration, + BoxFit, + BoxShadow, + BoxShadowValue, + BoxShape, + ColorFilter, + DecorationImage, + FilterQuality, + ) + from flet.controls.buttons import ( + BeveledRectangleBorder, + ButtonStyle, + CircleBorder, + ContinuousRectangleBorder, + OutlinedBorder, + RoundedRectangleBorder, + ShapeBorder, + StadiumBorder, + ) + from flet.controls.colors import Colors + from flet.controls.context import ( + Context, + context, + ) + from flet.controls.control import Control + from flet.controls.control_event import ( + ControlEvent, + ControlEventHandler, + Event, + EventControlType, + EventHandler, + ) + from flet.controls.control_state import ( + ControlState, + ControlStateValue, + ) + from flet.controls.core.animated_switcher import ( + AnimatedSwitcher, + AnimatedSwitcherTransition, + ) + from flet.controls.core.autofill_group import ( + AutofillGroup, + AutofillGroupDisposeAction, + AutofillHint, + ) + from flet.controls.core.column import Column + from flet.controls.core.dismissible import ( + Dismissible, + DismissibleDismissEvent, + DismissibleUpdateEvent, + ) + from flet.controls.core.drag_target import ( + DragTarget, + DragTargetEvent, + DragTargetLeaveEvent, + DragWillAcceptEvent, + ) + from flet.controls.core.draggable import Draggable + from flet.controls.core.flet_app import ( + FletApp, + FletAppOutputEvent, + ) + from flet.controls.core.gesture_detector import GestureDetector + from flet.controls.core.grid_view import GridView + from flet.controls.core.hero import Hero + from flet.controls.core.icon import Icon + from flet.controls.core.image import Image + from flet.controls.core.interactive_viewer import InteractiveViewer + from flet.controls.core.keyboard_listener import ( + KeyboardListener, + KeyDownEvent, + KeyRepeatEvent, + KeyUpEvent, + ) + from flet.controls.core.list_view import ListView + from flet.controls.core.markdown import ( + Markdown, + MarkdownCodeTheme, + MarkdownCustomCodeTheme, + MarkdownExtensionSet, + MarkdownStyleSheet, + ) + from flet.controls.core.merge_semantics import MergeSemantics + from flet.controls.core.page_view import PageView + from flet.controls.core.pagelet import Pagelet + from flet.controls.core.placeholder import Placeholder + from flet.controls.core.raw_image import RawImage + from flet.controls.core.reorderable_drag_handle import ReorderableDragHandle + from flet.controls.core.responsive_row import ResponsiveRow + from flet.controls.core.rotated_box import RotatedBox + from flet.controls.core.row import Row + from flet.controls.core.safe_area import SafeArea + from flet.controls.core.screenshot import Screenshot + from flet.controls.core.semantics import Semantics + from flet.controls.core.shader_mask import ShaderMask + from flet.controls.core.shimmer import ( + Shimmer, + ShimmerDirection, + ) + from flet.controls.core.stack import ( + Stack, + StackFit, + ) + from flet.controls.core.text import ( + Text, + TextAffinity, + TextSelection, + TextSelectionChangeCause, + TextSelectionChangeEvent, + ) + from flet.controls.core.text_span import TextSpan + from flet.controls.core.transparent_pointer import TransparentPointer + from flet.controls.core.view import View + from flet.controls.core.window import ( + Window, + WindowEvent, + WindowEventType, + WindowResizeEdge, + ) + from flet.controls.core.window_drag_area import WindowDragArea + from flet.controls.cupertino import ( + cupertino_colors, + cupertino_icons, + ) + from flet.controls.cupertino.cupertino_action_sheet import CupertinoActionSheet + from flet.controls.cupertino.cupertino_action_sheet_action import ( + CupertinoActionSheetAction, + ) + from flet.controls.cupertino.cupertino_activity_indicator import ( + CupertinoActivityIndicator, + ) + from flet.controls.cupertino.cupertino_alert_dialog import CupertinoAlertDialog + from flet.controls.cupertino.cupertino_app_bar import CupertinoAppBar + from flet.controls.cupertino.cupertino_bottom_sheet import CupertinoBottomSheet + from flet.controls.cupertino.cupertino_button import ( + CupertinoButton, + CupertinoButtonSize, + ) + from flet.controls.cupertino.cupertino_checkbox import CupertinoCheckbox + from flet.controls.cupertino.cupertino_colors import CupertinoColors + from flet.controls.cupertino.cupertino_context_menu import CupertinoContextMenu + from flet.controls.cupertino.cupertino_context_menu_action import ( + CupertinoContextMenuAction, + ) + from flet.controls.cupertino.cupertino_date_picker import ( + CupertinoDatePicker, + CupertinoDatePickerDateOrder, + CupertinoDatePickerMode, + ) + from flet.controls.cupertino.cupertino_dialog_action import CupertinoDialogAction + from flet.controls.cupertino.cupertino_filled_button import CupertinoFilledButton from flet.controls.cupertino.cupertino_icons import CupertinoIcons - from flet.controls.material import icons + from flet.controls.cupertino.cupertino_list_tile import CupertinoListTile + from flet.controls.cupertino.cupertino_navigation_bar import CupertinoNavigationBar + from flet.controls.cupertino.cupertino_picker import CupertinoPicker + from flet.controls.cupertino.cupertino_radio import CupertinoRadio + from flet.controls.cupertino.cupertino_segmented_button import ( + CupertinoSegmentedButton, + ) + from flet.controls.cupertino.cupertino_slider import CupertinoSlider + from flet.controls.cupertino.cupertino_sliding_segmented_button import ( + CupertinoSlidingSegmentedButton, + ) + from flet.controls.cupertino.cupertino_switch import CupertinoSwitch + from flet.controls.cupertino.cupertino_textfield import ( + CupertinoTextField, + OverlayVisibilityMode, + ) + from flet.controls.cupertino.cupertino_timer_picker import ( + CupertinoTimerPicker, + CupertinoTimerPickerMode, + ) + from flet.controls.cupertino.cupertino_tinted_button import CupertinoTintedButton + from flet.controls.device_info import ( + AndroidBuildVersion, + AndroidDeviceInfo, + DeviceInfo, + IosDeviceInfo, + IosUtsname, + LinuxDeviceInfo, + MacOsDeviceInfo, + WebBrowserName, + WebDeviceInfo, + WindowsDeviceInfo, + ) + from flet.controls.dialog_control import DialogControl + from flet.controls.duration import ( + DateTimeValue, + Duration, + DurationValue, + ) + from flet.controls.events import ( + DragDownEvent, + DragEndEvent, + DragStartEvent, + DragUpdateEvent, + ForcePressEvent, + HoverEvent, + LongPressDownEvent, + LongPressEndEvent, + LongPressMoveUpdateEvent, + LongPressStartEvent, + MultiTapEvent, + PointerEvent, + ScaleEndEvent, + ScaleStartEvent, + ScaleUpdateEvent, + ScrollEvent, + TapEvent, + TapMoveEvent, + ) + from flet.controls.exceptions import ( + FletException, + FletPageDisconnectedException, + FletUnimplementedPlatformException, + FletUnsupportedPlatformException, + ) + from flet.controls.geometry import ( + Rect, + Size, + ) + from flet.controls.gradients import ( + Gradient, + GradientTileMode, + LinearGradient, + RadialGradient, + SweepGradient, + ) + from flet.controls.icon_data import IconData + from flet.controls.id_counter import IdCounter + from flet.controls.keys import ( + Key, + KeyValue, + ScrollKey, + ValueKey, + ) + from flet.controls.layout_control import ( + ConstrainedControl, + LayoutControl, + LayoutSizeChangeEvent, + ) + from flet.controls.margin import ( + Margin, + MarginValue, + ) + from flet.controls.material import ( + dropdown, + dropdownm2, + icons, + ) + from flet.controls.material.alert_dialog import AlertDialog + from flet.controls.material.app_bar import AppBar + from flet.controls.material.auto_complete import ( + AutoComplete, + AutoCompleteSelectEvent, + AutoCompleteSuggestion, + ) + from flet.controls.material.badge import ( + Badge, + BadgeValue, + ) + from flet.controls.material.banner import Banner + from flet.controls.material.bottom_app_bar import BottomAppBar + from flet.controls.material.bottom_sheet import BottomSheet + from flet.controls.material.button import Button + from flet.controls.material.card import ( + Card, + CardVariant, + ) + from flet.controls.material.checkbox import Checkbox + from flet.controls.material.chip import Chip + from flet.controls.material.circle_avatar import CircleAvatar + from flet.controls.material.container import Container + from flet.controls.material.context_menu import ( + ContextMenu, + ContextMenuDismissEvent, + ContextMenuSelectEvent, + ContextMenuTrigger, + ) + from flet.controls.material.datatable import ( + DataCell, + DataColumn, + DataColumnSortEvent, + DataRow, + DataTable, + ) + from flet.controls.material.date_picker import ( + DatePicker, + DatePickerEntryMode, + DatePickerEntryModeChangeEvent, + DatePickerMode, + ) + from flet.controls.material.date_range_picker import DateRangePicker + from flet.controls.material.divider import Divider + from flet.controls.material.dropdown import ( + Dropdown, + DropdownOption, + ) + from flet.controls.material.dropdownm2 import DropdownM2 + from flet.controls.material.elevated_button import ElevatedButton + from flet.controls.material.expansion_panel import ( + ExpansionPanel, + ExpansionPanelList, + ExpansionPanelListChangeEvent, + ) + from flet.controls.material.expansion_tile import ( + ExpansionTile, + TileAffinity, + ) + from flet.controls.material.filled_button import FilledButton + from flet.controls.material.filled_tonal_button import FilledTonalButton + from flet.controls.material.floating_action_button import FloatingActionButton + from flet.controls.material.form_field_control import ( + FormFieldControl, + InputBorder, + ) + from flet.controls.material.icon_button import ( + FilledIconButton, + FilledTonalIconButton, + IconButton, + OutlinedIconButton, + ) from flet.controls.material.icons import Icons + from flet.controls.material.list_tile import ( + ListTile, + ListTileStyle, + ListTileTitleAlignment, + ) + from flet.controls.material.menu_bar import ( + MenuBar, + MenuStyle, + ) + from flet.controls.material.menu_item_button import MenuItemButton + from flet.controls.material.navigation_bar import ( + NavigationBar, + NavigationBarDestination, + NavigationBarLabelBehavior, + ) + from flet.controls.material.navigation_drawer import ( + NavigationDrawer, + NavigationDrawerDestination, + ) + from flet.controls.material.navigation_rail import ( + NavigationRail, + NavigationRailDestination, + NavigationRailLabelType, + ) + from flet.controls.material.outlined_button import OutlinedButton + from flet.controls.material.popup_menu_button import ( + PopupMenuButton, + PopupMenuItem, + PopupMenuPosition, + ) + from flet.controls.material.progress_bar import ProgressBar + from flet.controls.material.progress_ring import ProgressRing + from flet.controls.material.radio import Radio + from flet.controls.material.radio_group import RadioGroup + from flet.controls.material.range_slider import RangeSlider + from flet.controls.material.reorderable_list_view import ( + OnReorderEvent, + ReorderableListView, + ) + from flet.controls.material.search_bar import SearchBar + from flet.controls.material.segmented_button import ( + Segment, + SegmentedButton, + ) + from flet.controls.material.selection_area import SelectionArea + from flet.controls.material.slider import ( + Slider, + SliderInteraction, + ) + from flet.controls.material.snack_bar import ( + DismissDirection, + SnackBar, + SnackBarAction, + SnackBarBehavior, + ) + from flet.controls.material.submenu_button import SubmenuButton + from flet.controls.material.switch import Switch + from flet.controls.material.tabs import ( + Tab, + TabAlignment, + TabBar, + TabBarHoverEvent, + TabBarIndicatorSize, + TabBarView, + TabIndicatorAnimation, + Tabs, + UnderlineTabIndicator, + ) + from flet.controls.material.text_button import TextButton + from flet.controls.material.textfield import ( + InputFilter, + KeyboardType, + NumbersOnlyInputFilter, + TextCapitalization, + TextField, + TextOnlyInputFilter, + ) + from flet.controls.material.time_picker import ( + TimePicker, + TimePickerEntryMode, + TimePickerEntryModeChangeEvent, + TimePickerHourFormat, + ) + from flet.controls.material.tooltip import ( + Tooltip, + TooltipTriggerMode, + TooltipValue, + ) + from flet.controls.material.vertical_divider import VerticalDivider + from flet.controls.multi_view import MultiView + from flet.controls.padding import ( + Padding, + PaddingValue, + ) + from flet.controls.page import ( + AppLifecycleStateChangeEvent, + KeyboardEvent, + LocaleChangeEvent, + LoginEvent, + MultiViewAddEvent, + MultiViewRemoveEvent, + Page, + PlatformBrightnessChangeEvent, + RouteChangeEvent, + ViewPopEvent, + ViewsPopUntilEvent, + ) + from flet.controls.painting import ( + Paint, + PaintGradient, + PaintingStyle, + PaintLinearGradient, + PaintRadialGradient, + PaintSweepGradient, + ) + from flet.controls.query_string import QueryString + from flet.controls.ref import Ref + from flet.controls.scrollable_control import ( + OnScrollEvent, + ScrollableControl, + Scrollbar, + ScrollbarOrientation, + ScrollDirection, + ScrollType, + ) + from flet.controls.services.accelerometer import ( + Accelerometer, + AccelerometerReadingEvent, + ) + from flet.controls.services.barometer import ( + Barometer, + BarometerReadingEvent, + ) + from flet.controls.services.battery import ( + Battery, + BatteryState, + BatteryStateChangeEvent, + ) + from flet.controls.services.browser_context_menu import BrowserContextMenu + from flet.controls.services.clipboard import Clipboard + from flet.controls.services.connectivity import ( + Connectivity, + ConnectivityChangeEvent, + ConnectivityType, + ) + from flet.controls.services.file_picker import ( + FilePicker, + FilePickerFile, + FilePickerFileType, + FilePickerUploadEvent, + FilePickerUploadFile, + ) + from flet.controls.services.gyroscope import ( + Gyroscope, + GyroscopeReadingEvent, + ) + from flet.controls.services.haptic_feedback import HapticFeedback + from flet.controls.services.magnetometer import ( + Magnetometer, + MagnetometerReadingEvent, + ) + from flet.controls.services.screen_brightness import ( + ScreenBrightness, + ScreenBrightnessChangeEvent, + ) + from flet.controls.services.semantics_service import ( + Assertiveness, + SemanticsService, + ) + from flet.controls.services.sensor_error_event import SensorErrorEvent + from flet.controls.services.service import Service + from flet.controls.services.shake_detector import ShakeDetector + from flet.controls.services.share import ( + Share, + ShareCupertinoActivityType, + ShareFile, + ShareResult, + ShareResultStatus, + ) + from flet.controls.services.shared_preferences import SharedPreferences + from flet.controls.services.storage_paths import StoragePaths + from flet.controls.services.url_launcher import ( + BrowserConfiguration, + LaunchMode, + UrlLauncher, + WebViewConfiguration, + ) + from flet.controls.services.user_accelerometer import ( + UserAccelerometer, + UserAccelerometerReadingEvent, + ) + from flet.controls.services.wakelock import Wakelock + from flet.controls.template_route import TemplateRoute + from flet.controls.text_style import ( + StrutStyle, + TextBaseline, + TextDecoration, + TextDecorationStyle, + TextOverflow, + TextStyle, + TextThemeStyle, + ) from flet.controls.theme import ( AppBarTheme, BadgeTheme, @@ -617,6 +668,65 @@ TimePickerTheme, TooltipTheme, ) + from flet.controls.transform import ( + Flip, + Matrix4, + Offset, + OffsetValue, + Rotate, + RotateValue, + Scale, + ScaleValue, + Transform, + ) + from flet.controls.types import ( + AppLifecycleState, + AppView, + AutomaticNotchShape, + BlendMode, + Brightness, + CircularRectangleNotchShape, + ClipBehavior, + ColorValue, + CrossAxisAlignment, + DeviceOrientation, + FloatingActionButtonLocation, + FontWeight, + IconDataOrControl, + ImageRepeat, + LabelPosition, + Locale, + LocaleConfiguration, + MainAxisAlignment, + MouseCursor, + NotchShape, + Number, + Orientation, + PagePlatform, + PointerDeviceType, + ResponsiveNumber, + ResponsiveRowBreakpoint, + RouteUrlStrategy, + ScrollMode, + StrokeCap, + StrokeJoin, + StrOrControl, + SupportsStr, + TextAlign, + ThemeMode, + Url, + UrlTarget, + VerticalAlignment, + VisualDensity, + WebRenderer, + ) + from flet.data_channel import ( + DataChannel, + DataChannelOpenEvent, + ) + from flet.pubsub.pubsub_client import PubSubClient + from flet.pubsub.pubsub_hub import PubSubHub + __all__ = [ "Accelerometer", @@ -755,6 +865,8 @@ "CupertinoTimerPickerMode", "CupertinoTintedButton", "DataCell", + "DataChannel", + "DataChannelOpenEvent", "DataColumn", "DataColumnSortEvent", "DataRow", @@ -959,6 +1071,7 @@ "RadioGroup", "RadioTheme", "RangeSlider", + "RawImage", "Rect", "Ref", "ReorderableDragHandle", @@ -1148,73 +1261,555 @@ "value", ] -_THEME_EXPORTS = { - "AppBarTheme", - "BadgeTheme", - "BannerTheme", - "BottomAppBarTheme", - "BottomSheetTheme", - "ButtonTheme", - "CardTheme", - "CheckboxTheme", - "ChipTheme", - "ColorScheme", - "DataTableTheme", - "DatePickerTheme", - "DialogTheme", - "DividerTheme", - "DropdownTheme", - "ExpansionTileTheme", - "FilledButtonTheme", - "FloatingActionButtonTheme", - "IconButtonTheme", - "IconTheme", - "ListTileTheme", - "NavigationBarTheme", - "NavigationDrawerTheme", - "NavigationRailTheme", - "OutlinedButtonTheme", - "PageTransitionsTheme", - "PageTransitionTheme", - "PopupMenuTheme", - "ProgressIndicatorTheme", - "RadioTheme", - "ScrollbarTheme", - "SearchBarTheme", - "SearchViewTheme", - "SegmentedButtonTheme", - "SliderTheme", - "SnackBarTheme", - "SwitchTheme", - "SystemOverlayStyle", - "TabBarTheme", - "TextButtonTheme", - "TextTheme", - "Theme", - "TimePickerTheme", - "TooltipTheme", +# Generated: exported name -> module that defines it. +_LAZY = { + "Accelerometer": "flet.controls.services.accelerometer", + "AccelerometerReadingEvent": "flet.controls.services.accelerometer", + "AdaptiveControl": "flet.controls.adaptive_control", + "AlertDialog": "flet.controls.material.alert_dialog", + "Alignment": "flet.controls.alignment", + "AndroidBuildVersion": "flet.controls.device_info", + "AndroidDeviceInfo": "flet.controls.device_info", + "AnimatedSwitcher": "flet.controls.core.animated_switcher", + "AnimatedSwitcherTransition": "flet.controls.core.animated_switcher", + "Animation": "flet.controls.animation", + "AnimationCurve": "flet.controls.animation", + "AnimationStyle": "flet.controls.animation", + "AnimationValue": "flet.controls.animation", + "AppBar": "flet.controls.material.app_bar", + "AppBarTheme": "flet.controls.theme", + "AppCallable": "flet.app", + "AppLifecycleState": "flet.controls.types", + "AppLifecycleStateChangeEvent": "flet.controls.page", + "AppView": "flet.controls.types", + "Assertiveness": "flet.controls.services.semantics_service", + "AutoComplete": "flet.controls.material.auto_complete", + "AutoCompleteSelectEvent": "flet.controls.material.auto_complete", + "AutoCompleteSuggestion": "flet.controls.material.auto_complete", + "AutofillGroup": "flet.controls.core.autofill_group", + "AutofillGroupDisposeAction": "flet.controls.core.autofill_group", + "AutofillHint": "flet.controls.core.autofill_group", + "AutomaticNotchShape": "flet.controls.types", + "Axis": "flet.controls.alignment", + "Badge": "flet.controls.material.badge", + "BadgeTheme": "flet.controls.theme", + "BadgeValue": "flet.controls.material.badge", + "Banner": "flet.controls.material.banner", + "BannerTheme": "flet.controls.theme", + "Barometer": "flet.controls.services.barometer", + "BarometerReadingEvent": "flet.controls.services.barometer", + "BaseControl": "flet.controls.base_control", + "BasePage": "flet.controls.base_page", + "Battery": "flet.controls.services.battery", + "BatteryState": "flet.controls.services.battery", + "BatteryStateChangeEvent": "flet.controls.services.battery", + "BeveledRectangleBorder": "flet.controls.buttons", + "BlendMode": "flet.controls.types", + "Blur": "flet.controls.blur", + "BlurStyle": "flet.controls.box", + "BlurTileMode": "flet.controls.blur", + "BlurValue": "flet.controls.blur", + "Border": "flet.controls.border", + "BorderRadius": "flet.controls.border_radius", + "BorderRadiusValue": "flet.controls.border_radius", + "BorderSide": "flet.controls.border", + "BorderSideStrokeAlign": "flet.controls.border", + "BorderSideStrokeAlignValue": "flet.controls.border", + "BorderStyle": "flet.controls.border", + "BottomAppBar": "flet.controls.material.bottom_app_bar", + "BottomAppBarTheme": "flet.controls.theme", + "BottomSheet": "flet.controls.material.bottom_sheet", + "BottomSheetTheme": "flet.controls.theme", + "BoxConstraints": "flet.controls.box", + "BoxDecoration": "flet.controls.box", + "BoxFit": "flet.controls.box", + "BoxShadow": "flet.controls.box", + "BoxShadowValue": "flet.controls.box", + "BoxShape": "flet.controls.box", + "Brightness": "flet.controls.types", + "BrowserConfiguration": "flet.controls.services.url_launcher", + "BrowserContextMenu": "flet.controls.services.browser_context_menu", + "Button": "flet.controls.material.button", + "ButtonStyle": "flet.controls.buttons", + "ButtonTheme": "flet.controls.theme", + "Card": "flet.controls.material.card", + "CardTheme": "flet.controls.theme", + "CardVariant": "flet.controls.material.card", + "Checkbox": "flet.controls.material.checkbox", + "CheckboxTheme": "flet.controls.theme", + "Chip": "flet.controls.material.chip", + "ChipTheme": "flet.controls.theme", + "CircleAvatar": "flet.controls.material.circle_avatar", + "CircleBorder": "flet.controls.buttons", + "CircularRectangleNotchShape": "flet.controls.types", + "ClipBehavior": "flet.controls.types", + "Clipboard": "flet.controls.services.clipboard", + "ColorFilter": "flet.controls.box", + "ColorScheme": "flet.controls.theme", + "ColorValue": "flet.controls.types", + "Colors": "flet.controls.colors", + "Column": "flet.controls.core.column", + "Component": "flet.components.component", + "Connectivity": "flet.controls.services.connectivity", + "ConnectivityChangeEvent": "flet.controls.services.connectivity", + "ConnectivityType": "flet.controls.services.connectivity", + "ConstrainedControl": "flet.controls.layout_control", + "Container": "flet.controls.material.container", + "Context": "flet.controls.context", + "ContextMenu": "flet.controls.material.context_menu", + "ContextMenuDismissEvent": "flet.controls.material.context_menu", + "ContextMenuSelectEvent": "flet.controls.material.context_menu", + "ContextMenuTrigger": "flet.controls.material.context_menu", + "ContextProvider": "flet.components.hooks.use_context", + "ContinuousRectangleBorder": "flet.controls.buttons", + "Control": "flet.controls.control", + "ControlEvent": "flet.controls.control_event", + "ControlEventHandler": "flet.controls.control_event", + "ControlState": "flet.controls.control_state", + "ControlStateValue": "flet.controls.control_state", + "CrossAxisAlignment": "flet.controls.types", + "CupertinoActionSheet": "flet.controls.cupertino.cupertino_action_sheet", + "CupertinoActionSheetAction": "flet.controls.cupertino.cupertino_action_sheet_action", # noqa: E501 + "CupertinoActivityIndicator": "flet.controls.cupertino.cupertino_activity_indicator", # noqa: E501 + "CupertinoAlertDialog": "flet.controls.cupertino.cupertino_alert_dialog", + "CupertinoAppBar": "flet.controls.cupertino.cupertino_app_bar", + "CupertinoBottomSheet": "flet.controls.cupertino.cupertino_bottom_sheet", + "CupertinoButton": "flet.controls.cupertino.cupertino_button", + "CupertinoButtonSize": "flet.controls.cupertino.cupertino_button", + "CupertinoCheckbox": "flet.controls.cupertino.cupertino_checkbox", + "CupertinoColors": "flet.controls.cupertino.cupertino_colors", + "CupertinoContextMenu": "flet.controls.cupertino.cupertino_context_menu", + "CupertinoContextMenuAction": "flet.controls.cupertino.cupertino_context_menu_action", # noqa: E501 + "CupertinoDatePicker": "flet.controls.cupertino.cupertino_date_picker", + "CupertinoDatePickerDateOrder": "flet.controls.cupertino.cupertino_date_picker", + "CupertinoDatePickerMode": "flet.controls.cupertino.cupertino_date_picker", + "CupertinoDialogAction": "flet.controls.cupertino.cupertino_dialog_action", + "CupertinoFilledButton": "flet.controls.cupertino.cupertino_filled_button", + "CupertinoIcons": "flet.controls.cupertino.cupertino_icons", + "CupertinoListTile": "flet.controls.cupertino.cupertino_list_tile", + "CupertinoNavigationBar": "flet.controls.cupertino.cupertino_navigation_bar", + "CupertinoPicker": "flet.controls.cupertino.cupertino_picker", + "CupertinoRadio": "flet.controls.cupertino.cupertino_radio", + "CupertinoSegmentedButton": "flet.controls.cupertino.cupertino_segmented_button", + "CupertinoSlider": "flet.controls.cupertino.cupertino_slider", + "CupertinoSlidingSegmentedButton": "flet.controls.cupertino.cupertino_sliding_segmented_button", # noqa: E501 + "CupertinoSwitch": "flet.controls.cupertino.cupertino_switch", + "CupertinoTextField": "flet.controls.cupertino.cupertino_textfield", + "CupertinoTimerPicker": "flet.controls.cupertino.cupertino_timer_picker", + "CupertinoTimerPickerMode": "flet.controls.cupertino.cupertino_timer_picker", + "CupertinoTintedButton": "flet.controls.cupertino.cupertino_tinted_button", + "DataCell": "flet.controls.material.datatable", + "DataChannel": "flet.data_channel", + "DataChannelOpenEvent": "flet.data_channel", + "DataColumn": "flet.controls.material.datatable", + "DataColumnSortEvent": "flet.controls.material.datatable", + "DataRow": "flet.controls.material.datatable", + "DataTable": "flet.controls.material.datatable", + "DataTableTheme": "flet.controls.theme", + "DatePicker": "flet.controls.material.date_picker", + "DatePickerEntryMode": "flet.controls.material.date_picker", + "DatePickerEntryModeChangeEvent": "flet.controls.material.date_picker", + "DatePickerMode": "flet.controls.material.date_picker", + "DatePickerTheme": "flet.controls.theme", + "DateRangePicker": "flet.controls.material.date_range_picker", + "DateTimeValue": "flet.controls.duration", + "DecorationImage": "flet.controls.box", + "DeviceInfo": "flet.controls.device_info", + "DeviceOrientation": "flet.controls.types", + "DialogControl": "flet.controls.dialog_control", + "DialogTheme": "flet.controls.theme", + "DismissDirection": "flet.controls.material.snack_bar", + "Dismissible": "flet.controls.core.dismissible", + "DismissibleDismissEvent": "flet.controls.core.dismissible", + "DismissibleUpdateEvent": "flet.controls.core.dismissible", + "Divider": "flet.controls.material.divider", + "DividerTheme": "flet.controls.theme", + "DragDownEvent": "flet.controls.events", + "DragEndEvent": "flet.controls.events", + "DragStartEvent": "flet.controls.events", + "DragTarget": "flet.controls.core.drag_target", + "DragTargetEvent": "flet.controls.core.drag_target", + "DragTargetLeaveEvent": "flet.controls.core.drag_target", + "DragUpdateEvent": "flet.controls.events", + "DragWillAcceptEvent": "flet.controls.core.drag_target", + "Draggable": "flet.controls.core.draggable", + "Dropdown": "flet.controls.material.dropdown", + "DropdownM2": "flet.controls.material.dropdownm2", + "DropdownOption": "flet.controls.material.dropdown", + "DropdownTheme": "flet.controls.theme", + "Duration": "flet.controls.duration", + "DurationValue": "flet.controls.duration", + "ElevatedButton": "flet.controls.material.elevated_button", + "Event": "flet.controls.control_event", + "EventControlType": "flet.controls.control_event", + "EventHandler": "flet.controls.control_event", + "ExpansionPanel": "flet.controls.material.expansion_panel", + "ExpansionPanelList": "flet.controls.material.expansion_panel", + "ExpansionPanelListChangeEvent": "flet.controls.material.expansion_panel", + "ExpansionTile": "flet.controls.material.expansion_tile", + "ExpansionTileTheme": "flet.controls.theme", + "FilePicker": "flet.controls.services.file_picker", + "FilePickerFile": "flet.controls.services.file_picker", + "FilePickerFileType": "flet.controls.services.file_picker", + "FilePickerUploadEvent": "flet.controls.services.file_picker", + "FilePickerUploadFile": "flet.controls.services.file_picker", + "FilledButton": "flet.controls.material.filled_button", + "FilledButtonTheme": "flet.controls.theme", + "FilledIconButton": "flet.controls.material.icon_button", + "FilledTonalButton": "flet.controls.material.filled_tonal_button", + "FilledTonalIconButton": "flet.controls.material.icon_button", + "FilterQuality": "flet.controls.box", + "FletApp": "flet.controls.core.flet_app", + "FletAppOutputEvent": "flet.controls.core.flet_app", + "FletException": "flet.controls.exceptions", + "FletPageDisconnectedException": "flet.controls.exceptions", + "FletUnimplementedPlatformException": "flet.controls.exceptions", + "FletUnsupportedPlatformException": "flet.controls.exceptions", + "Flip": "flet.controls.transform", + "FloatingActionButton": "flet.controls.material.floating_action_button", + "FloatingActionButtonLocation": "flet.controls.types", + "FloatingActionButtonTheme": "flet.controls.theme", + "FontWeight": "flet.controls.types", + "ForcePressEvent": "flet.controls.events", + "FormFieldControl": "flet.controls.material.form_field_control", + "GestureDetector": "flet.controls.core.gesture_detector", + "Gradient": "flet.controls.gradients", + "GradientTileMode": "flet.controls.gradients", + "GridView": "flet.controls.core.grid_view", + "Gyroscope": "flet.controls.services.gyroscope", + "GyroscopeReadingEvent": "flet.controls.services.gyroscope", + "HapticFeedback": "flet.controls.services.haptic_feedback", + "Hero": "flet.controls.core.hero", + "HoverEvent": "flet.controls.events", + "Icon": "flet.controls.core.icon", + "IconButton": "flet.controls.material.icon_button", + "IconButtonTheme": "flet.controls.theme", + "IconData": "flet.controls.icon_data", + "IconDataOrControl": "flet.controls.types", + "IconTheme": "flet.controls.theme", + "Icons": "flet.controls.material.icons", + "IdCounter": "flet.controls.id_counter", + "Image": "flet.controls.core.image", + "ImageRepeat": "flet.controls.types", + "InputBorder": "flet.controls.material.form_field_control", + "InputFilter": "flet.controls.material.textfield", + "InteractiveViewer": "flet.controls.core.interactive_viewer", + "IosDeviceInfo": "flet.controls.device_info", + "IosUtsname": "flet.controls.device_info", + "Key": "flet.controls.keys", + "KeyDownEvent": "flet.controls.core.keyboard_listener", + "KeyRepeatEvent": "flet.controls.core.keyboard_listener", + "KeyUpEvent": "flet.controls.core.keyboard_listener", + "KeyValue": "flet.controls.keys", + "KeyboardEvent": "flet.controls.page", + "KeyboardListener": "flet.controls.core.keyboard_listener", + "KeyboardType": "flet.controls.material.textfield", + "LabelPosition": "flet.controls.types", + "LaunchMode": "flet.controls.services.url_launcher", + "LayoutControl": "flet.controls.layout_control", + "LayoutSizeChangeEvent": "flet.controls.layout_control", + "LinearGradient": "flet.controls.gradients", + "LinuxDeviceInfo": "flet.controls.device_info", + "ListTile": "flet.controls.material.list_tile", + "ListTileStyle": "flet.controls.material.list_tile", + "ListTileTheme": "flet.controls.theme", + "ListTileTitleAlignment": "flet.controls.material.list_tile", + "ListView": "flet.controls.core.list_view", + "Locale": "flet.controls.types", + "LocaleChangeEvent": "flet.controls.page", + "LocaleConfiguration": "flet.controls.types", + "LocationInfo": "flet.components.router", + "LoginEvent": "flet.controls.page", + "LongPressDownEvent": "flet.controls.events", + "LongPressEndEvent": "flet.controls.events", + "LongPressMoveUpdateEvent": "flet.controls.events", + "LongPressStartEvent": "flet.controls.events", + "MacOsDeviceInfo": "flet.controls.device_info", + "Magnetometer": "flet.controls.services.magnetometer", + "MagnetometerReadingEvent": "flet.controls.services.magnetometer", + "MainAxisAlignment": "flet.controls.types", + "Margin": "flet.controls.margin", + "MarginValue": "flet.controls.margin", + "Markdown": "flet.controls.core.markdown", + "MarkdownCodeTheme": "flet.controls.core.markdown", + "MarkdownCustomCodeTheme": "flet.controls.core.markdown", + "MarkdownExtensionSet": "flet.controls.core.markdown", + "MarkdownStyleSheet": "flet.controls.core.markdown", + "Matrix4": "flet.controls.transform", + "MenuBar": "flet.controls.material.menu_bar", + "MenuItemButton": "flet.controls.material.menu_item_button", + "MenuStyle": "flet.controls.material.menu_bar", + "MergeSemantics": "flet.controls.core.merge_semantics", + "MouseCursor": "flet.controls.types", + "MultiTapEvent": "flet.controls.events", + "MultiView": "flet.controls.multi_view", + "MultiViewAddEvent": "flet.controls.page", + "MultiViewRemoveEvent": "flet.controls.page", + "NavigationBar": "flet.controls.material.navigation_bar", + "NavigationBarDestination": "flet.controls.material.navigation_bar", + "NavigationBarLabelBehavior": "flet.controls.material.navigation_bar", + "NavigationBarTheme": "flet.controls.theme", + "NavigationDrawer": "flet.controls.material.navigation_drawer", + "NavigationDrawerDestination": "flet.controls.material.navigation_drawer", + "NavigationDrawerTheme": "flet.controls.theme", + "NavigationRail": "flet.controls.material.navigation_rail", + "NavigationRailDestination": "flet.controls.material.navigation_rail", + "NavigationRailLabelType": "flet.controls.material.navigation_rail", + "NavigationRailTheme": "flet.controls.theme", + "NotchShape": "flet.controls.types", + "Number": "flet.controls.types", + "NumbersOnlyInputFilter": "flet.controls.material.textfield", + "Observable": "flet.components.observable", + "Offset": "flet.controls.transform", + "OffsetValue": "flet.controls.transform", + "OnReorderEvent": "flet.controls.material.reorderable_list_view", + "OnScrollEvent": "flet.controls.scrollable_control", + "Orientation": "flet.controls.types", + "OutlinedBorder": "flet.controls.buttons", + "OutlinedButton": "flet.controls.material.outlined_button", + "OutlinedButtonTheme": "flet.controls.theme", + "OutlinedIconButton": "flet.controls.material.icon_button", + "OverlayVisibilityMode": "flet.controls.cupertino.cupertino_textfield", + "Padding": "flet.controls.padding", + "PaddingValue": "flet.controls.padding", + "Page": "flet.controls.page", + "PageMediaData": "flet.controls.base_page", + "PagePlatform": "flet.controls.types", + "PageResizeEvent": "flet.controls.base_page", + "PageTransitionTheme": "flet.controls.theme", + "PageTransitionsTheme": "flet.controls.theme", + "PageView": "flet.controls.core.page_view", + "Pagelet": "flet.controls.core.pagelet", + "Paint": "flet.controls.painting", + "PaintGradient": "flet.controls.painting", + "PaintLinearGradient": "flet.controls.painting", + "PaintRadialGradient": "flet.controls.painting", + "PaintSweepGradient": "flet.controls.painting", + "PaintingStyle": "flet.controls.painting", + "Placeholder": "flet.controls.core.placeholder", + "PlatformBrightnessChangeEvent": "flet.controls.page", + "PointerDeviceType": "flet.controls.types", + "PointerEvent": "flet.controls.events", + "PopupMenuButton": "flet.controls.material.popup_menu_button", + "PopupMenuItem": "flet.controls.material.popup_menu_button", + "PopupMenuPosition": "flet.controls.material.popup_menu_button", + "PopupMenuTheme": "flet.controls.theme", + "ProgressBar": "flet.controls.material.progress_bar", + "ProgressIndicatorTheme": "flet.controls.theme", + "ProgressRing": "flet.controls.material.progress_ring", + "PubSubClient": "flet.pubsub.pubsub_client", + "PubSubHub": "flet.pubsub.pubsub_hub", + "QueryString": "flet.controls.query_string", + "RadialGradient": "flet.controls.gradients", + "Radio": "flet.controls.material.radio", + "RadioGroup": "flet.controls.material.radio_group", + "RadioTheme": "flet.controls.theme", + "RangeSlider": "flet.controls.material.range_slider", + "RawImage": "flet.controls.core.raw_image", + "Rect": "flet.controls.geometry", + "Ref": "flet.controls.ref", + "ReorderableDragHandle": "flet.controls.core.reorderable_drag_handle", + "ReorderableListView": "flet.controls.material.reorderable_list_view", + "ResponsiveNumber": "flet.controls.types", + "ResponsiveRow": "flet.controls.core.responsive_row", + "ResponsiveRowBreakpoint": "flet.controls.types", + "Rotate": "flet.controls.transform", + "RotateValue": "flet.controls.transform", + "RotatedBox": "flet.controls.core.rotated_box", + "RoundedRectangleBorder": "flet.controls.buttons", + "Route": "flet.components.router", + "RouteChangeEvent": "flet.controls.page", + "RouteUrlStrategy": "flet.controls.types", + "Router": "flet.components.router", + "Row": "flet.controls.core.row", + "SafeArea": "flet.controls.core.safe_area", + "Scale": "flet.controls.transform", + "ScaleEndEvent": "flet.controls.events", + "ScaleStartEvent": "flet.controls.events", + "ScaleUpdateEvent": "flet.controls.events", + "ScaleValue": "flet.controls.transform", + "ScreenBrightness": "flet.controls.services.screen_brightness", + "ScreenBrightnessChangeEvent": "flet.controls.services.screen_brightness", + "Screenshot": "flet.controls.core.screenshot", + "ScrollDirection": "flet.controls.scrollable_control", + "ScrollEvent": "flet.controls.events", + "ScrollKey": "flet.controls.keys", + "ScrollMode": "flet.controls.types", + "ScrollType": "flet.controls.scrollable_control", + "ScrollableControl": "flet.controls.scrollable_control", + "Scrollbar": "flet.controls.scrollable_control", + "ScrollbarOrientation": "flet.controls.scrollable_control", + "ScrollbarTheme": "flet.controls.theme", + "SearchBar": "flet.controls.material.search_bar", + "SearchBarTheme": "flet.controls.theme", + "SearchViewTheme": "flet.controls.theme", + "Segment": "flet.controls.material.segmented_button", + "SegmentedButton": "flet.controls.material.segmented_button", + "SegmentedButtonTheme": "flet.controls.theme", + "SelectionArea": "flet.controls.material.selection_area", + "Semantics": "flet.controls.core.semantics", + "SemanticsService": "flet.controls.services.semantics_service", + "SensorErrorEvent": "flet.controls.services.sensor_error_event", + "Service": "flet.controls.services.service", + "ShaderMask": "flet.controls.core.shader_mask", + "ShakeDetector": "flet.controls.services.shake_detector", + "ShapeBorder": "flet.controls.buttons", + "Share": "flet.controls.services.share", + "ShareCupertinoActivityType": "flet.controls.services.share", + "ShareFile": "flet.controls.services.share", + "ShareResult": "flet.controls.services.share", + "ShareResultStatus": "flet.controls.services.share", + "SharedPreferences": "flet.controls.services.shared_preferences", + "Shimmer": "flet.controls.core.shimmer", + "ShimmerDirection": "flet.controls.core.shimmer", + "Size": "flet.controls.geometry", + "Slider": "flet.controls.material.slider", + "SliderInteraction": "flet.controls.material.slider", + "SliderTheme": "flet.controls.theme", + "SnackBar": "flet.controls.material.snack_bar", + "SnackBarAction": "flet.controls.material.snack_bar", + "SnackBarBehavior": "flet.controls.material.snack_bar", + "SnackBarTheme": "flet.controls.theme", + "Stack": "flet.controls.core.stack", + "StackFit": "flet.controls.core.stack", + "StadiumBorder": "flet.controls.buttons", + "StoragePaths": "flet.controls.services.storage_paths", + "StrOrControl": "flet.controls.types", + "StrokeCap": "flet.controls.types", + "StrokeJoin": "flet.controls.types", + "StrutStyle": "flet.controls.text_style", + "SubmenuButton": "flet.controls.material.submenu_button", + "SupportsStr": "flet.controls.types", + "SweepGradient": "flet.controls.gradients", + "Switch": "flet.controls.material.switch", + "SwitchTheme": "flet.controls.theme", + "SystemOverlayStyle": "flet.controls.theme", + "Tab": "flet.controls.material.tabs", + "TabAlignment": "flet.controls.material.tabs", + "TabBar": "flet.controls.material.tabs", + "TabBarHoverEvent": "flet.controls.material.tabs", + "TabBarIndicatorSize": "flet.controls.material.tabs", + "TabBarTheme": "flet.controls.theme", + "TabBarView": "flet.controls.material.tabs", + "TabIndicatorAnimation": "flet.controls.material.tabs", + "Tabs": "flet.controls.material.tabs", + "TapEvent": "flet.controls.events", + "TapMoveEvent": "flet.controls.events", + "TemplateRoute": "flet.controls.template_route", + "Text": "flet.controls.core.text", + "TextAffinity": "flet.controls.core.text", + "TextAlign": "flet.controls.types", + "TextBaseline": "flet.controls.text_style", + "TextButton": "flet.controls.material.text_button", + "TextButtonTheme": "flet.controls.theme", + "TextCapitalization": "flet.controls.material.textfield", + "TextDecoration": "flet.controls.text_style", + "TextDecorationStyle": "flet.controls.text_style", + "TextField": "flet.controls.material.textfield", + "TextOnlyInputFilter": "flet.controls.material.textfield", + "TextOverflow": "flet.controls.text_style", + "TextSelection": "flet.controls.core.text", + "TextSelectionChangeCause": "flet.controls.core.text", + "TextSelectionChangeEvent": "flet.controls.core.text", + "TextSpan": "flet.controls.core.text_span", + "TextStyle": "flet.controls.text_style", + "TextTheme": "flet.controls.theme", + "TextThemeStyle": "flet.controls.text_style", + "Theme": "flet.controls.theme", + "ThemeMode": "flet.controls.types", + "TileAffinity": "flet.controls.material.expansion_tile", + "TimePicker": "flet.controls.material.time_picker", + "TimePickerEntryMode": "flet.controls.material.time_picker", + "TimePickerEntryModeChangeEvent": "flet.controls.material.time_picker", + "TimePickerHourFormat": "flet.controls.material.time_picker", + "TimePickerTheme": "flet.controls.theme", + "Tooltip": "flet.controls.material.tooltip", + "TooltipTheme": "flet.controls.theme", + "TooltipTriggerMode": "flet.controls.material.tooltip", + "TooltipValue": "flet.controls.material.tooltip", + "Transform": "flet.controls.transform", + "TransparentPointer": "flet.controls.core.transparent_pointer", + "UnderlineTabIndicator": "flet.controls.material.tabs", + "Url": "flet.controls.types", + "UrlLauncher": "flet.controls.services.url_launcher", + "UrlTarget": "flet.controls.types", + "UserAccelerometer": "flet.controls.services.user_accelerometer", + "UserAccelerometerReadingEvent": "flet.controls.services.user_accelerometer", + "Value": "flet.controls.base_control", + "ValueKey": "flet.controls.keys", + "VerticalAlignment": "flet.controls.types", + "VerticalDivider": "flet.controls.material.vertical_divider", + "View": "flet.controls.core.view", + "ViewPopEvent": "flet.controls.page", + "ViewsPopUntilEvent": "flet.controls.page", + "VisualDensity": "flet.controls.types", + "Wakelock": "flet.controls.services.wakelock", + "WebBrowserName": "flet.controls.device_info", + "WebDeviceInfo": "flet.controls.device_info", + "WebRenderer": "flet.controls.types", + "WebViewConfiguration": "flet.controls.services.url_launcher", + "Window": "flet.controls.core.window", + "WindowDragArea": "flet.controls.core.window_drag_area", + "WindowEvent": "flet.controls.core.window", + "WindowEventType": "flet.controls.core.window", + "WindowResizeEdge": "flet.controls.core.window", + "WindowsDeviceInfo": "flet.controls.device_info", + "alignment": "flet.controls", + "app": "flet.app", + "app_async": "flet.app", + "border": "flet.controls", + "border_radius": "flet.controls", + "component": "flet.components.component_decorator", + "context": "flet.controls.context", + "control": "flet.controls.base_control", + "create_context": "flet.components.hooks.use_context", + "cupertino_colors": "flet.controls.cupertino", + "cupertino_icons": "flet.controls.cupertino", + "dropdown": "flet.controls.material", + "dropdownm2": "flet.controls.material", + "icons": "flet.controls.material", + "is_route_active": "flet.components.router", + "margin": "flet.controls", + "memo": "flet.components.memo", + "observable": "flet.components.observable", + "on_mounted": "flet.components.hooks.use_effect", + "on_unmounted": "flet.components.hooks.use_effect", + "on_updated": "flet.components.hooks.use_effect", + "padding": "flet.controls", + "run": "flet.app", + "run_async": "flet.app", + "unwrap_component": "flet.components.public_utils", + "use_callback": "flet.components.hooks.use_callback", + "use_context": "flet.components.hooks.use_context", + "use_dialog": "flet.components.hooks.use_dialog", + "use_effect": "flet.components.hooks.use_effect", + "use_memo": "flet.components.hooks.use_memo", + "use_ref": "flet.components.hooks.use_ref", + "use_route_loader_data": "flet.components.router", + "use_route_location": "flet.components.router", + "use_route_outlet": "flet.components.router", + "use_route_params": "flet.components.router", + "use_state": "flet.components.hooks.use_state", + "use_view_path": "flet.components.router", + "value": "flet.controls.base_control", } def __getattr__(name: str): - if name in _THEME_EXPORTS: - from flet.controls import theme - - return getattr(theme, name) - if name == "Icons": - from flet.controls.material.icons import Icons - - return Icons - if name == "CupertinoIcons": - from flet.controls.cupertino.cupertino_icons import CupertinoIcons + module_path = _LAZY.get(name) + if module_path is None: + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + import importlib - return CupertinoIcons - if name == "icons": - import importlib + module = importlib.import_module(module_path) + try: + value = getattr(module, name) + except AttributeError: + # `name` is itself a submodule (e.g. `flet.alignment`), not an attribute. + value = importlib.import_module(f"{module_path}.{name}") + globals()[name] = value # cache: subsequent access skips __getattr__ + return value - return importlib.import_module("flet.controls.material.icons") - if name == "cupertino_icons": - import importlib - return importlib.import_module("flet.controls.cupertino.cupertino_icons") - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") +def __dir__(): + return list(__all__) diff --git a/sdk/python/packages/flet/src/flet/app.py b/sdk/python/packages/flet/src/flet/app.py index 24061c5e44..1c6a82762b 100644 --- a/sdk/python/packages/flet/src/flet/app.py +++ b/sdk/python/packages/flet/src/flet/app.py @@ -41,7 +41,12 @@ """ -@deprecated("Use run() instead.", version="0.80.0", show_parentheses=True) +@deprecated( + "Use run() instead.", + docs_reason="Use [`run()`][flet.run] instead.", + version="0.80.0", + show_parentheses=True, +) def app(*args, **kwargs): new_args = list(args) if "target" in kwargs: @@ -49,7 +54,12 @@ def app(*args, **kwargs): return run(*new_args, **kwargs) -@deprecated("Use run() instead.", version="0.80.0", show_parentheses=True) +@deprecated( + "Use run_async() instead.", + docs_reason="Use [`run_async()`][flet.run_async] instead.", + version="0.80.0", + show_parentheses=True, +) def app_async(*args, **kwargs): new_args = list(args) if "target" in kwargs: @@ -94,7 +104,7 @@ def run( target: Deprecated alias for `main`. Returns: - When `export_asgi_app=True`, returns a FastAPI ASGI app. + A FastAPI ASGI app when `export_asgi_app=True`. Otherwise, runs the app and returns `None`. """ if is_pyodide(): @@ -252,15 +262,26 @@ def exit_gracefully(signum, frame): signal.signal(signal.SIGINT, exit_gracefully) signal.signal(signal.SIGTERM, exit_gracefully) - conn = ( - await __run_socket_server( + # Embedded runtime can opt into the in-process dart_bridge transport + # (provided by libdart_bridge from flet-dev/serious-python) by setting + # FLET_DART_BRIDGE_PORT. Falls back to the existing socket / web + # transports when the env var is absent. + bridge_port_env = os.getenv("FLET_DART_BRIDGE_PORT") + if is_embedded() and bridge_port_env: + conn = await __run_dart_bridge_server( + port=int(bridge_port_env), + main=main or target, + before_main=before_main, + ) + elif is_socket_server: + conn = await __run_socket_server( port=port, main=main or target, before_main=before_main, blocking=is_embedded(), ) - if is_socket_server - else await __run_web_server( + else: + conn = await __run_web_server( main=main or target, before_main=before_main, host=host, @@ -273,7 +294,6 @@ def exit_gracefully(signum, frame): no_cdn=no_cdn, on_startup=on_app_startup, ) - ) logger.info("Flet app has started...") @@ -305,6 +325,13 @@ def exit_gracefully(signum, frame): with contextlib.suppress(KeyboardInterrupt): await terminate.wait() + elif is_embedded() and bridge_port_env: + # dart_bridge has no serve_forever (no socket accept loop) — the + # embedded interpreter would otherwise exit as soon as the user's + # main() returns. Park here until the host process tears us down. + with contextlib.suppress(KeyboardInterrupt): + await terminate.wait() + elif view == AppView.WEB_BROWSER or view is None or force_web_server: with contextlib.suppress(KeyboardInterrupt): await terminate.wait() @@ -400,6 +427,158 @@ async def __run_socket_server( return conn +class _DartBridgeServerHandle: + """ + Forwarding facade over the currently-active `FletDartBridgeServer`. + + On Android process reuse (libdart_bridge stays loaded, the Dart VM + restarts with fresh native port numbers), this handle replaces the + underlying connection in place via `_swap_to_port`. The outer caller + in `run_async` keeps holding the same handle through restarts, so + its `finally: await conn.close()` always closes whichever connection + is current at process-teardown time. + """ + + def __init__(self, build_conn): + # `build_conn` is a callable that creates a fresh + # FletDartBridgeServer for the given port — used both initially + # and on every restart so we don't capture stale args. + self._build_conn = build_conn + self._conn = None # type: ignore[assignment] + # Pending swap-in tasks during a restart — tracked so close() + # can wait for an in-flight swap rather than racing. + self._swap_lock = asyncio.Lock() + + @property + def page_url(self) -> str: + return self._conn.page_url if self._conn is not None else "" + + @property + def pubsubhub(self): + # `flet.app.run_async` doesn't touch this, but keep parity in case + # downstream callers (tests, alternative entry points) do. + return self._conn.pubsubhub if self._conn is not None else None + + async def start(self, port: int): + self._conn = self._build_conn(port) + await self._conn.start() + + async def _swap_to_port(self, port: int): + """Close the current connection and bring up a new one on `port`.""" + async with self._swap_lock: + old = self._conn + new = self._build_conn(port) + await new.start() + self._conn = new + if old is not None: + try: + await old.close() + except Exception: + logger.warning( + "Error closing previous dart_bridge connection during " + "session restart", + exc_info=True, + ) + + async def close(self): + async with self._swap_lock: + if self._conn is not None: + await self._conn.close() + self._conn = None + + +async def __run_dart_bridge_server( + port: int, + main: Optional[AppCallable] = None, + before_main: Optional[AppCallable] = None, +): + """ + Start Flet dart_bridge transport and return active connection object. + + This transport exchanges the same MsgPack-framed protocol as + `__run_socket_server`, but over the in-process `dart_bridge` byte channel + instead of a Unix socket — eliminating the socket file, kernel context + switches, and the connect/handshake retry loop for embedded apps. + + The returned object is a `_DartBridgeServerHandle` that forwards to the + current `FletDartBridgeServer` and swaps it transparently on Android + process reuse — a `dart_bridge.add_session_restart_handler` callback + rebuilds the connection on the new Dart native port when the new Dart + VM signals fresh ports. + + Args: + port: Dart native port (passed in via env var by the embedding side; + doubles as the keyed channel identifier). + main: User app entry handler. + before_main: Optional hook called before `main`. + + Returns: + Started dart_bridge-server handle. + """ + # Imported lazily so non-embedded runs (web server, native desktop) never + # try to load libdart_bridge. + from flet.messaging.flet_dart_bridge_server import FletDartBridgeServer + + loop = asyncio.get_running_loop() + executor = concurrent.futures.ThreadPoolExecutor() + + def _build_conn(p: int) -> FletDartBridgeServer: + return FletDartBridgeServer( + loop=loop, + port=p, + on_session_created=__get_on_session_created(main), + before_main=before_main, + executor=executor, + ) + + handle = _DartBridgeServerHandle(_build_conn) + await handle.start(port) + + # Subscribe to Dart VM restart events. The C-side + # `dart_bridge_signal_dart_session` (libdart_bridge >= 1.3.0) fires + # every registered Python callback with `{label: new_port}`. On + # pre-1.3.0 binaries the symbol is absent and Dart-side + # `signalDartSession` is a no-op, so this handler never fires and the + # flow degrades to the existing "one-Dart-VM lifetime" behavior — no + # crash, no regression. + try: + import dart_bridge # type: ignore[import-not-found] + except ImportError: + # Not running inside libdart_bridge (e.g. unit tests). Skip + # restart subscription; nothing to swap to. + return handle + + add_handler = getattr(dart_bridge, "add_session_restart_handler", None) + if add_handler is None: + # Older libdart_bridge without the restart API. Same fallback as + # above — first session only. + logger.debug( + "dart_bridge.add_session_restart_handler not available; " + "process-reuse restarts will be unsupported" + ) + return handle + + def _on_session_restart(port_map): + # Called from libdart_bridge (under the GIL, possibly off the + # asyncio loop's thread). Marshal back onto the loop and run the + # swap as a regular asyncio task. + new_port = int(port_map.get("protocol", 0)) + if new_port <= 0 or new_port == port: + return + logger.info( + "Dart VM restart detected; rebinding FletDartBridgeServer " + "from port %s → %s", + port, + new_port, + ) + loop.call_soon_threadsafe( + lambda: asyncio.create_task(handle._swap_to_port(new_port)) + ) + + add_handler(_on_session_restart) + return handle + + async def __run_web_server( main: Optional[AppCallable], before_main: Optional[AppCallable], diff --git a/sdk/python/packages/flet/src/flet/components/component.py b/sdk/python/packages/flet/src/flet/components/component.py index 085babbfd5..b151a7c1a1 100644 --- a/sdk/python/packages/flet/src/flet/components/component.py +++ b/sdk/python/packages/flet/src/flet/components/component.py @@ -68,8 +68,20 @@ class Component(BaseControl): """ fn: Callable[..., Any] = field(metadata={"skip": True}) + """ + Component function called to produce the rendered body. + """ + args: tuple[Any, ...] = field(default_factory=tuple, metadata={"skip": True}) + """ + Positional arguments passed to :attr:`fn`. + """ + kwargs: dict[str, Any] = field(default_factory=dict, metadata={"skip": True}) + """ + Keyword arguments passed to :attr:`fn`. + """ + _parent_component: weakref.ref[Component] | None = field( default=None, metadata={"skip": True} ) @@ -78,6 +90,10 @@ class Component(BaseControl): ) _contexts: dict[object, Any] = field(default_factory=dict, metadata={"skip": True}) memoized: bool = field(default=False, metadata={"skip": True}) + """ + Whether this component can skip rendering when arguments are unchanged. + """ + _stale: bool = field(default=False, metadata={"skip": True}) visible: bool = True diff --git a/sdk/python/packages/flet/src/flet/components/component_owned.py b/sdk/python/packages/flet/src/flet/components/component_owned.py index 9247fc8c79..c00b06de78 100644 --- a/sdk/python/packages/flet/src/flet/components/component_owned.py +++ b/sdk/python/packages/flet/src/flet/components/component_owned.py @@ -16,6 +16,9 @@ class ComponentOwned: """ owner: InitVar["Component"] + """ + Component that owns this object. + """ def __post_init__(self, owner: "Component") -> None: self._component = weakref.ref(owner) diff --git a/sdk/python/packages/flet/src/flet/components/hooks/use_context.py b/sdk/python/packages/flet/src/flet/components/hooks/use_context.py index db1830e342..bc6a1449b3 100644 --- a/sdk/python/packages/flet/src/flet/components/hooks/use_context.py +++ b/sdk/python/packages/flet/src/flet/components/hooks/use_context.py @@ -1,11 +1,6 @@ from collections.abc import Callable from dataclasses import dataclass -from typing import TypeVar, cast - -try: - from typing import Protocol -except ImportError: - from typing_extensions import Protocol +from typing import Protocol, TypeVar, cast from flet.components.hooks.hook import Hook from flet.components.observable import Observable diff --git a/sdk/python/packages/flet/src/flet/components/hooks/use_state.py b/sdk/python/packages/flet/src/flet/components/hooks/use_state.py index c78de6d9c8..3df5d19cd9 100644 --- a/sdk/python/packages/flet/src/flet/components/hooks/use_state.py +++ b/sdk/python/packages/flet/src/flet/components/hooks/use_state.py @@ -15,12 +15,12 @@ @dataclass class StateHook(Hook): """ - Hook state container backing :func:`~flet.use_state`. + Hook state container backing :func:`flet.use_state`. """ value: Any """ - Current state value returned by :func:`~flet.use_state`. + Current state value returned by :func:`flet.use_state`. Updated by the `set_state` setter. It may hold any Python value, including an :class:`~flet.Observable`. diff --git a/sdk/python/packages/flet/src/flet/components/observable.py b/sdk/python/packages/flet/src/flet/components/observable.py index 31d4e4f79f..d7cca21194 100644 --- a/sdk/python/packages/flet/src/flet/components/observable.py +++ b/sdk/python/packages/flet/src/flet/components/observable.py @@ -59,6 +59,9 @@ class ObservableSubscription(ComponentOwned): """ observable: InitVar[Observable] + """ + Observable object to subscribe to. + """ def __post_init__(self, owner: Component, observable: Observable) -> None: super().__post_init__(owner) diff --git a/sdk/python/packages/flet/src/flet/components/public_utils.py b/sdk/python/packages/flet/src/flet/components/public_utils.py index 842e9e7982..62c4f3e7d1 100644 --- a/sdk/python/packages/flet/src/flet/components/public_utils.py +++ b/sdk/python/packages/flet/src/flet/components/public_utils.py @@ -1,6 +1,12 @@ -from typing import Any +from typing import TYPE_CHECKING, Any, Optional -from flet.components.component import Component +if TYPE_CHECKING: + from flet.components.component import Component + +# Cached lazily on first call so merely importing this helper (done by Page / +# BasePage) doesn't pull the whole components subsystem into the cold-start +# import graph for apps that don't use components. +_Component: "Optional[type[Component]]" = None def unwrap_component(c: Any): @@ -17,7 +23,12 @@ def unwrap_component(c: Any): The first non-`Component` value in the chain (for example a control, list of controls/views, or `None`). """ + global _Component + if _Component is None: + from flet.components.component import Component + + _Component = Component p = c - while isinstance(p, Component): + while isinstance(p, _Component): p = p._b return p diff --git a/sdk/python/packages/flet/src/flet/controls/animation.py b/sdk/python/packages/flet/src/flet/controls/animation.py index 0ecc2cc0c7..84df2b5c91 100644 --- a/sdk/python/packages/flet/src/flet/controls/animation.py +++ b/sdk/python/packages/flet/src/flet/controls/animation.py @@ -235,8 +235,8 @@ class Animation: Explicit animation configuration for animatable control properties. Properties that accept animation usually also support shorthand values via - :data:`~flet.AnimationValue`: - - `True`: enables a default `1000ms` :attr:`~flet.AnimationCurve.LINEAR` animation. + :data:`flet.AnimationValue`: + - `True`: enables a default `1000ms` :attr:`flet.AnimationCurve.LINEAR` animation. - `int`: interpreted as animation duration in milliseconds with a linear curve. """ diff --git a/sdk/python/packages/flet/src/flet/controls/base_control.py b/sdk/python/packages/flet/src/flet/controls/base_control.py index 95e29de41c..a064b6e39f 100644 --- a/sdk/python/packages/flet/src/flet/controls/base_control.py +++ b/sdk/python/packages/flet/src/flet/controls/base_control.py @@ -75,6 +75,8 @@ def control( *, isolated: Optional[bool] = None, post_init_args: int = 1, + categories: Optional[tuple[str, ...]] = None, + tags: Optional[tuple[str, ...]] = None, **dataclass_kwargs: Any, ) -> Callable[[type[T]], type[T]]: """ @@ -92,6 +94,8 @@ def control( *, isolated: Optional[bool] = None, post_init_args: int = 1, + categories: Optional[tuple[str, ...]] = None, + tags: Optional[tuple[str, ...]] = None, **dataclass_kwargs: Any, ) -> Union[type[T], Callable[[type[T]], type[T]]]: """ @@ -103,6 +107,8 @@ def control( isolated: If `True`, marks the control as isolated. An isolated control is excluded from page updates when its parent control is updated. post_init_args: Number of InitVar arguments to pass to __post_init__. + categories: MCP metadata — control categories (e.g. `("input", "form")`). + tags: MCP metadata — descriptive tags (e.g. `("text", "editable")`). dataclass_kwargs: Additional keyword arguments passed to `@dataclass`. Usage: @@ -110,18 +116,32 @@ def control( - Supports `@control("WidgetName")` (with optional arguments) - Supports `@control("WidgetName", post_init_args=1, isolated=True)` to specify the number of `InitVar` arguments and isolation + - Supports `@control("WidgetName", categories=("input",), tags=("text",))` + to add MCP metadata for discovery """ # Case 1: If used as `@control` (without parentheses) if isinstance(dart_widget_name, type): return _apply_control( - dart_widget_name, None, isolated, post_init_args, **dataclass_kwargs + dart_widget_name, + None, + isolated, + post_init_args, + categories=categories, + tags=tags, + **dataclass_kwargs, ) # Case 2: If used as `@control("custom_type", post_init_args=N, isolated=True)` def wrapper(cls: type[T]) -> type[T]: return _apply_control( - cls, dart_widget_name, isolated, post_init_args, **dataclass_kwargs + cls, + dart_widget_name, + isolated, + post_init_args, + categories=categories, + tags=tags, + **dataclass_kwargs, ) return wrapper @@ -132,12 +152,20 @@ def _apply_control( type_name: Optional[str], isolated: Optional[bool], post_init_args: int, + categories: Optional[tuple[str, ...]] = None, + tags: Optional[tuple[str, ...]] = None, **dataclass_kwargs, ) -> type[T]: """Applies @control logic, ensuring compatibility with @dataclass.""" cls = dataclass(**dataclass_kwargs)(cls) # Apply @dataclass first _install_props(cls) # Install Prop descriptors for sparse tracking + # Store MCP metadata for discovery by Flet MCP server + cls.__control_meta__ = { + "categories": tuple(categories) if categories else (), + "tags": tuple(tags) if tags else (), + } + orig_post_init = getattr(cls, "__post_init__", lambda self, *args: None) def new_post_init(self: T, *args): @@ -197,6 +225,9 @@ class BaseControl: """ key: Optional["KeyValue"] = None + """ + A stable key used to preserve control identity across updates. + """ ref: InitVar[Optional[Ref["BaseControl"]]] = None """A reference to this control.""" @@ -362,6 +393,26 @@ def will_unmount(self): controls_log.debug("%s.will_unmount()", self) pass + def get_data_channel(self, channel_id: int): + """ + Resolve the [DataChannel] allocated on the Dart side for this + widget. Pattern: + + on_data_channel_open: Optional[ft.EventHandler[DataChannelOpenEvent]] = None + + def init(self): + self.on_data_channel_open = self._on_open + + def _on_open(self, e): + self._channel = self.get_data_channel(e.channel_id) + + Idempotent — the underlying Connection caches DataChannels by id, + so repeated calls return the same instance. No error path: the id + always comes from a framework-fired event, so by the time this + runs the channel exists on both sides. + """ + return self.page.session.connection.data_channel_for(channel_id) + # public methods def update(self) -> None: """ diff --git a/sdk/python/packages/flet/src/flet/controls/base_page.py b/sdk/python/packages/flet/src/flet/controls/base_page.py index 23a8ce98f2..807bfe4c18 100644 --- a/sdk/python/packages/flet/src/flet/controls/base_page.py +++ b/sdk/python/packages/flet/src/flet/controls/base_page.py @@ -18,8 +18,6 @@ EventHandler, ) from flet.controls.core.view import View -from flet.controls.cupertino.cupertino_app_bar import CupertinoAppBar -from flet.controls.cupertino.cupertino_navigation_bar import CupertinoNavigationBar from flet.controls.dialog_control import DialogControl from flet.controls.duration import DurationValue from flet.controls.keys import ScrollKey @@ -50,6 +48,12 @@ _MANAGED_DIALOG_DISMISS_WRAPPER = "_managed_dialog_dismiss_wrapper" if TYPE_CHECKING: + # Annotation-only (quoted at use sites): deferred so a Page doesn't eagerly + # pull the Cupertino controls (cold-start import cost). + from flet.controls.cupertino.cupertino_app_bar import CupertinoAppBar + from flet.controls.cupertino.cupertino_navigation_bar import ( + CupertinoNavigationBar, + ) from flet.controls.theme import Theme @@ -256,7 +260,7 @@ def handle_page_size(e): - This property is read-only. - To get or set the full window height including window chrome (e.g., title bar and borders) when running a Flet app on desktop, - use the :attr:`~flet.Window.width` property of :attr:`flet.Page.window` \ + use the :attr:`flet.Window.width` property of :attr:`flet.Page.window` \ instead. """ @@ -268,7 +272,7 @@ def handle_page_size(e): - This property is read-only. - To get or set the full window height including window chrome (e.g., title bar and borders) when running a Flet app on desktop, - use the :attr:`~flet.Window.height` property of + use the :attr:`flet.Window.height` property of :attr:`flet.Page.window` instead. """ @@ -401,7 +405,7 @@ def show_dialog(self, dialog: DialogControl) -> None: This method adds the specified `dialog` to the active dialog stack and renders it on the page. - The :attr:`~flet.DialogControl.on_dismiss` handler of the dialog + The :attr:`flet.DialogControl.on_dismiss` handler of the dialog is temporarily wrapped to ensure the dialog is removed from the stack and its dismissal event is triggered appropriately. @@ -596,7 +600,7 @@ def controls(self, value: list[BaseControl]): # appbar @property - def appbar(self) -> Union[AppBar, CupertinoAppBar, None]: + def appbar(self) -> "Union[AppBar, CupertinoAppBar, None]": """ Gets or sets the top application bar (:class:`~flet.AppBar` or \ :class:`~flet.CupertinoAppBar`) for the view. @@ -607,7 +611,7 @@ def appbar(self) -> Union[AppBar, CupertinoAppBar, None]: return self.__root_view().appbar @appbar.setter - def appbar(self, value: Union[AppBar, CupertinoAppBar, None]): + def appbar(self, value: "Union[AppBar, CupertinoAppBar, None]"): self.__root_view().appbar = value # bottom_appbar @@ -625,7 +629,9 @@ def bottom_appbar(self, value: Optional[BottomAppBar]): # navigation_bar @property - def navigation_bar(self) -> Optional[Union[NavigationBar, CupertinoNavigationBar]]: + def navigation_bar( + self, + ) -> "Optional[Union[NavigationBar, CupertinoNavigationBar]]": """ Bottom navigation bar for the root view. """ @@ -635,7 +641,7 @@ def navigation_bar(self) -> Optional[Union[NavigationBar, CupertinoNavigationBar @navigation_bar.setter def navigation_bar( self, - value: Optional[Union[NavigationBar, CupertinoNavigationBar]], + value: "Optional[Union[NavigationBar, CupertinoNavigationBar]]", ): self.__root_view().navigation_bar = value diff --git a/sdk/python/packages/flet/src/flet/controls/buttons.py b/sdk/python/packages/flet/src/flet/controls/buttons.py index b4db55597d..1dfbd5d69b 100644 --- a/sdk/python/packages/flet/src/flet/controls/buttons.py +++ b/sdk/python/packages/flet/src/flet/controls/buttons.py @@ -119,6 +119,12 @@ class CircleBorder(OutlinedBorder): """ eccentricity: Number = 0.0 + """ + Defines how much the circle deforms to fit a rectangle. + + `0.0` keeps the shape circular, touching at least two sides of the rectangle. + `1.0` fully deforms it into an oval touching all sides. + """ def __post_init__(self): self._type = "circle" diff --git a/sdk/python/packages/flet/src/flet/controls/control_event.py b/sdk/python/packages/flet/src/flet/controls/control_event.py index 940938e0c6..3c8bd45cba 100644 --- a/sdk/python/packages/flet/src/flet/controls/control_event.py +++ b/sdk/python/packages/flet/src/flet/controls/control_event.py @@ -113,8 +113,19 @@ class Event(Generic[EventControlType]): """ name: str + """ + The event name. + """ + data: Optional[Any] = field(default=None, kw_only=True) + """ + Optional event payload data. + """ + control: EventControlType = field(repr=False) + """ + The control that emitted the event. + """ @property def page(self) -> Union["Page", "BasePage"]: diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/canvas.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/canvas.py index a06bdcad51..0dba88acf1 100644 --- a/sdk/python/packages/flet/src/flet/controls/core/canvas/canvas.py +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/canvas.py @@ -16,7 +16,7 @@ class CanvasResizeEvent(Event["Canvas"]): """ Event emitted when a :class:`~flet.canvas.Canvas` reports a new rendered size. - This event is delivered through :attr:`~flet.canvas.Canvas.on_resize` + This event is delivered through :attr:`flet.canvas.Canvas.on_resize` and carries the latest measured dimensions in logical pixels. """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/line.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/line.py index 46d02a9b89..6ceb632bf1 100644 --- a/sdk/python/packages/flet/src/flet/controls/core/canvas/line.py +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/line.py @@ -15,7 +15,7 @@ class Line(Shape): Note: The line is always rendered as a stroke, regardless of the value - of :attr:`paint`'s :attr:`~flet.Paint.style` property. + of :attr:`paint`'s :attr:`flet.Paint.style` property. """ x1: Number diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/oval.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/oval.py index 4b7b0e151d..8397c5a96f 100644 --- a/sdk/python/packages/flet/src/flet/controls/core/canvas/oval.py +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/oval.py @@ -14,7 +14,7 @@ class Oval(Shape): Draws an axis-aligned oval that fills the given axis-aligned rectangle with the \ given :attr:`paint`. - The :attr:`~flet.Paint.style` property of :attr:`paint` indicates + The :attr:`flet.Paint.style` property of :attr:`paint` indicates whether this oval is filled, stroked, or both. """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/column.py b/sdk/python/packages/flet/src/flet/controls/core/column.py index fa0625c324..c2cb41eabe 100644 --- a/sdk/python/packages/flet/src/flet/controls/core/column.py +++ b/sdk/python/packages/flet/src/flet/controls/core/column.py @@ -10,7 +10,7 @@ __all__ = ["Column"] -@control("Column") +@control("Column", categories=("layout",), tags=("vertical", "flex", "scrollable")) class Column(LayoutControl, ScrollableControl, AdaptiveControl): """ Arranges child controls vertically, optionally aligning and spacing them within \ diff --git a/sdk/python/packages/flet/src/flet/controls/core/dismissible.py b/sdk/python/packages/flet/src/flet/controls/core/dismissible.py index 24c9f06784..88493ba451 100644 --- a/sdk/python/packages/flet/src/flet/controls/core/dismissible.py +++ b/sdk/python/packages/flet/src/flet/controls/core/dismissible.py @@ -25,8 +25,8 @@ class DismissibleDismissEvent(Event["Dismissible"]): """ Event payload for dismissal confirmation and completion callbacks. - Used by :attr:`~flet.Dismissible.on_confirm_dismiss` and - :attr:`~flet.Dismissible.on_dismiss`. + Used by :attr:`flet.Dismissible.on_confirm_dismiss` and + :attr:`flet.Dismissible.on_dismiss`. """ direction: DismissDirection @@ -173,7 +173,7 @@ class Dismissible(LayoutControl, AdaptiveControl): This dismissible cannot be dragged again until this pending dismissal is resolved. To resolve the pending dismissal, call the - :meth:`~flet.Dismissible.confirm_dismiss` method + :meth:`flet.Dismissible.confirm_dismiss` method passing it a boolean representing the decision. If `True`, then the control will be dismissed, otherwise it will be moved back to its original location. """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/flet_app.py b/sdk/python/packages/flet/src/flet/controls/core/flet_app.py index 62f7e6cc89..5a38f74481 100644 --- a/sdk/python/packages/flet/src/flet/controls/core/flet_app.py +++ b/sdk/python/packages/flet/src/flet/controls/core/flet_app.py @@ -4,6 +4,7 @@ from flet.controls.base_control import control from flet.controls.control_event import ControlEventHandler, Event, EventHandler from flet.controls.layout_control import LayoutControl +from flet.utils.deprecated import deprecated __all__ = ["FletApp", "FletAppOutputEvent"] @@ -59,14 +60,22 @@ class FletApp(LayoutControl): Total time to try reconnecting. """ - show_app_startup_screen: bool = False + boot_screen_name: Optional[str] = None """ - Whether to show the app startup screen. + Name of the boot screen to show while the embedded app starts up. + + When `None`, the built-in `"flet"` boot screen is used. Custom boot screens + are provided by extensions; see the + [boot screen docs](https://flet.dev/docs/publish/#boot-screen). """ - app_startup_screen_message: Optional[str] = None + boot_screen_options: Optional[dict[str, Any]] = None """ - Message to display on the app startup screen. + Options for the boot screen, passed through to the boot screen widget. + + For the built-in `"flet"` screen these include `spinner_size`, + `startup_message`, `bgcolor_light`/`bgcolor_dark`, etc. See the + [boot screen docs](https://flet.dev/docs/publish/#boot-screen). """ app_error_message: Optional[str] = None @@ -89,3 +98,59 @@ class FletApp(LayoutControl): `force_pyodide=True`; root-level Pyodide pages have nowhere to bubble the event. """ + + @property + @deprecated( + reason="Use `boot_screen_options` instead, e.g. " + "boot_screen_options={'spinner_size': 30}.", + version="0.86.0", + delete_version="0.89.0", + ) + def show_app_startup_screen(self) -> bool: + """ + Whether to show the app startup screen. + """ + return bool((self.boot_screen_options or {}).get("spinner_size", 0)) + + @show_app_startup_screen.setter + @deprecated( + reason="Use `boot_screen_options` instead, e.g. " + "boot_screen_options={'spinner_size': 30}.", + version="0.86.0", + delete_version="0.89.0", + ) + def show_app_startup_screen(self, value: bool) -> None: + options = dict(self.boot_screen_options or {}) + if value: + options.setdefault("spinner_size", 30) + else: + options.pop("spinner_size", None) + self.boot_screen_options = options + + @property + @deprecated( + reason="Use `boot_screen_options` instead, e.g. " + "boot_screen_options={'startup_message': '...'}.", + version="0.86.0", + delete_version="0.89.0", + ) + def app_startup_screen_message(self) -> Optional[str]: + """ + Message to display on the app startup screen. + """ + return (self.boot_screen_options or {}).get("startup_message") + + @app_startup_screen_message.setter + @deprecated( + reason="Use `boot_screen_options` instead, e.g. " + "boot_screen_options={'startup_message': '...'}.", + version="0.86.0", + delete_version="0.89.0", + ) + def app_startup_screen_message(self, value: Optional[str]) -> None: + options = dict(self.boot_screen_options or {}) + if value is not None: + options["startup_message"] = value + else: + options.pop("startup_message", None) + self.boot_screen_options = options diff --git a/sdk/python/packages/flet/src/flet/controls/core/gesture_detector.py b/sdk/python/packages/flet/src/flet/controls/core/gesture_detector.py index 687ea62124..96c979bc43 100644 --- a/sdk/python/packages/flet/src/flet/controls/core/gesture_detector.py +++ b/sdk/python/packages/flet/src/flet/controls/core/gesture_detector.py @@ -75,7 +75,11 @@ class GestureDetector(LayoutControl, AdaptiveControl): exclude_from_semantics: bool = False """ - TBD + Whether the gestures of this detector should be excluded from the semantics tree. + + Set this to `True` when the wrapped content already exposes the appropriate + semantic actions and you do not want this detector to add duplicate accessibility + announcements. """ on_force_press_start: Optional[EventHandler[ForcePressEvent["GestureDetector"]]] = ( @@ -109,12 +113,17 @@ class GestureDetector(LayoutControl, AdaptiveControl): trackpad_scroll_causes_scale: bool = False """ - TBD + Whether trackpad scroll gestures should be interpreted as scale gestures. + + When enabled, compatible trackpad pinch/scroll input can trigger + :attr:`on_scale_start`, :attr:`on_scale_update`, and :attr:`on_scale_end`. """ allowed_devices: Optional[list[PointerDeviceType]] = None """ - TBD + Restricts gesture recognition to the specified pointer device types. + + If `None`, gestures from any supported input device can be recognized. """ on_tap: Optional[EventHandler[TapEvent["GestureDetector"]]] = None @@ -490,12 +499,13 @@ class GestureDetector(LayoutControl, AdaptiveControl): on_scale_update: Optional[EventHandler[ScaleUpdateEvent["GestureDetector"]]] = None """ - TBD + Called when the focal point, scale factor, or rotation of an active scale gesture + changes. """ on_scale_end: Optional[EventHandler[ScaleEndEvent["GestureDetector"]]] = None """ - TBD + Called when an active scale gesture ends. """ on_hover: Optional[EventHandler[HoverEvent["GestureDetector"]]] = None @@ -515,5 +525,6 @@ class GestureDetector(LayoutControl, AdaptiveControl): on_scroll: Optional[EventHandler[ScrollEvent["GestureDetector"]]] = None """ - TBD + Called when a pointer scroll event is received, such as a mouse wheel or trackpad + scroll. """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/grid_view.py b/sdk/python/packages/flet/src/flet/controls/core/grid_view.py index b686e249fe..ddfac29574 100644 --- a/sdk/python/packages/flet/src/flet/controls/core/grid_view.py +++ b/sdk/python/packages/flet/src/flet/controls/core/grid_view.py @@ -122,7 +122,13 @@ class GridView(LayoutControl, ScrollableControl, AdaptiveControl): build_controls_on_demand: bool = True """ - TBD + Whether grid children should be built lazily as they become visible. + + When `True`, the grid uses a builder-based implementation and creates child + controls on demand while scrolling. This is the recommended setting for large + collections. + + When `False`, all child controls are built eagerly when the grid is built. """ def __contains__(self, item): diff --git a/sdk/python/packages/flet/src/flet/controls/core/page_view.py b/sdk/python/packages/flet/src/flet/controls/core/page_view.py index d9e4fd36ee..af3b0f3e29 100644 --- a/sdk/python/packages/flet/src/flet/controls/core/page_view.py +++ b/sdk/python/packages/flet/src/flet/controls/core/page_view.py @@ -39,7 +39,7 @@ class PageView(LayoutControl): """ The zero-based index of the currently visible page. - Changing it later on (followed by :meth:`~flet.BaseControl.update`) + Changing it later on (followed by :meth:`flet.BaseControl.update`) jumps to the specified page without animation. Raises: @@ -131,7 +131,7 @@ class PageView(LayoutControl): """ Fired when the visible page changes. - The :attr:`~flet.Event.data` property of the event argument contains + The :attr:`flet.Event.data` property of the event argument contains the index of the new page. """ @@ -203,7 +203,7 @@ async def next_page( ): """ Animates to the next page. Same as calling - :meth:`~flet.PageView.go_to_page` with `selected_index + 1`. + :meth:`flet.PageView.go_to_page` with `selected_index + 1`. Args: animation_duration: Length of the animation. @@ -221,7 +221,7 @@ async def previous_page( ): """ Animates to the previous page. Same as calling - :meth:`~flet.PageView.go_to_page` with `selected_index - 1`. + :meth:`flet.PageView.go_to_page` with `selected_index - 1`. Args: animation_duration: Length of the animation. diff --git a/sdk/python/packages/flet/src/flet/controls/core/raw_image.py b/sdk/python/packages/flet/src/flet/controls/core/raw_image.py new file mode 100644 index 0000000000..e42caaff58 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/raw_image.py @@ -0,0 +1,475 @@ +import asyncio +import contextlib +import io +from collections import deque +from typing import Any, Optional + +from flet.controls.base_control import control +from flet.controls.box import BoxFit, FilterQuality +from flet.controls.control_event import EventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.types import Number +from flet.data_channel import DataChannel, DataChannelOpenEvent + +__all__ = ["RawImage"] + + +@control("RawImage") +class RawImage(LayoutControl): + """ + Displays pixel frames pushed from Python at full bandwidth. + + Unlike :class:`~flet.Image`, whose `src` travels through the regular + Flet protocol on every update, `RawImage` streams frames over a + dedicated :class:`~flet.DataChannel`: bytes skip MsgPack + encode/decode entirely and, on local transports (desktop app, `flet run`, + Pyodide), are displayed from raw RGBA pixels without any image + encoding or decoding. This makes it suitable for animations, generated + graphics, camera frames and Pillow output at interactive frame rates. + + Frames are pushed with the awaitable :meth:`render`, :meth:`render_rgba` + and :meth:`render_encoded` methods. Each call resolves when the client + has actually displayed the frame, so a plain loop self-paces to display + speed: + + ```python + raw_image = ft.RawImage(width=400, height=300) + page.add(raw_image) + + while True: + await raw_image.render(produce_pil_image()) + ``` + + Transport behavior is selected automatically: + + - **Local transports** (`local_data_transport` connections): frames are + sent as uncompressed premultiplied RGBA8888 and uploaded straight to + a GPU texture on the client. + - **Remote transports** (`flet-web` over WebSocket): Pillow and NumPy + frames are PNG-encoded off the event loop to save bandwidth; raw + pixel frames for which no straight-alpha source is available are sent + uncompressed. + + **Premultiplied alpha.** The raw-pixel path uploads frames directly as + GPU textures in Flutter's `rgba8888` format, which expects RGB values + already multiplied by alpha ("premultiplied"). Pillow, numpy code and + image files normally produce *straight* alpha instead, where color and + opacity are independent: a half-transparent white pixel is + `(255, 255, 255, 128)` straight but `(128, 128, 128, 128)` + premultiplied (each color channel becomes `value * alpha // 255`). + The `premultiplied` argument of the render methods says whether that + conversion is already done: + + - `premultiplied=False` — pixels carry straight alpha; RGB is + multiplied by alpha before sending. The conversion runs in fast C + loops and is skipped when the frame turns out to be fully opaque. + - `premultiplied=True` — skip the conversion. Use it when pixels are + genuinely premultiplied or, the common case, when the frame is + **fully opaque**: with every alpha at 255 both forms are identical, + and declaring it saves an alpha scan per frame in streaming loops. + + Passing straight-alpha pixels with `premultiplied=True` makes + semi-transparent areas render too bright; for fully opaque frames the + flag cannot be wrong either way. + + The last frame is retained and replayed automatically when the client + widget remounts (page rebuild, route navigation), mirroring how + `Image.src` persists. + """ + + fit: Optional[BoxFit] = None + """ + Defines how to inscribe the current frame into the space allocated + during layout. + """ + + filter_quality: FilterQuality = FilterQuality.LOW + """ + The rendering quality of the displayed frame. + + Defaults to `LOW` (bilinear), a good trade-off for streamed frames. + Use `NONE` for crisp nearest-neighbor scaling of pixel-art-style + content. + """ + + scale: Number = 1.0 + """ + How many physical frame pixels correspond to one logical pixel. + + Only affects the intrinsic size of this control when it is laid out + without tight constraints: a 800x600 frame with `scale=2` measures + 400x300 logical pixels. Set it to the device pixel ratio when frames + are rendered at physical resolution. + """ + + ready_timeout: Optional[Number] = 5.0 + """ + Seconds the `render` methods wait for the client widget to attach its + data channel before raising `TimeoutError`. + + Set to `None` to wait indefinitely. + """ + + ack_timeout: Optional[Number] = 10.0 + """ + Seconds a `render` call waits for the client's frame-applied + acknowledgment before raising `TimeoutError`. + + The ack normally arrives within milliseconds of the frame being + displayed. The timeout is a liveness guard: transports drop frames + sent while the client is disconnected (closed browser tab, network + loss), and without it a `while True: await raw_image.render(...)` + loop would wait for the lost ack forever. Raise it when streaming + very large frames to slow remote clients, or set to `None` to wait + indefinitely. + """ + + on_data_channel_open: Optional[EventHandler[DataChannelOpenEvent]] = None + """ + Framework hook — Dart fires this when it opens the data channel on + mount. The default handler captures the channel used by the `render` + methods; override only to do something extra at attach-time. + """ + + def init(self) -> None: + super().init() + self._channel: Optional[DataChannel] = None + # Set once the Dart side has announced its data channel; `render` + # calls block on it so frames pushed before first mount are held + # (up to `ready_timeout`) instead of dropped. + self._ready = asyncio.Event() + # FIFO of per-frame ack futures. Each send enqueues a future and + # awaits it; `_on_dart_message` resolves the head when Dart's + # `[0xFF]` frame-applied ack arrives. The await is the + # backpressure that paces producer loops to display speed. + self._pending_acks: deque[asyncio.Future] = deque() + # Last frame packet sent, replayed when the client widget + # remounts so the image survives page rebuilds like `Image.src`. + self._last_packet: Optional[bytes] = None + if self.on_data_channel_open is None: + self.on_data_channel_open = self._capture_channel + + # -- channel plumbing --------------------------------------------------- + + def _capture_channel(self, e: DataChannelOpenEvent) -> None: + # Single-channel widget; no need to dispatch on e.channel_name. + self._channel = self.get_data_channel(e.channel_id) + self._channel.on_bytes(self._on_dart_message) + # Acks pending on a previous channel will never arrive; resolve + # them so old `render` awaits return instead of hanging. + while self._pending_acks: + fut = self._pending_acks.popleft() + if not fut.done(): + fut.set_result(None) + # Replay the last frame without registering an ack future — its + # ack finds an empty deque and is ignored. + if self._last_packet is not None: + self._channel.send(self._last_packet) + self._ready.set() + + def _on_dart_message(self, payload: bytes) -> None: + # Reverse direction (Dart -> Python) wire format: + # [0xFF] — frame-applied ack, sent after each frame completes. + if not payload or payload[0] != 0xFF: + return + if self._pending_acks: + fut = self._pending_acks.popleft() + if not fut.done(): + fut.set_result(None) + + async def _send_and_wait(self, packet: bytes) -> None: + if not self._ready.is_set(): + await asyncio.wait_for( + self._ready.wait(), + None if self.ready_timeout is None else float(self.ready_timeout), + ) + assert self._channel is not None + loop = asyncio.get_running_loop() + fut: asyncio.Future = loop.create_future() + self._pending_acks.append(fut) + self._channel.send(packet) + if self.ack_timeout is None: + await fut + return + try: + await asyncio.wait_for(fut, float(self.ack_timeout)) + except (TimeoutError, asyncio.TimeoutError): + # Withdraw the abandoned future so a future ack doesn't + # resolve it instead of the frame it belongs to. + with contextlib.suppress(ValueError): + self._pending_acks.remove(fut) + raise TimeoutError( + f"frame was not acknowledged within {self.ack_timeout}s — " + "the client may have disconnected" + ) from None + + async def _send_frame(self, packet: bytes) -> None: + self._last_packet = packet + await self._send_and_wait(packet) + + def _local_data_transport(self) -> bool: + try: + page = self.page + except RuntimeError: # not added to a page yet + return False + return bool(getattr(page.session.connection, "local_data_transport", False)) + + # -- public API --------------------------------------------------------- + + async def render(self, image: Any, *, premultiplied: bool = False) -> None: + """ + Display a Pillow image or a NumPy-style array and wait until the + client has shown it. + + Args: + image: A `PIL.Image.Image` (any mode; converted to RGBA as + needed), or an object exposing `__array_interface__` + (e.g. a NumPy array) of shape `(height, width, 4)` or + `(height, width, 3)` with `uint8` values. + premultiplied: Set to `True` if RGB values are already + premultiplied by alpha to skip the premultiplication step. + + Raises: + TypeError: If `image` is neither a Pillow image nor an + array-like object. + TimeoutError: If the client widget doesn't attach within + :attr:`ready_timeout`. + """ + if hasattr(image, "mode") and hasattr(image, "tobytes"): + await self._render_pil(image, premultiplied) + elif hasattr(image, "__array_interface__"): + await self._render_array(image, premultiplied) + else: + raise TypeError( + "RawImage.render() accepts a PIL.Image.Image or an object " + f"with __array_interface__, got {type(image).__name__}" + ) + + async def render_rgba( + self, + width: int, + height: int, + pixels: bytes, + *, + premultiplied: bool = True, + ) -> None: + """ + Display a raw RGBA8888 frame and wait until the client has shown it. + + Args: + width: Frame width in physical pixels. + height: Frame height in physical pixels. + pixels: Tightly packed RGBA8888 bytes, `width * height * 4` + long. RGB values must be premultiplied by alpha (fully + opaque frames are premultiplied by definition). + premultiplied: Set to `False` if RGB values are straight + (non-premultiplied); Pillow is then required to + premultiply them. + + Raises: + ValueError: If `pixels` has the wrong length. + TimeoutError: If the client widget doesn't attach within + :attr:`ready_timeout`. + """ + if len(pixels) != width * height * 4: + raise ValueError( + f"pixels must be width * height * 4 = {width * height * 4} " + f"bytes, got {len(pixels)}" + ) + if not premultiplied and _rgba_is_opaque(pixels): + premultiplied = True # straight == premultiplied when opaque + local = self._local_data_transport() + if not premultiplied: + # Straight alpha: Pillow is required either to premultiply + # (local raw upload) or to PNG-encode (remote). + img = _pil_from_rgba(width, height, pixels) + if local: + pixels = _premultiply_pil(img).tobytes() + else: + await self._send_frame( + b"\x01" + await asyncio.to_thread(_pil_to_png_bytes, img) + ) + return + elif not local and _rgba_is_opaque(pixels): + # Opaque frames PNG-encode losslessly (nothing to premultiply); + # non-opaque premultiplied frames have no straight-alpha source + # to encode and are sent raw. + img = _try_pil_from_rgba(width, height, pixels) + if img is not None: + await self._send_frame( + b"\x01" + await asyncio.to_thread(_pil_to_png_bytes, img) + ) + return + await self._send_frame(_encode_raw_packet(width, height, pixels)) + + async def render_encoded(self, data: bytes) -> None: + """ + Display an encoded image (PNG, JPEG, WebP, ...) and wait until the + client has shown it. + + The bytes still travel over the data channel (skipping the Flet + protocol), but the client decodes them with its image codecs + instead of a raw pixel upload. + + Args: + data: Encoded image bytes. + + Raises: + TimeoutError: If the client widget doesn't attach within + :attr:`ready_timeout`. + """ + await self._send_frame(b"\x01" + data) + + async def clear(self) -> None: + """ + Clear the displayed frame. + """ + self._last_packet = None + await self._send_and_wait(b"\x03") + + # -- input paths ---------------------------------------------------------- + + async def _render_pil(self, image: Any, premultiplied: bool) -> None: + if not self._local_data_transport(): + # PNG carries straight alpha — encode the original image, + # never a premultiplied copy. Encoding is CPU-heavy; keep it + # off the event loop. + await self._send_frame( + b"\x01" + await asyncio.to_thread(_pil_to_png_bytes, image) + ) + return + if image.mode != "RGBA": + image = image.convert("RGBA") + if not premultiplied: + image = _premultiply_pil(image) + width, height = image.size + await self._send_frame(_encode_raw_packet(width, height, image.tobytes())) + + async def _render_array(self, array: Any, premultiplied: bool) -> None: + # An object with __array_interface__ guarantees numpy is importable + # in practice; import lazily so flet itself never depends on it. + import numpy as np + + arr = np.asarray(array) + if arr.dtype != np.uint8 or arr.ndim != 3 or arr.shape[2] not in (3, 4): + raise TypeError( + "array must be uint8 with shape (height, width, 4) or " + f"(height, width, 3), got {arr.dtype} {arr.shape}" + ) + if arr.shape[2] == 3: + rgba = np.empty(arr.shape[:2] + (4,), dtype=np.uint8) + rgba[:, :, :3] = arr + rgba[:, :, 3] = 255 + arr = rgba + premultiplied = True # opaque + if not self._local_data_transport(): + try: + from PIL import Image as PILImage + except ImportError: + pass + else: + if premultiplied and (arr[:, :, 3] != 255).any(): + # No straight-alpha source to encode — send raw. + await self._send_frame(self._array_packet(np, arr, True)) + return + img = PILImage.frombuffer( + "RGBA", + (arr.shape[1], arr.shape[0]), + np.ascontiguousarray(arr).tobytes(), + ) + await self._send_frame( + b"\x01" + await asyncio.to_thread(_pil_to_png_bytes, img) + ) + return + await self._send_frame(self._array_packet(np, arr, premultiplied)) + + @staticmethod + def _array_packet(np: Any, arr: Any, premultiplied: bool) -> bytes: + if not premultiplied and (arr[:, :, 3] != 255).any(): + # Flutter's rgba8888 upload assumes premultiplied alpha. + out = arr.copy() + a = out[:, :, 3:4].astype(np.uint16) + out[:, :, :3] = (out[:, :, :3].astype(np.uint16) * a // 255).astype( + np.uint8 + ) + arr = out + arr = np.ascontiguousarray(arr) + return _encode_raw_packet(arr.shape[1], arr.shape[0], arr.tobytes()) + + +# -- Pillow helpers (Pillow is an optional dependency; import lazily) --------- + + +def _premultiply_pil(image: Any) -> Any: + """ + Premultiplies RGB by alpha in an RGBA Pillow image. + + Flutter's rgba8888 texture upload assumes premultiplied alpha, while + Pillow produces straight alpha. All per-pixel work happens in Pillow's + C loops: an opaque image is detected with `getextrema()` and returned + as-is; otherwise each color band is multiplied by the alpha band. + """ + alpha = image.getchannel("A") + if alpha.getextrema() == (255, 255): + return image + from PIL import Image as PILImage + from PIL import ImageChops + + r, g, b, a = image.split() + return PILImage.merge( + "RGBA", + ( + ImageChops.multiply(r, a), + ImageChops.multiply(g, a), + ImageChops.multiply(b, a), + a, + ), + ) + + +def _pil_from_rgba(width: int, height: int, pixels: bytes) -> Any: + try: + from PIL import Image as PILImage + except ImportError: + raise RuntimeError( + "Pillow is required to premultiply raw RGBA pixels; install it " + "or pass premultiplied pixels" + ) from None + return PILImage.frombuffer("RGBA", (width, height), pixels) + + +def _try_pil_from_rgba(width: int, height: int, pixels: bytes) -> Optional[Any]: + try: + from PIL import Image as PILImage + except ImportError: + return None + return PILImage.frombuffer("RGBA", (width, height), pixels) + + +def _rgba_is_opaque(pixels: bytes) -> bool: + """ + Whether every alpha byte in tightly packed RGBA8888 is 255. + + The strided slice and count both run in C — no per-pixel Python loop. + """ + alphas = pixels[3::4] + return alphas.count(255) == len(alphas) + + +def _pil_to_png_bytes(image: Any) -> bytes: + buf = io.BytesIO() + image.save(buf, format="PNG") + return buf.getvalue() + + +def _encode_raw_packet(width: int, height: int, rgba: bytes) -> bytes: + """ + Encodes a raw full frame into a 0x04 wire packet: + `[0x04][width u32 LE][height u32 LE][premultiplied RGBA8888]`. + """ + pkt = bytearray(9 + len(rgba)) + pkt[0] = 0x04 + pkt[1:5] = width.to_bytes(4, "little") + pkt[5:9] = height.to_bytes(4, "little") + pkt[9:] = rgba + return bytes(pkt) diff --git a/sdk/python/packages/flet/src/flet/controls/core/row.py b/sdk/python/packages/flet/src/flet/controls/core/row.py index 70993e8d69..8ee71b0b61 100644 --- a/sdk/python/packages/flet/src/flet/controls/core/row.py +++ b/sdk/python/packages/flet/src/flet/controls/core/row.py @@ -10,13 +10,13 @@ __all__ = ["Row"] -@control("Row") +@control("Row", categories=("layout",), tags=("horizontal", "flex", "scrollable")) class Row(LayoutControl, ScrollableControl, AdaptiveControl): """ Displays its children in a horizontal array. To cause a child control to expand and fill the available horizontal space, set - its :attr:`~flet.Control.expand` property. + its :attr:`flet.Control.expand` property. Example: ```python diff --git a/sdk/python/packages/flet/src/flet/controls/core/semantics.py b/sdk/python/packages/flet/src/flet/controls/core/semantics.py index 681c17080d..e2d18f2ebf 100644 --- a/sdk/python/packages/flet/src/flet/controls/core/semantics.py +++ b/sdk/python/packages/flet/src/flet/controls/core/semantics.py @@ -133,7 +133,10 @@ class Semantics(Control): on_tap_hint_text: Optional[str] = None """ - TBD + A hint describing what happens when the user activates :attr:`on_tap`. + + Assistive technologies can announce this together with :attr:`hint_text` to make + the tap action more specific. """ current_value_length: Optional[int] = None @@ -149,7 +152,10 @@ class Semantics(Control): exclude_semantics: bool = False """ - TBD + Whether the semantics information from :attr:`content` should be excluded. + + When `True`, only the semantics configured on this :class:`~flet.Semantics` + wrapper are exposed. """ mixed: Optional[bool] = None @@ -161,12 +167,15 @@ class Semantics(Control): on_long_press_hint_text: Optional[str] = None """ - TBD + A hint describing what happens when the user activates :attr:`on_long_press`. """ container: Optional[bool] = None """ - TBD + Whether this semantics node should introduce its own semantic container. + + A container groups the semantics of its subtree into a distinct node instead of + always merging with surrounding semantics. """ live_region: Optional[bool] = None @@ -201,7 +210,11 @@ class Semantics(Control): on_double_tap: Optional[ControlEventHandler["Semantics"]] = None """ - TBD + Reserved for a semantic double-tap action. + + Warning: + This event is not wired by the current runtime implementation and will not + fire until the control implementation adds support for it. """ on_increase: Optional[ControlEventHandler["Semantics"]] = None diff --git a/sdk/python/packages/flet/src/flet/controls/core/stack.py b/sdk/python/packages/flet/src/flet/controls/core/stack.py index 86886e92e2..69e88faeda 100644 --- a/sdk/python/packages/flet/src/flet/controls/core/stack.py +++ b/sdk/python/packages/flet/src/flet/controls/core/stack.py @@ -107,8 +107,8 @@ class Stack(LayoutControl, AdaptiveControl): alignment: Optional[Alignment] = None """ Specifies the alignment for non-positioned (those without explicit alignment \ - properties such as :attr:`~flet.LayoutControl.top` - or :attr:`~flet.LayoutControl.bottom`) and + properties such as :attr:`flet.LayoutControl.top` + or :attr:`flet.LayoutControl.bottom`) and partially-positioned :attr:`controls`. """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/view.py b/sdk/python/packages/flet/src/flet/controls/core/view.py index 094e248d9b..289b643172 100644 --- a/sdk/python/packages/flet/src/flet/controls/core/view.py +++ b/sdk/python/packages/flet/src/flet/controls/core/view.py @@ -1,12 +1,10 @@ from dataclasses import field -from typing import Optional, Union +from typing import TYPE_CHECKING, Optional, Union from flet.controls.base_control import BaseControl, control from flet.controls.box import BoxDecoration from flet.controls.control import Control from flet.controls.control_event import ControlEventHandler -from flet.controls.cupertino.cupertino_app_bar import CupertinoAppBar -from flet.controls.cupertino.cupertino_navigation_bar import CupertinoNavigationBar from flet.controls.layout_control import LayoutControl from flet.controls.material.app_bar import AppBar from flet.controls.material.bottom_app_bar import BottomAppBar @@ -25,6 +23,14 @@ Number, ) +if TYPE_CHECKING: + # Annotation-only (quoted below): deferred so a View doesn't eagerly pull the + # Cupertino controls (cold-start import cost). + from flet.controls.cupertino.cupertino_app_bar import CupertinoAppBar + from flet.controls.cupertino.cupertino_navigation_bar import ( + CupertinoNavigationBar, + ) + __all__ = ["View"] @@ -49,7 +55,7 @@ class View(ScrollableControl, LayoutControl): program to update :attr:`flet.Page.route` when a view popped. """ - appbar: Optional[Union[AppBar, CupertinoAppBar]] = None + appbar: "Optional[Union[AppBar, CupertinoAppBar]]" = None """ An :class:`~flet.AppBar` control to display at the top of the `Page`. """ @@ -71,7 +77,7 @@ class View(ScrollableControl, LayoutControl): Describes position of :attr:`floating_action_button` """ - navigation_bar: Union[NavigationBar, CupertinoNavigationBar, None] = None + navigation_bar: "Union[NavigationBar, CupertinoNavigationBar, None]" = None """ A navigation bar (:class:`~flet.NavigationBar` or \ :class:`~flet.CupertinoNavigationBar`) control to display at the bottom of the \ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_checkbox.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_checkbox.py index 1c2a223e8f..78f2a6daf1 100644 --- a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_checkbox.py +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_checkbox.py @@ -98,9 +98,9 @@ class CupertinoCheckbox(LayoutControl): states. :attr:`active_color` is used as fallback color when - the checkbox is in the :attr:`~flet.ControlState.SELECTED` state, + the checkbox is in the :attr:`flet.ControlState.SELECTED` state, :attr:`flet.CupertinoColors.WHITE` at `50%` opacity is used as fallback color - when this checkbox is in the :attr:`~flet.ControlState.DISABLED` state, and + when this checkbox is in the :attr:`flet.ControlState.DISABLED` state, and :attr:`flet.CupertinoColors.WHITE` otherwise. Note: diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_date_picker.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_date_picker.py index e5359bf13f..2a151a884f 100644 --- a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_date_picker.py +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_date_picker.py @@ -26,7 +26,7 @@ class CupertinoDatePickerMode(Enum): """ Mode that shows the date in hour, minute, and (optional) an AM/PM designation. The AM/PM designation is shown only if `CupertinoDatePicker` does not use 24h - format, i.e. if :attr:`~flet.CupertinoDatePicker.use_24h_format` is `False`. + format, i.e. if :attr:`flet.CupertinoDatePicker.use_24h_format` is `False`. Column order is subject to internationalization. Example: `4 | 14 | PM` @@ -46,7 +46,7 @@ class CupertinoDatePickerMode(Enum): Mode that shows the date as day of the week, month, day of month and the time in hour, minute, and (optional) an AM/PM designation. The AM/PM designation is shown only if `CupertinoDatePicker` does not use 24h - format, i.e. if :attr:`~flet.CupertinoDatePicker.use_24h_format` is `False`. + format, i.e. if :attr:`flet.CupertinoDatePicker.use_24h_format` is `False`. Column order is subject to internationalization. Example: `Fri Jul 13 | 4 | 14 | PM` diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_textfield.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_textfield.py index 56c14ce32f..f647a6fcfd 100644 --- a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_textfield.py +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_textfield.py @@ -75,7 +75,7 @@ class CupertinoTextField(TextField): blend_mode: Optional[BlendMode] = None """ - The blend mode applied to the :attr:`~flet.FormFieldControl.bgcolor` + The blend mode applied to the :attr:`flet.FormFieldControl.bgcolor` or :attr:`gradient` background. """ @@ -86,23 +86,23 @@ class CupertinoTextField(TextField): prefix_visibility_mode: OverlayVisibilityMode = OverlayVisibilityMode.ALWAYS """ - Defines the visibility of the :attr:`~flet.FormFieldControl.prefix` + Defines the visibility of the :attr:`flet.FormFieldControl.prefix` control based on the state of text entry. Note: Has no effect if - :attr:`~flet.FormFieldControl.prefix` + :attr:`flet.FormFieldControl.prefix` is not specified. """ suffix_visibility_mode: OverlayVisibilityMode = OverlayVisibilityMode.ALWAYS """ - Defines the visibility of the :attr:`~flet.FormFieldControl.suffix` + Defines the visibility of the :attr:`flet.FormFieldControl.suffix` control based on the state of text entry. Note: Has no effect if - :attr:`~flet.FormFieldControl.suffix` + :attr:`flet.FormFieldControl.suffix` is not specified. """ @@ -110,9 +110,7 @@ class CupertinoTextField(TextField): """ Defines the visibility of the clear button based on the state of text entry. - Will appear only if no - :attr:`~flet.FormFieldControl.suffix` - is provided. + Will appear only if no :attr:`flet.FormFieldControl.suffix` is provided. """ clear_button_semantics_label: Optional[str] = "Clear" @@ -124,15 +122,15 @@ class CupertinoTextField(TextField): image: Optional[DecorationImage] = None """ - An image to paint above the :attr:`~flet.FormFieldControl.bgcolor` + An image to paint above the :attr:`flet.FormFieldControl.bgcolor` or :attr:`gradient` background. """ padding: PaddingValue = field(default_factory=lambda: Padding.all(7)) """ The padding around the text entry area between the \ - :attr:`~flet.FormFieldControl.prefix` - and :attr:`~flet.FormFieldControl.suffix` + :attr:`flet.FormFieldControl.prefix` + and :attr:`flet.FormFieldControl.suffix` or the clear button when :attr:`clear_button_visibility_mode` is not :attr:`flet.OverlayVisibilityMode.NEVER`. """ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_timer_picker.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_timer_picker.py index e8f35c91dd..f3ce5c4d2d 100644 --- a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_timer_picker.py +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_timer_picker.py @@ -121,7 +121,7 @@ class CupertinoTimerPicker(LayoutControl): """ Called when the timer's duration changes. - The :attr:`~flet.Event.data` property of the event + The :attr:`flet.Event.data` property of the event handler contains the new duration value. Its type matches :attr:`value`: if `value` is a `Duration`, then `data` is also a `Duration`; otherwise, it is an `int` (seconds). diff --git a/sdk/python/packages/flet/src/flet/controls/device_info.py b/sdk/python/packages/flet/src/flet/controls/device_info.py index 8442db5f5f..de2a24399c 100644 --- a/sdk/python/packages/flet/src/flet/controls/device_info.py +++ b/sdk/python/packages/flet/src/flet/controls/device_info.py @@ -639,6 +639,9 @@ class WindowsDeviceInfo(DeviceInfo): """ user_name: str + """ + The name of the current user. + """ major_version: int """The major version number of the operating system. diff --git a/sdk/python/packages/flet/src/flet/controls/geometry.py b/sdk/python/packages/flet/src/flet/controls/geometry.py index 8130ec8aae..cc7acb2365 100644 --- a/sdk/python/packages/flet/src/flet/controls/geometry.py +++ b/sdk/python/packages/flet/src/flet/controls/geometry.py @@ -17,7 +17,14 @@ class Size: """ width: Number + """ + The horizontal extent of the size. + """ + height: Number + """ + The vertical extent of the size. + """ @property def aspect_ratio(self) -> float: diff --git a/sdk/python/packages/flet/src/flet/controls/gradients.py b/sdk/python/packages/flet/src/flet/controls/gradients.py index 12f1d86a71..2ce095c7ca 100644 --- a/sdk/python/packages/flet/src/flet/controls/gradients.py +++ b/sdk/python/packages/flet/src/flet/controls/gradients.py @@ -14,7 +14,7 @@ "SweepGradient", ] -from flet.controls.types import Number +from flet.controls.types import ColorValue, Number class GradientTileMode(Enum): @@ -66,7 +66,7 @@ class Gradient: - `SweepGradient` """ - colors: list[str] + colors: list[ColorValue] """ The colors the gradient should obtain at each of the stops. This list must contain \ at least two colors. diff --git a/sdk/python/packages/flet/src/flet/controls/layout_control.py b/sdk/python/packages/flet/src/flet/controls/layout_control.py index d7c4ba9937..6af296eb1f 100644 --- a/sdk/python/packages/flet/src/flet/controls/layout_control.py +++ b/sdk/python/packages/flet/src/flet/controls/layout_control.py @@ -231,56 +231,62 @@ def main(page: ft.Page): animate_opacity: Optional[AnimationValue] = None """ - Enables implicit animation of the :attr:`~flet.Control.opacity` property. + Enables implicit animation of the :attr:`flet.Control.opacity` property. More information [here](https://flet.dev/docs/cookbook/animations). """ animate_size: Optional[AnimationValue] = None """ - TBD + Enables implicit animation of this control's size. + + If :attr:`width` or :attr:`height` is set, changes to those dimensions are + animated. If neither dimension is set, changes to the control's natural size are + animated instead. + + More information [here](https://flet.dev/docs/cookbook/animations). """ animate_position: Optional[AnimationValue] = None """ Enables implicit animation of the positioning properties \ - (:attr:`~flet.LayoutControl.left`, :attr:`~flet.LayoutControl.right`, \ - :attr:`~flet.LayoutControl.top` and :attr:`~flet.LayoutControl.bottom`). + (:attr:`flet.LayoutControl.left`, :attr:`flet.LayoutControl.right`, \ + :attr:`flet.LayoutControl.top` and :attr:`flet.LayoutControl.bottom`). More information [here](https://flet.dev/docs/cookbook/animations). """ animate_align: Optional[AnimationValue] = None """ - Enables implicit animation of the :attr:`~flet.LayoutControl.align` property. + Enables implicit animation of the :attr:`flet.LayoutControl.align` property. More information [here](https://flet.dev/docs/cookbook/animations). """ animate_margin: Optional[AnimationValue] = None """ - Enables implicit animation of the :attr:`~flet.LayoutControl.margin` property. + Enables implicit animation of the :attr:`flet.LayoutControl.margin` property. More information [here](https://flet.dev/docs/cookbook/animations). """ animate_rotation: Optional[AnimationValue] = None """ - Enables implicit animation of the :attr:`~flet.LayoutControl.rotate` property. + Enables implicit animation of the :attr:`flet.LayoutControl.rotate` property. More information [here](https://flet.dev/docs/cookbook/animations). """ animate_scale: Optional[AnimationValue] = None """ - Enables implicit animation of the :attr:`~flet.LayoutControl.scale` property. + Enables implicit animation of the :attr:`flet.LayoutControl.scale` property. More information [here](https://flet.dev/docs/cookbook/animations). """ animate_offset: Optional[AnimationValue] = None """ - Enables implicit animation of the :attr:`~flet.LayoutControl.offset` property. + Enables implicit animation of the :attr:`flet.LayoutControl.offset` property. More information [here](https://flet.dev/docs/cookbook/animations). """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/alert_dialog.py b/sdk/python/packages/flet/src/flet/controls/material/alert_dialog.py index 9292d730c7..f98ad0c025 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/alert_dialog.py +++ b/sdk/python/packages/flet/src/flet/controls/material/alert_dialog.py @@ -29,6 +29,7 @@ class AlertDialog(DialogControl): `title` is displayed above the :attr:`content` and the `actions` are displayed below the `content`. + Example: ```python ft.AlertDialog( title=ft.Text("Session expired"), @@ -211,7 +212,10 @@ class AlertDialog(DialogControl): title_text_style: Optional[TextStyle] = None """ - TBD + The text style for the :attr:`title` of this dialog. + + If `None`, :attr:`flet.DialogTheme.title_text_style` is used. + If that is also `None`, the default comes from the active dialog theme. """ clip_behavior: ClipBehavior = ClipBehavior.NONE diff --git a/sdk/python/packages/flet/src/flet/controls/material/auto_complete.py b/sdk/python/packages/flet/src/flet/controls/material/auto_complete.py index 472fec76fc..7f41f3c1f8 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/auto_complete.py +++ b/sdk/python/packages/flet/src/flet/controls/material/auto_complete.py @@ -57,8 +57,8 @@ class AutoComplete(LayoutControl): Note: - A valid :class:`~flet.AutoCompleteSuggestion` must have at least a - :attr:`~flet.AutoCompleteSuggestion.key` or - :attr:`~flet.AutoCompleteSuggestion.value` specified, else it will be + :attr:`flet.AutoCompleteSuggestion.key` or + :attr:`flet.AutoCompleteSuggestion.value` specified, else it will be ignored. If only `key` is provided, `value` will be set to `key` as fallback and vice versa. - The internal filtration process of the suggestions (based on their `key`s) diff --git a/sdk/python/packages/flet/src/flet/controls/material/badge.py b/sdk/python/packages/flet/src/flet/controls/material/badge.py index eac930d9f2..b77b31cc32 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/badge.py +++ b/sdk/python/packages/flet/src/flet/controls/material/badge.py @@ -49,7 +49,7 @@ class Badge(BaseControl): alignment: Optional[Alignment] = None """ - Aligns the :attr:`~flet.Badge.label` relative to the content of the badge. + Aligns the :attr:`flet.Badge.label` relative to the content of the badge. The alignment positions the :attr:`label` in similar way :attr:`flet.Container.content` is positioned using :attr:`flet.Container.alignment`, diff --git a/sdk/python/packages/flet/src/flet/controls/material/checkbox.py b/sdk/python/packages/flet/src/flet/controls/material/checkbox.py index 086edff697..5ec1262a71 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/checkbox.py +++ b/sdk/python/packages/flet/src/flet/controls/material/checkbox.py @@ -20,7 +20,7 @@ __all__ = ["Checkbox"] -@control("Checkbox") +@control("Checkbox", categories=("input", "selection"), tags=("form", "toggle")) class Checkbox(LayoutControl, AdaptiveControl): """ Checkbox allows to select one or more items from a group, or switch between two \ diff --git a/sdk/python/packages/flet/src/flet/controls/material/chip.py b/sdk/python/packages/flet/src/flet/controls/material/chip.py index f14ca46169..1c0241b760 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/chip.py +++ b/sdk/python/packages/flet/src/flet/controls/material/chip.py @@ -189,7 +189,10 @@ class Chip(LayoutControl): visual_density: Optional[VisualDensity] = None """ - TBD + Defines how compact this chip should be. + + Negative density values make the chip more compact, while positive values make it + more spacious. """ border_side: Optional[BorderSide] = None diff --git a/sdk/python/packages/flet/src/flet/controls/material/circle_avatar.py b/sdk/python/packages/flet/src/flet/controls/material/circle_avatar.py index 000cce24a6..7b5519cf60 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/circle_avatar.py +++ b/sdk/python/packages/flet/src/flet/controls/material/circle_avatar.py @@ -125,7 +125,7 @@ class CircleAvatar(LayoutControl): Called when an error occurs while loading the :attr:`background_image_src` or \ :attr:`foreground_image_src`. - The :attr:`~flet.Event.data` property of the event handler argument is + The :attr:`flet.Event.data` property of the event handler argument is a string whose value is either `"background"` or `"foreground"` indicating the error's origin. """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/container.py b/sdk/python/packages/flet/src/flet/controls/material/container.py index 4b0c4502b4..b46ba5c27f 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/container.py +++ b/sdk/python/packages/flet/src/flet/controls/material/container.py @@ -239,7 +239,7 @@ class Container(LayoutControl, AdaptiveControl): """ Called when a mouse pointer enters or exists the container area. - The :attr:`~flet.Event.data` property of the event handler argument is a boolean: + The :attr:`flet.Event.data` property of the event handler argument is a boolean: `True` when the cursor enters and `False` when it exits this container. """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/context_menu.py b/sdk/python/packages/flet/src/flet/controls/material/context_menu.py index f5c7db25f6..b426df9e69 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/context_menu.py +++ b/sdk/python/packages/flet/src/flet/controls/material/context_menu.py @@ -97,7 +97,7 @@ class ContextMenu(LayoutControl): Wraps its :attr:`content` and displays contextual menus for specific mouse events. Tip: - On web, call :meth:`~flet.BrowserContextMenu.disable` method of + On web, call :meth:`flet.BrowserContextMenu.disable` method of :attr:`flet.Page.browser_context_menu` to suppress the default browser context menu before relying on custom menus. """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/datatable.py b/sdk/python/packages/flet/src/flet/controls/material/datatable.py index eed55b9029..9d78fe7ce7 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/datatable.py +++ b/sdk/python/packages/flet/src/flet/controls/material/datatable.py @@ -222,7 +222,7 @@ class DataRow(Control): Note: There must be exactly as many cells as there are visible - :attr:`~flet.DataTable.columns` in the table. + :attr:`flet.DataTable.columns` in the table. Raises: ValueError: If it does not contain at least one visible :class:`~flet.DataCell`. diff --git a/sdk/python/packages/flet/src/flet/controls/material/date_picker.py b/sdk/python/packages/flet/src/flet/controls/material/date_picker.py index 7de5ab9e41..3aa03dcdaf 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/date_picker.py +++ b/sdk/python/packages/flet/src/flet/controls/material/date_picker.py @@ -87,6 +87,7 @@ class DatePicker(DialogControl): Depending on the :attr:`entry_mode`, it will show either a Calendar or an Input (TextField) for picking a date. + Example: ```python picker = ft.DatePicker() @@ -143,7 +144,7 @@ class DatePicker(DialogControl): but does not participate in page-level locale resolution. If set to `None` (the default) or an inexistent/unsupported locale, - the :attr:`~flet.LocaleConfiguration.current_locale` of the + the :attr:`flet.LocaleConfiguration.current_locale` of the :attr:`flet.Page.locale_configuration` is used as fallback. """ @@ -253,7 +254,7 @@ class DatePicker(DialogControl): default_factory=lambda: Padding.symmetric(horizontal=16.0, vertical=24.0) ) """ - The amount of padding added to :attr:`~flet.PageMediaData.view_insets` of the \ + The amount of padding added to :attr:`flet.PageMediaData.view_insets` of the \ :attr:`flet.Page.media` on the outside of this picker's dialog. This defines the minimum space between the screen's edges and the dialog. @@ -264,7 +265,7 @@ class DatePicker(DialogControl): Called when user clicks confirm button. :attr:`value` is updated with selected date. - The :attr:`~flet.Event.data` property of the event handler argument + The :attr:`flet.Event.data` property of the event handler argument contains the selected date. """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/date_range_picker.py b/sdk/python/packages/flet/src/flet/controls/material/date_range_picker.py index c3b2d69134..c9e9352ca8 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/date_range_picker.py +++ b/sdk/python/packages/flet/src/flet/controls/material/date_range_picker.py @@ -31,6 +31,7 @@ class DateRangePicker(DialogControl): Depending on the :attr:`entry_mode`, it will show either a Calendar or an Input (text field) for picking a date range. + Example: ```python picker = ft.DateRangePicker() @@ -101,7 +102,7 @@ class DateRangePicker(DialogControl): but does not participate in page-level locale resolution. If set to `None` (the default) or an inexistent/unsupported locale, - the :attr:`~flet.LocaleConfiguration.current_locale` of the + the :attr:`flet.LocaleConfiguration.current_locale` of the :attr:`flet.Page.locale_configuration` is used as fallback. """ @@ -200,6 +201,6 @@ class DateRangePicker(DialogControl): :attr:`start_value` and :attr:`end_value` are updated with selected dates. - The :attr:`~flet.Event.data` property of the event handler + The :attr:`flet.Event.data` property of the event handler argument contains the selected dates. """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/dropdown.py b/sdk/python/packages/flet/src/flet/controls/material/dropdown.py index 75a10f7989..f84e23327c 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/dropdown.py +++ b/sdk/python/packages/flet/src/flet/controls/material/dropdown.py @@ -104,7 +104,7 @@ class Dropdown(LayoutControl): value: Optional[str] = None """ - The :attr:`~flet.DropdownOption.key` of the dropdown :attr:`options` + The :attr:`flet.DropdownOption.key` of the dropdown :attr:`options` corresponding to the selected option. """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/dropdownm2.py b/sdk/python/packages/flet/src/flet/controls/material/dropdownm2.py index a5136b3b9a..52da53640f 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/dropdownm2.py +++ b/sdk/python/packages/flet/src/flet/controls/material/dropdownm2.py @@ -77,6 +77,7 @@ class Option(Control): @deprecated_class( reason="Use Dropdown instead.", + docs_reason="Use [`Dropdown`][flet.Dropdown] instead.", version="0.84.0", delete_version="1.0", ) diff --git a/sdk/python/packages/flet/src/flet/controls/material/expansion_panel.py b/sdk/python/packages/flet/src/flet/controls/material/expansion_panel.py index cb0204f46b..49f5abe80f 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/expansion_panel.py +++ b/sdk/python/packages/flet/src/flet/controls/material/expansion_panel.py @@ -30,7 +30,7 @@ class ExpansionPanelListChangeEvent(Event["ExpansionPanelList"]): """ The index of the panel in :attr:`flet.ExpansionPanelList.controls` that was toggled. - Panels with :attr:`~flet.Control.visible` set to `False` are not counted/indexed. + Panels with :attr:`flet.Control.visible` set to `False` are not counted/indexed. This means the value may differ from the panel's position in the original :attr:`flet.ExpansionPanelList.controls` list when some panels are invisible. To map it back, filter :attr:`flet.ExpansionPanelList.controls` to only visible diff --git a/sdk/python/packages/flet/src/flet/controls/material/expansion_tile.py b/sdk/python/packages/flet/src/flet/controls/material/expansion_tile.py index 2560735c71..747ad27b0d 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/expansion_tile.py +++ b/sdk/python/packages/flet/src/flet/controls/material/expansion_tile.py @@ -192,7 +192,7 @@ class ExpansionTile(LayoutControl, AdaptiveControl): The color of this tile's titles when the sublist is :attr:`expanded`. If `None`, :attr:`flet.ExpansionTileTheme.text_color` is used; - if that is also `None`, then defaults to :attr:`~flet.TextTheme.body_large` + if that is also `None`, then defaults to :attr:`flet.TextTheme.body_large` of the :attr:`flet.Theme.text_theme`. """ @@ -248,7 +248,7 @@ class ExpansionTile(LayoutControl, AdaptiveControl): False). If `None`, :attr:`flet.ExpansionTileTheme.collapsed_text_color` is used; - if that is also `None`, then defaults to :attr:`~flet.TextTheme.body_large` + if that is also `None`, then defaults to :attr:`flet.TextTheme.body_large` of the :attr:`flet.Theme.text_theme`. """ @@ -340,7 +340,7 @@ class ExpansionTile(LayoutControl, AdaptiveControl): """ Called when a user clicks or taps the list tile. - The :attr:`~flet.Event.data` property of the event handler argument is a boolean + The :attr:`flet.Event.data` property of the event handler argument is a boolean representing the :attr:`expanded` state of the tile after the change. """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/form_field_control.py b/sdk/python/packages/flet/src/flet/controls/material/form_field_control.py index e6d607a01d..d4a5271476 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/form_field_control.py +++ b/sdk/python/packages/flet/src/flet/controls/material/form_field_control.py @@ -18,13 +18,38 @@ class InputBorder(Enum): + """ + Border styles supported by :class:`~flet.FormFieldControl`. + + These values select the border style drawn around the decorated input area. + """ + NONE = "none" + """ + Draws no border around the decoration's container. + """ + OUTLINE = "outline" + """ + Draws a border around all sides of the decoration's container. + """ + UNDERLINE = "underline" + """ + Draws a horizontal line along the bottom edge of the decoration's container. + """ @control(kw_only=True) class FormFieldControl(LayoutControl): + """ + Base class for Material form-field controls with a decorated input area. + + It provides the shared label, hint, helper, error, prefix, suffix, fill, and + border properties used by controls such as :class:`~flet.TextField` and + :class:`~flet.DropdownM2`. + """ + text_size: Optional[Number] = None """ Text size in virtual pixels. @@ -80,11 +105,16 @@ class FormFieldControl(LayoutControl): TextField background color. Note: - Will not be visible if :attr:`~flet.FormFieldControl.filled` is `False`. + Will not be visible if :attr:`filled` is `False`. """ border_radius: Optional[BorderRadiusValue] = None """ + Rounds the corners of the outlined decoration border. + + Note: + This is applied when :attr:`border` uses an outlined + border. Underline and borderless variants do not visibly use this radius. """ border_width: Optional[Number] = None @@ -115,7 +145,7 @@ class FormFieldControl(LayoutControl): Background color in focused state. Note: - Will not be visible if :attr:`~flet.FormFieldControl.filled` is `False`. + Will not be visible if :attr:`filled` is `False`. """ focused_border_width: Optional[Number] = None @@ -140,14 +170,11 @@ class FormFieldControl(LayoutControl): filled: Optional[bool] = None """ - If `True` the decoration's container is filled with theme \ - :attr:`~flet.FormFieldControl.fill_color`. + Whether the decoration's container is filled with :attr:`fill_color`. If `filled=None` (the default), then it is implicitly set to `True` when at least - one of the following is not `None`: :attr:`~flet.FormFieldControl.fill_color`, - :attr:`~flet.FormFieldControl.focused_bgcolor`, - :attr:`~flet.FormFieldControl.hover_color` and \ - :attr:`~flet.FormFieldControl.bgcolor`. + one of the following is not `None`: :attr:`fill_color`, + :attr:`focused_bgcolor`, :attr:`hover_color`, and :attr:`bgcolor`. """ fill_color: Optional[ColorValue] = None @@ -155,17 +182,26 @@ class FormFieldControl(LayoutControl): Background color of TextField. Note: - Will not be visible if :attr:`~flet.FormFieldControl.filled` is `False`. + Will not be visible if :attr:`filled` is `False`. """ focus_color: Optional[ColorValue] = None """ - TBD + The fill color of the decoration's container when the control has input focus. + + Note: + Text fields usually indicate focus by changing the focused border instead of + the fill color. In Flet, prefer :attr:`focused_bgcolor` and + :attr:`focused_border_color` when you need explicit + focused-state styling. """ align_label_with_hint: Optional[bool] = None """ - TBD + Whether the floating label should align with :attr:`hint_text`. + + This is typically set to `True` for multiline text input to align the label with + the top of the hint instead of centering it vertically. """ hover_color: Optional[ColorValue] = None @@ -173,7 +209,7 @@ class FormFieldControl(LayoutControl): Background color of TextField when hovered. Note: - Will not be visible if :attr:`~flet.FormFieldControl.filled` is `False`. + Will not be visible if :attr:`filled` is `False`. """ hint_text: Optional[str] = None @@ -181,22 +217,23 @@ class FormFieldControl(LayoutControl): Text that suggests what sort of input the field accepts. Displayed on top of the input when the it's empty and either - (a) :attr:`~flet.FormFieldControl.label` is `None` or (b) the input has the focus. + (a) :attr:`label` is `None` or (b) the input has the focus. """ hint_style: Optional[TextStyle] = None """ - The text style to use for :attr:`~flet.FormFieldControl.hint_text`. + The text style to use for :attr:`hint_text`. """ hint_fade_duration: Optional[DurationValue] = None """ - TBD + The duration of the :attr:`hint_text` fade-in and fade-out + animations. """ hint_max_lines: Optional[int] = None """ - TBD + The maximum number of lines the :attr:`hint_text` can occupy. """ helper: Optional[StrOrControl] = None @@ -205,19 +242,18 @@ class FormFieldControl(LayoutControl): used. If non-null, the text is displayed below the input decorator, in the same location - as :attr:`~flet.FormFieldControl.error`. If a non-null - :attr:`~flet.FormFieldControl.error` value is specified then the helper text is not - shown. + as :attr:`error`. If a non-null :attr:`error` value is specified then the helper + text is not shown. """ helper_style: Optional[TextStyle] = None """ - The text style to use for :attr:`~flet.FormFieldControl.helper`. + The text style to use for :attr:`helper`. """ helper_max_lines: Optional[int] = None """ - TBD + The maximum number of lines the :attr:`helper` can occupy. """ counter: Optional[StrOrControl] = None @@ -237,25 +273,27 @@ class FormFieldControl(LayoutControl): Text that appears below the input border. If non-null, the border's color animates to red - and the :attr:`~flet.FormFieldControl.helper` is not shown. + and the :attr:`helper` is not shown. """ error_style: Optional[TextStyle] = None """ - The text style to use for :attr:`~flet.FormFieldControl.error`. + The text style to use for :attr:`error`. """ error_max_lines: Optional[int] = None """ - TBD + The maximum number of lines the :attr:`error` can occupy. + + By default, soft line breaks are truncated with an ellipsis while explicit line + breaks are respected. Set this property to allow long error text to wrap. """ prefix: Optional[StrOrControl] = None """ A `Control` to place on the line before the input. - It appears after the :attr:`~flet.FormFieldControl.prefix_icon`, if both are \ - specified. + It appears after the :attr:`prefix_icon`, if both are specified. This can be used, for example, to add some padding to text that would otherwise be specified using `prefix`, or to add a custom control in front of the input. @@ -267,25 +305,29 @@ class FormFieldControl(LayoutControl): An icon that appears before the editable part of the text field, within the \ decoration's container. - If :attr:`~flet.FormFieldControl.prefix` is specified and visible, + If :attr:`prefix` is specified and visible, this icon will appear to its left. """ prefix_icon_size_constraints: Optional[BoxConstraints] = None """ - TBD + Size constraints for the area surrounding :attr:`prefix_icon`. + + This can be used to shrink or expand the default icon box. By default, the minimum + width and height are `48` pixels, and tighter constraints are commonly used + together with a dense decoration. """ prefix_style: Optional[TextStyle] = None """ - The text style to use for :attr:`~flet.FormFieldControl.prefix`. + The text style to use for :attr:`prefix`. """ suffix: Optional[StrOrControl] = None """ A `Control` to place on the line after the input. - It appears before the :attr:`~flet.FormFieldControl.suffix_icon`, + It appears before the :attr:`suffix_icon`, if both are specified. This can be used, for example, to add some padding to the text that would otherwise @@ -296,32 +338,51 @@ class FormFieldControl(LayoutControl): suffix_icon: Optional[IconDataOrControl] = None """ An icon that appears after the editable part of the text field and after the \ - :attr:`~flet.FormFieldControl.suffix`, within the decoration's container. + :attr:`suffix`, within the decoration's container. """ suffix_icon_size_constraints: Optional[BoxConstraints] = None """ - TBD + Size constraints for the area surrounding :attr:`suffix_icon`. + + This can be used to shrink or expand the default icon box. By default, the minimum + width and height are `48` pixels, and tighter constraints are commonly used + together with a dense decoration. """ size_constraints: Optional[BoxConstraints] = None """ - TBD + Defines the minimum and maximum size of the input decorator. """ collapsed: Optional[bool] = None """ - TBD + Whether the decoration should be the same size as the input field. + + A collapsed decoration removes the extra padding normally added by the decorator. + + Note: + Collapsed decorations do not support :attr:`label`, :attr:`error`, + :attr:`counter`, :attr:`icon`, :attr:`prefix`, or :attr:`suffix`. """ fit_parent_size: Optional[bool] = None """ - TBD + Whether the editable area should expand to fill the height of its parent. + + For controls that support expanding text input, such as + :class:`~flet.TextField`, + setting this to `True` expands the editable area to fill the parent and clears the + line count constraints. + + Note: + When enabled, :attr:`flet.TextField.min_lines` and + :attr:`flet.TextField.max_lines` must effectively remain unset. """ suffix_style: Optional[TextStyle] = None """ - The text style to use for :attr:`~flet.FormFieldControl.suffix`. + The text style to use for :attr:`suffix`. """ async def focus(self): diff --git a/sdk/python/packages/flet/src/flet/controls/material/icon_button.py b/sdk/python/packages/flet/src/flet/controls/material/icon_button.py index d507d817f0..fd5998713e 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/icon_button.py +++ b/sdk/python/packages/flet/src/flet/controls/material/icon_button.py @@ -48,12 +48,12 @@ class IconButton(LayoutControl, AdaptiveControl): icon_color: Optional[ColorValue] = None """ - The foreground color of the :attr:`~flet.IconButton.icon`. + The foreground color of the :attr:`flet.IconButton.icon`. """ icon_size: Optional[Number] = None """ - The :attr:`~flet.IconButton.icon`'s size in virtual pixels. + The :attr:`flet.IconButton.icon`'s size in virtual pixels. Defaults to `24`. """ @@ -63,8 +63,8 @@ class IconButton(LayoutControl, AdaptiveControl): The optional selection state of this button. If this property is not set, the button will behave as a normal push button, - otherwise, the button will toggle between showing :attr:`~flet.IconButton.icon` - (when `False`), and :attr:`~flet.IconButton.selected_icon` (when `True`). + otherwise, the button will toggle between showing :attr:`flet.IconButton.icon` + (when `False`), and :attr:`flet.IconButton.selected_icon` (when `True`). """ selected_icon: Optional[IconDataOrControl] = None @@ -98,9 +98,9 @@ class IconButton(LayoutControl, AdaptiveControl): - If :attr:`flet.Theme.use_material3` is `True`, any parameters defined in style will be overridden by the corresponding parameters in this button. - For example, if icon button :attr:`~flet.IconButton.visual_density` + For example, if icon button :attr:`flet.IconButton.visual_density` is set to :attr:`flet.VisualDensity.STANDARD` and - style's :attr:`~flet.ButtonStyle.visual_density` is + style's :attr:`flet.ButtonStyle.visual_density` is set to :attr:`flet.VisualDensity.COMPACT`, \ :attr:`flet.VisualDensity.STANDARD` will be used. @@ -174,7 +174,7 @@ class IconButton(LayoutControl, AdaptiveControl): """ The URL to open when this button is clicked. - Additionally, if :attr:`~flet.IconButton.on_click` event callback is provided, + Additionally, if :attr:`flet.IconButton.on_click` event callback is provided, it is fired after that. """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/list_tile.py b/sdk/python/packages/flet/src/flet/controls/material/list_tile.py index 028039ccca..035cc146bd 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/list_tile.py +++ b/sdk/python/packages/flet/src/flet/controls/material/list_tile.py @@ -23,18 +23,18 @@ class ListTileTitleAlignment(Enum): """ - Defines how :class:`~flet.ListTile` aligns :attr:`~flet.ListTile.leading` - and :attr:`~flet.ListTile.trailing` relative to the tile's title area. + Defines how :class:`~flet.ListTile` aligns :attr:`flet.ListTile.leading` + and :attr:`flet.ListTile.trailing` relative to the tile's title area. The alignment is computed against the text block formed by - :attr:`~flet.ListTile.title` and :attr:`~flet.ListTile.subtitle`. + :attr:`flet.ListTile.title` and :attr:`flet.ListTile.subtitle`. Use this to tune the visual balance between icon/avatar controls and text, especially when tiles switch between one-line, two-line, and three-line layouts. """ TOP = "top" """ - Aligns :attr:`~flet.ListTile.leading` and :attr:`~flet.ListTile.trailing` + Aligns :attr:`flet.ListTile.leading` and :attr:`flet.ListTile.trailing` toward the top of the title area. Top placement respects :attr:`flet.ListTile.min_vertical_padding`. @@ -42,13 +42,13 @@ class ListTileTitleAlignment(Enum): CENTER = "center" """ - Centers :attr:`~flet.ListTile.leading` and :attr:`~flet.ListTile.trailing` + Centers :attr:`flet.ListTile.leading` and :attr:`flet.ListTile.trailing` relative to the title/subtitle block. """ BOTTOM = "bottom" """ - Aligns :attr:`~flet.ListTile.leading` and :attr:`~flet.ListTile.trailing` + Aligns :attr:`flet.ListTile.leading` and :attr:`flet.ListTile.trailing` toward the bottom of the title area. Bottom placement respects :attr:`flet.ListTile.min_vertical_padding`. @@ -80,7 +80,13 @@ class ListTileStyle(Enum): """ LIST = "list" + """ + Uses the title style intended for list tiles shown in a regular list. + """ DRAWER = "drawer" + """ + Uses the title style intended for list tiles shown in a drawer. + """ @control("ListTile") diff --git a/sdk/python/packages/flet/src/flet/controls/material/navigation_bar.py b/sdk/python/packages/flet/src/flet/controls/material/navigation_bar.py index cef09dee1b..ffa44fe6c9 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/navigation_bar.py +++ b/sdk/python/packages/flet/src/flet/controls/material/navigation_bar.py @@ -28,8 +28,21 @@ class NavigationBarLabelBehavior(Enum): """ ALWAYS_SHOW = "alwaysShow" + """ + Always shows the label below every destination, selected and unselected. + """ ALWAYS_HIDE = "alwaysHide" + """ + Hides every destination label, regardless of which destination is selected. + """ ONLY_SHOW_SELECTED = "onlyShowSelected" + """ + Shows the label only for the selected destination. + + Unselected destinations hide their labels and keep the icon centered. When a + destination becomes selected, its label fades in and the label/icon pair shifts so + both remain centered together. + """ @control("NavigationBarDestination") @@ -171,7 +184,10 @@ class NavigationBar(LayoutControl, AdaptiveControl): border: Optional[Border] = None """ - TBD + The border of the adaptive navigation bar. + + This is applied only when :attr:`adaptive` is `True` and the control is rendered + as a Cupertino tab bar. """ animation_duration: Optional[DurationValue] = None diff --git a/sdk/python/packages/flet/src/flet/controls/material/navigation_drawer.py b/sdk/python/packages/flet/src/flet/controls/material/navigation_drawer.py index fb55dbd330..3612cf73fc 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/navigation_drawer.py +++ b/sdk/python/packages/flet/src/flet/controls/material/navigation_drawer.py @@ -23,7 +23,7 @@ @control("NavigationDrawerDestination") class NavigationDrawerDestination(Control): """ - A :class:`~NavigationDrawer` destination. + Displays an icon with a label, for use in NavigationDrawer destinations. """ label: StrOrControl diff --git a/sdk/python/packages/flet/src/flet/controls/material/outlined_button.py b/sdk/python/packages/flet/src/flet/controls/material/outlined_button.py index 1ad232cdda..631b07213f 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/outlined_button.py +++ b/sdk/python/packages/flet/src/flet/controls/material/outlined_button.py @@ -52,6 +52,12 @@ class OutlinedButton(LayoutControl, AdaptiveControl): style: Optional[ButtonStyle] = None """ + The style to apply to the button. + + Use this to override visual properties such as colors, padding, shape, and + outline side. For outlined buttons, specifying the outline appearance usually + requires setting both :attr:`flet.ButtonStyle.shape` and + :attr:`flet.ButtonStyle.side`. """ autofocus: bool = False diff --git a/sdk/python/packages/flet/src/flet/controls/material/popup_menu_button.py b/sdk/python/packages/flet/src/flet/controls/material/popup_menu_button.py index 9be3b6cba3..3787800d86 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/popup_menu_button.py +++ b/sdk/python/packages/flet/src/flet/controls/material/popup_menu_button.py @@ -193,27 +193,39 @@ class PopupMenuButton(LayoutControl): padding: PaddingValue = 8 """ - TBD + The padding around the button's tappable area. + + This affects the button itself, not the spacing inside the popup menu. """ menu_padding: Optional[PaddingValue] = None """ - TBD + The padding around the menu's contents. + + Use this to inset the list of popup menu entries from the menu's outer boundary. """ style: Optional[ButtonStyle] = None """ - TBD + The button style used for the popup menu button itself. + + This customizes the appearance and interactive states of the anchor button, not + the popup menu entries. """ popup_animation_style: Optional[AnimationStyle] = None """ - TBD + The animation style used when the popup menu opens and closes. + + Use this to customize the menu's motion timing, curves, and related animation + behavior. """ size_constraints: Optional[BoxConstraints] = None """ - TBD + Size constraints applied to the popup menu. + + Use this to control the minimum and maximum size of the menu when it is shown. """ on_open: Optional[ControlEventHandler["PopupMenuButton"]] = None @@ -228,7 +240,10 @@ class PopupMenuButton(LayoutControl): on_select: Optional[ControlEventHandler["PopupMenuButton"]] = None """ - TBD + Called when the user selects a popup menu item. + + The :attr:`flet.Event.data` property of the event handler argument contains the + selected :class:`~flet.PopupMenuItem` control's ID as a string. """ def __contains__(self, item): diff --git a/sdk/python/packages/flet/src/flet/controls/material/reorderable_list_view.py b/sdk/python/packages/flet/src/flet/controls/material/reorderable_list_view.py index f239be5431..dc5bde09d2 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/reorderable_list_view.py +++ b/sdk/python/packages/flet/src/flet/controls/material/reorderable_list_view.py @@ -23,8 +23,8 @@ class OnReorderEvent(Event["ReorderableListView"]): The new position of the item after the reordering, if available. Will be non-`None` only for the following events: - :attr:`~flet.ReorderableListView.on_reorder`, - :attr:`~flet.ReorderableListView.on_reorder_end`. + :attr:`flet.ReorderableListView.on_reorder`, + :attr:`flet.ReorderableListView.on_reorder_end`. """ old_index: Optional[int] = None @@ -32,8 +32,8 @@ class OnReorderEvent(Event["ReorderableListView"]): The previous position of the item before the reordering, if available. Will be non-`None` only for the following events: - :attr:`~flet.ReorderableListView.on_reorder`, - :attr:`~flet.ReorderableListView.on_reorder_start`. + :attr:`flet.ReorderableListView.on_reorder`, + :attr:`flet.ReorderableListView.on_reorder_start`. """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/search_bar.py b/sdk/python/packages/flet/src/flet/controls/material/search_bar.py index b35a3c73ed..9c1ec1c723 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/search_bar.py +++ b/sdk/python/packages/flet/src/flet/controls/material/search_bar.py @@ -26,10 +26,10 @@ class SearchBar(LayoutControl): Manages a "search view" route that allows the user to select one of the suggested \ completions for a search query. + Example: ```python ft.SearchBar(bar_hint_text="Search...") ``` - """ controls: list[Control] = field(default_factory=list) @@ -78,8 +78,8 @@ class SearchBar(LayoutControl): bar_overlay_color: Optional[ControlStateValue[ColorValue]] = None """ Defines the highlight color that's typically used to indicate that the search bar \ - is in :attr:`~flet.ControlState.FOCUSED`, :attr:`~flet.ControlState.HOVERED`, or \ - :attr:`~flet.ControlState.PRESSED` states. + is in :attr:`flet.ControlState.FOCUSED`, :attr:`flet.ControlState.HOVERED`, or \ + :attr:`flet.ControlState.PRESSED` states. """ bar_shadow_color: Optional[ControlStateValue[ColorValue]] = None diff --git a/sdk/python/packages/flet/src/flet/controls/material/segmented_button.py b/sdk/python/packages/flet/src/flet/controls/material/segmented_button.py index 54c6216032..4a587aaa93 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/segmented_button.py +++ b/sdk/python/packages/flet/src/flet/controls/material/segmented_button.py @@ -171,7 +171,7 @@ class SegmentedButton(LayoutControl): """ Called when the selection changes. - The :attr:`~flet.Event.data` property of the event handler argument + The :attr:`flet.Event.data` property of the event handler argument contains a list of strings identifying the selected segments. """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/tabs.py b/sdk/python/packages/flet/src/flet/controls/material/tabs.py index 229453cfc5..03129e4ed7 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/tabs.py +++ b/sdk/python/packages/flet/src/flet/controls/material/tabs.py @@ -129,6 +129,13 @@ class TabBarHoverEvent(Event["TabBar"]): @value class UnderlineTabIndicator: + """ + Draws a horizontal line below the selected tab. + + Use this with :attr:`flet.TabBar.indicator` to customize the indicator's line, + insets, and optional corner radius. + """ + border_side: BorderSide = field( default_factory=lambda: BorderSide(width=2.0, color=Colors.WHITE) ) @@ -155,7 +162,7 @@ class UnderlineTabIndicator: """ -@control("Tabs") +@control("Tabs", categories=("navigation", "layout"), tags=("tabbed", "switcher")) class Tabs(LayoutControl, AdaptiveControl): """ Used for navigating frequently accessed, distinct content categories. Tabs allow \ @@ -249,7 +256,7 @@ class Tabs(LayoutControl, AdaptiveControl): """ Called when :attr:`selected_index` changes. - The :attr:`~flet.Event.data` property of the event handler argument + The :attr:`flet.Event.data` property of the event handler argument contains the index of the selected tab. """ @@ -320,7 +327,7 @@ class TabBarView(LayoutControl, AdaptiveControl): Note: The length of :attr:`controls` must be the same as the - :attr:`~flet.Tabs.length` property of the ancestor :class:`~flet.Tabs`. + :attr:`flet.Tabs.length` property of the ancestor :class:`~flet.Tabs`. """ controls: list[Control] @@ -557,7 +564,7 @@ class TabBar(LayoutControl, AdaptiveControl): """ Called when a tab is clicked. - The :attr:`~flet.Event.data` property of the event handler argument + The :attr:`flet.Event.data` property of the event handler argument contains the index of the clicked tab. """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/text_button.py b/sdk/python/packages/flet/src/flet/controls/material/text_button.py index ea6806b2db..0d999a999b 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/text_button.py +++ b/sdk/python/packages/flet/src/flet/controls/material/text_button.py @@ -87,7 +87,7 @@ class TextButton(LayoutControl, AdaptiveControl): """ Called when a mouse pointer enters or exists this button's response area. - The :attr:`~flet.Event.data` property of the event handler argument is `True` when + The :attr:`flet.Event.data` property of the event handler argument is `True` when cursor enters and `False` when it exits. """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/textfield.py b/sdk/python/packages/flet/src/flet/controls/material/textfield.py index 4cd223a7d6..d08a4fe5ce 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/textfield.py +++ b/sdk/python/packages/flet/src/flet/controls/material/textfield.py @@ -210,8 +210,6 @@ class InputFilter: replacement_string: str = "" """ A string used to replace banned/denied patterns. - - Defaults to an empty string. """ multiline: bool = False @@ -268,7 +266,9 @@ def __init__(self): super().__init__(regex_string=r"^[a-zA-Z]*$", allow=True, replacement_string="") -@control("TextField") +@control( + "TextField", categories=("input", "form"), tags=("text", "editable", "validation") +) class TextField(FormFieldControl, AdaptiveControl): """ A text field lets the user enter text, either with hardware keyboard or with an \ @@ -295,7 +295,7 @@ class TextField(FormFieldControl, AdaptiveControl): Setting this property visually updates the field's selection to match the given value, and hence leads to the :attr:`on_selection_change` event being triggered. To ensure the selection is visible and the event is fired, the text field must - be focused. Call :meth:`~flet.FormFieldControl.focus` + be focused. Call :meth:`flet.FormFieldControl.focus` on the field before setting this property. """ @@ -373,9 +373,9 @@ class TextField(FormFieldControl, AdaptiveControl): Displays a toggle icon button that allows revealing the entered password. Is shown \ if both :attr:`password` and `can_reveal_password` are `True`. - The icon is displayed in the same location as :attr:`~flet.FormFieldControl.suffix` + The icon is displayed in the same location as :attr:`flet.FormFieldControl.suffix` and in case both `can_reveal_password`/:attr:`password` and `suffix` are - provided, then the :attr:`~flet.FormFieldControl.suffix` won't be shown. + provided, then the :attr:`flet.FormFieldControl.suffix` won't be shown. """ read_only: bool = False @@ -466,7 +466,10 @@ class TextField(FormFieldControl, AdaptiveControl): cursor_error_color: Optional[ColorValue] = None """ - TBD + The color of the text cursor while the field is showing an error. + + If not set, the cursor color falls back to the error text style and then to the + theme's error color. """ cursor_width: Number = 2.0 @@ -499,67 +502,98 @@ class TextField(FormFieldControl, AdaptiveControl): obscuring_character: str = "•" """ - TBD + The single character used to mask the text when :attr:`password` is `True`. """ enable_interactive_selection: bool = True """ - TBD + Whether interactive text selection is enabled. + + When enabled, users can move the caret, select text, and use the cut/copy/paste + menu. When disabled, selection cannot be adjusted interactively and editing + shortcuts for cut/copy/paste are suppressed. """ enable_ime_personalized_learning: bool = True """ - TBD + Whether the input method is allowed to learn from what the user types. + + This affects Android only and controls personalized data such as typing history + and user dictionary entries. """ can_request_focus: bool = True """ - TBD + Whether this field can request focus. + + If set to `False`, the field does not request focus when tapped or when its + context menu is shown, and it cannot be reached with keyboard focus traversal. """ ignore_pointers: bool = False """ - TBD + Whether this field ignores pointer events. """ enable_stylus_handwriting: bool = True """ - TBD + Whether this field supports stylus handwriting input. + + On supported devices, the user can write directly on top of the field with a + stylus instead of typing from the keyboard. """ animate_cursor_opacity: Optional[bool] = None """ - TBD + Whether the text cursor animates between transparent and opaque during each blink. + + If not set, the default follows the platform behavior used by Flet. """ always_call_on_tap: bool = False """ - TBD + Whether :attr:`on_click` should be called for every tap. + + By default, only the first tap in a tap sequence triggers :attr:`on_click`. + When enabled, consecutive taps trigger it as well. """ scroll_padding: PaddingValue = 20 """ - TBD + Padding to keep around the field when a surrounding scrollable scrolls it into view. + + When the field receives focus and is partly hidden, for example by the onscreen + keyboard, this padding helps keep space between the field and the edges of the + surrounding scrollable after scrolling. """ clip_behavior: ClipBehavior = ClipBehavior.HARD_EDGE """ - TBD + How the field's contents should be clipped. + + See :class:`~flet.ClipBehavior` for the available clipping modes. """ keyboard_brightness: Optional[Brightness] = None """ - TBD + The brightness to use for the onscreen keyboard. + + This setting is honored on iOS only. """ mouse_cursor: Optional[MouseCursor] = None """ - TBD + The mouse pointer to show while hovering over the field. + + If not set, the standard text cursor is used. """ strut_style: Optional[StrutStyle] = None """ - TBD + The :class:`~flet.StrutStyle` used for vertical text layout. + + Strut style establishes a predictable minimum line height, which is useful when + entered text may vary in font metrics or script. """ autofill_hints: Optional[Union[AutofillHint, list[AutofillHint]]] = None @@ -587,7 +621,10 @@ class TextField(FormFieldControl, AdaptiveControl): on_click: Optional[ControlEventHandler["TextField"]] = None """ - TBD + Called when the field is tapped. + + If :attr:`always_call_on_tap` is `True`, this event is also triggered for + consecutive taps. """ on_submit: Optional[ControlEventHandler["TextField"]] = None @@ -607,7 +644,13 @@ class TextField(FormFieldControl, AdaptiveControl): on_tap_outside: Optional[ControlEventHandler["TextField"]] = None """ - TBD + Called when a pointer-down event occurs outside the field while it is focused. + + Use this to react when the user taps away from the field. + + Note: + This callback is a notification only and does not include the pointer event + details. """ def _migrate_state(self, other: BaseControl): diff --git a/sdk/python/packages/flet/src/flet/controls/material/time_picker.py b/sdk/python/packages/flet/src/flet/controls/material/time_picker.py index e6cab1bd33..88335988df 100644 --- a/sdk/python/packages/flet/src/flet/controls/material/time_picker.py +++ b/sdk/python/packages/flet/src/flet/controls/material/time_picker.py @@ -127,7 +127,7 @@ class TimePicker(DialogControl): but does not participate in page-level locale resolution. If set to `None` (the default) or an inexistent/unsupported locale, - the :attr:`~flet.LocaleConfiguration.current_locale` of the + the :attr:`flet.LocaleConfiguration.current_locale` of the :attr:`flet.Page.locale_configuration` is used as fallback. """ @@ -227,7 +227,7 @@ class TimePicker(DialogControl): Called when user clicks confirm button. :attr:`value` property is updated with selected time. - Additionally, the :attr:`~flet.Event.data` property of the event handler argument + Additionally, the :attr:`flet.Event.data` property of the event handler argument also contains the selected time. """ diff --git a/sdk/python/packages/flet/src/flet/controls/multi_view.py b/sdk/python/packages/flet/src/flet/controls/multi_view.py index 54821801f5..57604eb52e 100644 --- a/sdk/python/packages/flet/src/flet/controls/multi_view.py +++ b/sdk/python/packages/flet/src/flet/controls/multi_view.py @@ -9,14 +9,19 @@ @control() class MultiView(BasePage): """ - TBD + Represents an additional app view managed by a multi-view session. + + Multi-view sessions can create more than one view for the same app. Each view + has its own :attr:`view_id` and can receive an initial payload through + :attr:`initial_data`. """ view_id: int """ - TBD + Unique identifier of this view. """ + initial_data: dict[str, Any] """ - TBD + Initial payload provided when this view was opened. """ diff --git a/sdk/python/packages/flet/src/flet/controls/object_patch.py b/sdk/python/packages/flet/src/flet/controls/object_patch.py index 34a8be5baa..631ae8d860 100644 --- a/sdk/python/packages/flet/src/flet/controls/object_patch.py +++ b/sdk/python/packages/flet/src/flet/controls/object_patch.py @@ -47,10 +47,29 @@ class Operation(Enum): + """ + Operation types supported by object patches. + """ + Replace = 0 + """ + Replace the value at a path. + """ + Add = 1 + """ + Add a value at a path. + """ + Remove = 2 + """ + Remove the value at a path. + """ + Move = 3 + """ + Move a value from one path to another path. + """ class ObjectPatchException(Exception): diff --git a/sdk/python/packages/flet/src/flet/controls/page.py b/sdk/python/packages/flet/src/flet/controls/page.py index 6a874d522a..be0c3fb51e 100644 --- a/sdk/python/packages/flet/src/flet/controls/page.py +++ b/sdk/python/packages/flet/src/flet/controls/page.py @@ -13,14 +13,12 @@ Any, Callable, Optional, + ParamSpec, TypeVar, Union, ) from urllib.parse import urlparse -from flet.auth.authorization import Authorization -from flet.auth.oauth_provider import OAuthProvider -from flet.components.component import Renderer from flet.components.public_utils import unwrap_component from flet.controls.base_control import BaseControl, control from flet.controls.base_page import BasePage @@ -47,11 +45,7 @@ from flet.controls.multi_view import MultiView from flet.controls.query_string import QueryString from flet.controls.ref import Ref -from flet.controls.services.browser_context_menu import BrowserContextMenu -from flet.controls.services.clipboard import Clipboard from flet.controls.services.service import Service -from flet.controls.services.shared_preferences import SharedPreferences -from flet.controls.services.storage_paths import StoragePaths from flet.controls.services.url_launcher import UrlLauncher from flet.controls.types import ( AppLifecycleState, @@ -68,27 +62,32 @@ from flet.utils.from_dict import from_dict from flet.utils.strings import random_string -if not is_pyodide(): - from flet.auth.authorization_service import AuthorizationService - - AuthorizationImpl = AuthorizationService -else: - AuthorizationImpl = Authorization - if TYPE_CHECKING: + from flet.auth.authorization import Authorization + from flet.auth.oauth_provider import OAuthProvider from flet.messaging.session import Session from flet.pubsub.pubsub_client import PubSubClient -try: - from typing import ParamSpec -except ImportError: - from typing_extensions import ParamSpec + +def _default_authorization_impl() -> "type[Authorization]": + """Resolve the default `Authorization` implementation lazily. + + Deferring these imports keeps the auth subsystem out of the cold-start + import graph for apps that never call `Page.login`. + """ + if not is_pyodide(): + from flet.auth.authorization_service import AuthorizationService + + return AuthorizationService + from flet.auth.authorization import Authorization + + return Authorization logger = logging.getLogger("flet") -AT = TypeVar("AT", bound=Authorization) +AT = TypeVar("AT", bound="Authorization") InputT = ParamSpec("InputT") RetT = TypeVar("RetT") @@ -599,12 +598,17 @@ class Page(BasePage): on_multi_view_add: Optional[EventHandler[MultiViewAddEvent]] = None """ - TBD + Called when a new multi-view is created. + + The event payload includes the new view's identifier and any initial data passed + when opening the view. """ on_multi_view_remove: Optional[EventHandler[MultiViewRemoveEvent]] = None """ - TBD + Called when a multi-view is removed. + + The event payload includes the identifier of the removed view. """ _services: ServiceRegistry = field(default_factory=ServiceRegistry) @@ -652,6 +656,8 @@ def render( **kwargs: Keyword arguments passed to `component`. """ + from flet.components.component import Renderer + logger.debug("Page.render()") self._notify = self.__notify self.views[0].controls = Renderer().render(component, *args, **kwargs) @@ -675,6 +681,8 @@ def render_views( **kwargs: Keyword arguments passed to `component`. """ + from flet.components.component import Renderer + logger.debug("Page.render_views()") self._notify = self.__notify self.views = Renderer().render(component, *args, **kwargs) @@ -1045,7 +1053,7 @@ def get_upload_url(self, file_name: str, expires: int) -> str: async def login( self, - provider: OAuthProvider, + provider: "OAuthProvider", fetch_user: bool = True, fetch_groups: bool = False, scope: Optional[list[str]] = None, @@ -1055,14 +1063,16 @@ async def login( ] = None, complete_page_html: Optional[str] = None, redirect_to_page: Optional[bool] = False, - authorization: type[AT] = AuthorizationImpl, - ) -> AT: + authorization: "Optional[type[AT]]" = None, + ) -> "AT": """ Starts OAuth flow. See [Authentication](https://flet.dev/docs/cookbook/authentication) guide for more information and examples. """ + if authorization is None: + authorization = _default_authorization_impl() self.__authorization = authorization( provider, fetch_user=fetch_user, @@ -1273,7 +1283,7 @@ def executor(self) -> Optional[ThreadPoolExecutor]: return self.session.connection.executor @property - def auth(self) -> Optional[Authorization]: + def auth(self) -> "Optional[Authorization]": """ The current authorization context, or `None` if the user is not authorized. """ @@ -1310,6 +1320,7 @@ def browser_context_menu(self): """ The BrowserContextMenu service for the current page. """ + from flet.controls.services.browser_context_menu import BrowserContextMenu return BrowserContextMenu() @@ -1324,6 +1335,7 @@ def shared_preferences(self): """ The SharedPreferences service for the current page. """ + from flet.controls.services.shared_preferences import SharedPreferences return SharedPreferences() @@ -1338,6 +1350,7 @@ def clipboard(self): """ The Clipboard service for the current page. """ + from flet.controls.services.clipboard import Clipboard return Clipboard() @@ -1352,6 +1365,7 @@ def storage_paths(self): """ The StoragePaths service for the current page. """ + from flet.controls.services.storage_paths import StoragePaths return StoragePaths() @@ -1367,7 +1381,7 @@ async def get_device_info(self) -> Optional[DeviceInfo]: if self.web: return from_dict(WebDeviceInfo, info) - elif self.platform == PagePlatform.ANDROID: + elif self.platform in [PagePlatform.ANDROID, PagePlatform.ANDROID_TV]: return from_dict(AndroidDeviceInfo, info) elif self.platform == PagePlatform.IOS: return from_dict(IosDeviceInfo, info) diff --git a/sdk/python/packages/flet/src/flet/controls/painting.py b/sdk/python/packages/flet/src/flet/controls/painting.py index 05ce657f34..eb88d8ea17 100644 --- a/sdk/python/packages/flet/src/flet/controls/painting.py +++ b/sdk/python/packages/flet/src/flet/controls/painting.py @@ -350,32 +350,59 @@ class Paint: stroke_cap: Optional[StrokeCap] = None """ - TBD + The kind of finish to place on the ends of stroked lines. + + This applies when :attr:`style` is :attr:`flet.PaintingStyle.STROKE`. + If not set, the effective default is :attr:`flet.StrokeCap.BUTT`. """ stroke_join: Optional[StrokeJoin] = None """ - TBD + The kind of finish to place on joins between stroked segments. + + This applies when :attr:`style` is + :attr:`flet.PaintingStyle.STROKE`. If not set, the effective default is + :attr:`flet.StrokeJoin.MITER`. + + See also: + :attr:`stroke_miter_limit` """ stroke_miter_limit: Optional[Number] = None """ - TBD + The limit for drawing miter joins when :attr:`stroke_join` is + :attr:`flet.StrokeJoin.MITER` and :attr:`style` is + :attr:`flet.PaintingStyle.STROKE`. + + If this limit is exceeded, a bevel join is used instead. If not set, the effective + default is `4.0`. """ stroke_width: Optional[Number] = None """ - TBD + How wide stroked edges should be, in logical pixels. + + This applies when :attr:`style` is :attr:`flet.PaintingStyle.STROKE`. If not set, + the effective default is `0.0`, which corresponds to a hairline width. """ stroke_dash_pattern: Optional[list[Number]] = None """ - TBD + Dash pattern used when painting stroked outlines. + + Values alternate between painted dash lengths and unpainted gap lengths. For + example, `[5, 10]` paints a dash 5 logical pixels long, then leaves a gap 10 + logical pixels long, repeating the pattern along the stroked path. + + Note: + This applies only when :attr:`style` is :attr:`flet.PaintingStyle.STROKE`. """ style: Optional[PaintingStyle] = None """ - TBD + Whether to paint filled interiors or only stroked outlines. + + If not set, the effective default is :attr:`flet.PaintingStyle.FILL`. """ def copy( diff --git a/sdk/python/packages/flet/src/flet/controls/scrollable_control.py b/sdk/python/packages/flet/src/flet/controls/scrollable_control.py index 51d7bc7e6e..1701cb1bc2 100644 --- a/sdk/python/packages/flet/src/flet/controls/scrollable_control.py +++ b/sdk/python/packages/flet/src/flet/controls/scrollable_control.py @@ -2,7 +2,7 @@ from enum import Enum from typing import Optional, Union -from flet.controls.animation import AnimationCurve +from flet.controls.animation import AnimationCurve, AnimationValue from flet.controls.base_control import control from flet.controls.control import Control from flet.controls.control_event import Event, EventHandler @@ -56,8 +56,8 @@ class ScrollType(Enum): """ Viewport was overscrolled. - See :attr:`~flet.OnScrollEvent.overscroll` and - :attr:`~flet.OnScrollEvent.velocity` are available. + See :attr:`flet.OnScrollEvent.overscroll` and + :attr:`flet.OnScrollEvent.velocity` are available. """ @@ -351,13 +351,28 @@ class ScrollableControl(Control): auto_scroll: bool = False """ - Whether the scrollbar should automatically move its position to the end when \ - children updated. + Whether to automatically move the scroll position to the end when the content + changes. + + This keeps the view pinned to the end as new children are added *and* as + existing content grows in place (e.g. text streamed into an existing child). + Pinning is suspended while the user has scrolled away from the end, and + resumes once they scroll back. Note: Must be `False` for :meth:`scroll_to` method to work. """ + auto_scroll_animation: Optional[AnimationValue] = None + """ + Animation used when :attr:`auto_scroll` moves the view to the end. + + Accepts an :class:`~flet.Animation` (duration + curve), an `int` duration in + milliseconds, or `True`. Defaults to a 1 second `ease` animation; set a + duration of `0` for an instant jump (recommended when following fast, + token-by-token streaming so the view stays tightly pinned). + """ + scroll_interval: Number = 10 """ Throttling in milliseconds for :attr:`on_scroll` event. diff --git a/sdk/python/packages/flet/src/flet/controls/services/file_picker.py b/sdk/python/packages/flet/src/flet/controls/services/file_picker.py index ba2e954603..a3fdb02c66 100644 --- a/sdk/python/packages/flet/src/flet/controls/services/file_picker.py +++ b/sdk/python/packages/flet/src/flet/controls/services/file_picker.py @@ -135,7 +135,7 @@ class FilePickerFile: """ File contents. - Returned only when :meth:`~flet.FilePicker.pick_files` is called with + Returned only when :meth:`flet.FilePicker.pick_files` is called with `with_data=True`. Otherwise this value is `None`. """ @@ -185,8 +185,8 @@ class FilePicker(Service): Called when a file is uploaded via :meth:`upload` method. This callback is invoked at least twice for each uploaded file: once with `0.0` - :attr:`~flet.FilePickerUploadEvent.progress` before the upload starts, and once with - `1.0` :attr:`~flet.FilePickerUploadEvent.progress` when the upload completes. + :attr:`flet.FilePickerUploadEvent.progress` before the upload starts, and once with + `1.0` :attr:`flet.FilePickerUploadEvent.progress` when the upload completes. For files larger than 1 MB, additional progress events are emitted at every 10% increment (for example, `0.1`, `0.2`, ...). @@ -258,9 +258,9 @@ async def save_file( name to save a file. Note: - - On desktop this method only opens a dialog for the user to select - a location and file name, and returns the chosen path. The file - itself is not created or saved. + - On desktop, this method opens a dialog for the user to select a + location and file name. If `src_bytes` is provided, those bytes + are written to the selected file. Args: dialog_title: The title of the dialog window. @@ -270,8 +270,7 @@ async def save_file( src_bytes: The contents of a file. Must be provided in web, iOS or Android modes. allowed_extensions: The allowed file extensions. Has effect only if - `file_type` is - :attr:`flet.FilePickerFileType.CUSTOM`. + `file_type` is :attr:`flet.FilePickerFileType.CUSTOM`. Raises: ValueError: If `src_bytes` is not provided, when called in web mode, @@ -308,6 +307,8 @@ async def pick_files( allowed_extensions: Optional[list[str]] = None, allow_multiple: bool = False, with_data: bool = False, + compression_quality: int = 0, + cancel_upload_on_window_blur: bool = True, ) -> list[FilePickerFile]: """ Opens a pick file dialog. @@ -323,12 +324,26 @@ async def pick_files( allow_multiple: Allow the selection of multiple files at once. with_data: Read selected file contents into :attr:`~flet.FilePickerFile.bytes`. + compression_quality: Image compression quality from `0` to `100`. + `0` disables compression. + cancel_upload_on_window_blur: Web-only. Whether to treat browser + window blur as a cancelled selection. Set to `False` to avoid + losing valid selections on slow networks or slow machines. allowed_extensions: The allowed file extensions. Has effect only if `file_type` is :attr:`flet.FilePickerFileType.CUSTOM`. Returns: A list of selected files. + + Raises: + ValueError: If `compression_quality` is not between + `0` and `100` inclusive. """ + if not (0 <= compression_quality <= 100): + raise ValueError( + "compression_quality must be between 0 and 100 inclusive, " + f"got {compression_quality}." + ) files = await self._invoke_method( "pick_files", { @@ -338,6 +353,8 @@ async def pick_files( "allowed_extensions": allowed_extensions, "allow_multiple": allow_multiple, "with_data": with_data, + "compression_quality": compression_quality, + "cancel_upload_on_window_blur": cancel_upload_on_window_blur, }, timeout=3600, ) diff --git a/sdk/python/packages/flet/src/flet/controls/services/haptic_feedback.py b/sdk/python/packages/flet/src/flet/controls/services/haptic_feedback.py index e3e7ebcd46..7d3c788b92 100644 --- a/sdk/python/packages/flet/src/flet/controls/services/haptic_feedback.py +++ b/sdk/python/packages/flet/src/flet/controls/services/haptic_feedback.py @@ -37,6 +37,9 @@ async def vibrate(self): async def selection_click(self): """ - TBD + Provides haptic feedback for a selection changing through discrete values. + + On supported platforms, this is typically used for controls such as pickers, + sliders, or other inputs where the selected value changes one step at a time. """ await self._invoke_method("selection_click") diff --git a/sdk/python/packages/flet/src/flet/controls/services/storage_paths.py b/sdk/python/packages/flet/src/flet/controls/services/storage_paths.py index 79f3da135a..9d7714cff3 100644 --- a/sdk/python/packages/flet/src/flet/controls/services/storage_paths.py +++ b/sdk/python/packages/flet/src/flet/controls/services/storage_paths.py @@ -22,6 +22,10 @@ async def get_application_cache_directory(self) -> str: If this directory does not exist, it is created automatically. + Tip: + In a running Flet app, this path is also exposed synchronously via + the `FLET_APP_STORAGE_CACHE` environment variable. + Returns: The path to a directory where the application may place cache files. @@ -64,6 +68,10 @@ async def get_application_support_directory(self) -> str: This directory is created automatically if it does not exist. Use this for files not exposed to the user. Do not use for user data files. + Tip: + In a running Flet app, the `FLET_APP_STORAGE_DATA` environment + variable points to a `data` subdirectory of this path. + Raises: FletUnsupportedPlatformException: If called on the web platform. @@ -175,6 +183,10 @@ async def get_temporary_directory(self) -> str: Files may be cleared at any time. The caller is responsible for managing files within this directory. + Tip: + In a running Flet app, this path is also exposed synchronously via + the `FLET_APP_STORAGE_TEMP` environment variable. + Raises: FletUnsupportedPlatformException: If called on the web platform. @@ -193,6 +205,10 @@ async def get_console_log_filename(self) -> str: This file is located in the :meth:`flet.StoragePaths.get_application_cache_directory`. + Tip: + In a running Flet app, this path is also exposed synchronously via + the `FLET_APP_CONSOLE` environment variable. + Raises: FletUnsupportedPlatformException: If called on the web platform. diff --git a/sdk/python/packages/flet/src/flet/controls/text_style.py b/sdk/python/packages/flet/src/flet/controls/text_style.py index 0130feb346..4d914d9040 100644 --- a/sdk/python/packages/flet/src/flet/controls/text_style.py +++ b/sdk/python/packages/flet/src/flet/controls/text_style.py @@ -318,7 +318,10 @@ class TextStyle: shadow: Optional[BoxShadowValue] = None """ - TBD + A list of shadows painted underneath the text. + + Multiple shadows can be used to simulate lighting from multiple sources. Shadow + order matters because different orders can produce different transparency results. """ foreground: Optional[Paint] = None @@ -411,7 +414,11 @@ def copy( @value class StrutStyle: """ - TBD + Defines the strut used for vertical text layout. + + A strut sets the minimum line height relative to the baseline and applies to every + line in the paragraph. It is useful when text may vary in script or font metrics + but should still keep a predictable vertical rhythm. """ size: Optional[Number] = None diff --git a/sdk/python/packages/flet/src/flet/controls/theme.py b/sdk/python/packages/flet/src/flet/controls/theme.py index 390b043962..f5e9d2a9f2 100644 --- a/sdk/python/packages/flet/src/flet/controls/theme.py +++ b/sdk/python/packages/flet/src/flet/controls/theme.py @@ -523,7 +523,7 @@ class TextTheme: @value class ScrollbarTheme: """ - Customizes the colors, thickness, and shape of scrollbars across the app. + Customizes the colors, thickness, and shape of descendant scrollbars. """ thumb_visibility: Optional[ControlStateValue[bool]] = None @@ -609,7 +609,7 @@ class ScrollbarTheme: @value class TabBarTheme: """ - Customizes the appearance of :class:`~flet.TabBar` control across the app. + Customizes the appearance of descendant :class:`~flet.TabBar` controls. """ indicator_size: Optional[TabBarIndicatorSize] = None @@ -741,7 +741,7 @@ class SystemOverlayStyle: @value class DialogTheme: """ - Customizes the appearance of :class:`~flet.AlertDialog` across the app. + Customizes the appearance of descendant :class:`~flet.AlertDialog` controls. """ bgcolor: Optional[ColorValue] = None @@ -823,7 +823,7 @@ class DialogTheme: @value class ButtonTheme: """ - Customizes the appearance of :class:`~flet.Button` across the app. + Customizes the appearance of descendant :class:`~flet.Button` controls. """ style: Optional[ButtonStyle] = None @@ -836,7 +836,7 @@ class ButtonTheme: @value class OutlinedButtonTheme: """ - Customizes the appearance of :class:`~flet.OutlinedButton` across the app. + Customizes the appearance of descendant :class:`~flet.OutlinedButton` controls. """ style: Optional[ButtonStyle] = None @@ -849,7 +849,7 @@ class OutlinedButtonTheme: @value class TextButtonTheme: """ - Customizes the appearance of :class:`~flet.TextButton` across the app. + Customizes the appearance of descendant :class:`~flet.TextButton` controls. """ style: Optional[ButtonStyle] = None @@ -862,7 +862,7 @@ class TextButtonTheme: @value class FilledButtonTheme: """ - Customizes the appearance of :class:`~flet.FilledButton` across the app. + Customizes the appearance of descendant :class:`~flet.FilledButton` controls. """ style: Optional[ButtonStyle] = None @@ -876,7 +876,7 @@ class FilledButtonTheme: @value class IconButtonTheme: """ - Customizes the appearance of :class:`~flet.IconButton` across the app. + Customizes the appearance of descendant :class:`~flet.IconButton` controls. """ style: Optional[ButtonStyle] = None @@ -889,7 +889,7 @@ class IconButtonTheme: @value class BottomSheetTheme: """ - Customizes the appearance of :class:`~flet.BottomSheet` across the app. + Customizes the appearance of descendant :class:`~flet.BottomSheet` controls. """ bgcolor: Optional[ColorValue] = None @@ -951,7 +951,7 @@ class BottomSheetTheme: @value class CardTheme: """ - Customizes the appearance of :class:`~flet.Card` across the app. + Customizes the appearance of descendant :class:`~flet.Card` controls. """ color: Optional[ColorValue] = None @@ -994,7 +994,7 @@ class CardTheme: @value class ChipTheme: """ - Customizes the appearance of :class:`~flet.Chip` across the app. + Customizes the appearance of descendant :class:`~flet.Chip` controls. """ color: Optional[ControlStateValue[ColorValue]] = None @@ -1121,8 +1121,8 @@ class ChipTheme: @value class FloatingActionButtonTheme: """ - Customizes the appearance of :class:`~flet.FloatingActionButton` - across the app. + Customizes the appearance of descendant :class:`~flet.FloatingActionButton` + controls. """ bgcolor: Optional[ColorValue] = None @@ -1234,7 +1234,7 @@ class FloatingActionButtonTheme: @value class NavigationRailTheme: """ - Customizes the appearance of :class:`~flet.NavigationRail` across the app. + Customizes the appearance of descendant :class:`~flet.NavigationRail` controls. """ bgcolor: Optional[ColorValue] = None @@ -1309,7 +1309,7 @@ class NavigationRailTheme: @value class AppBarTheme: """ - Customizes the appearance of :class:`~flet.AppBar` controls across the app. + Customizes the appearance of descendant :class:`~flet.AppBar` controls. """ color: Optional[ColorValue] = None @@ -1390,7 +1390,7 @@ class AppBarTheme: @value class BottomAppBarTheme: """ - Customizes the appearance of :class:`~flet.BottomAppBar` controls across the app. + Customizes the appearance of descendant :class:`~flet.BottomAppBar` controls. """ bgcolor: Optional[ColorValue] = None @@ -1836,7 +1836,7 @@ class BannerTheme: @value class DatePickerTheme: """ - Customizes the appearance of :class:`~flet.DatePicker` controls across the app. + Customizes the appearance of descendant :class:`~flet.DatePicker` controls. """ bgcolor: Optional[ColorValue] = None @@ -1899,7 +1899,8 @@ class DatePickerTheme: range_picker_elevation: Optional[Number] = None """ - Overrides the default elevation of the full screen DateRangePicker (TBD). + Overrides the default elevation of the full screen + :class:`~flet.DateRangePicker`. """ day_text_style: Optional[TextStyle] = None @@ -2013,7 +2014,8 @@ class DatePickerTheme: range_picker_shape: Optional[OutlinedBorder] = None """ - Overrides the default overall shape of a full screen DateRangePicker (TBD). + Overrides the default overall shape of a full screen + :class:`~flet.DateRangePicker`. If elevation is greater than zero then a shadow is shown and the shadow's shape mirrors the shape of the dialog. @@ -2022,7 +2024,7 @@ class DatePickerTheme: range_picker_header_help_text_style: Optional[TextStyle] = None """ Overrides the default text style used for the help text of the header of a full \ - screen DateRangePicker (TBD). + screen :class:`~flet.DateRangePicker`. The help text (also referred to as "supporting text" in the Material spec) is usually a prompt to the user at the top of the header (i.e. 'Select date'). @@ -2108,7 +2110,7 @@ class DatePickerTheme: @value class TimePickerTheme: """ - Customizes the appearance of :class:`~flet.TimePicker` controls across the app. + Customizes the appearance of descendant :class:`~flet.TimePicker` controls. """ bgcolor: Optional[ColorValue] = None @@ -2247,7 +2249,7 @@ class TimePickerTheme: @value class DropdownTheme: """ - Customizes the appearance of :class:`~flet.Dropdown` across the app. + Customizes the appearance of descendant :class:`~flet.Dropdown` controls. """ menu_style: Optional[MenuStyle] = None @@ -2685,8 +2687,8 @@ class SliderTheme: @value class ProgressIndicatorTheme: """ - Customizes the appearance of progress indicators (:class:`~flet.ProgressBar`, \ - :class:`~flet.ProgressRing`) across the app. + Customizes the appearance of descendant progress indicators + (:class:`~flet.ProgressBar`, :class:`~flet.ProgressRing`). """ color: Optional[ColorValue] = None @@ -2707,7 +2709,10 @@ class ProgressIndicatorTheme: refresh_bgcolor: Optional[ColorValue] = None """ - Background color of that fills the circle under the RefreshIndicator (TBD). + Background color that fills the circle under the refresh indicator. + + If a refresh indicator does not specify its own background color, this theme + value is used. If this is also not set, the current theme's canvas color is used. """ linear_min_height: Optional[Number] = None @@ -2771,7 +2776,7 @@ class ProgressIndicatorTheme: @value class PopupMenuTheme: """ - Customizes the appearance of :class:`~flet.PopupMenuButton` across the app. + Customizes the appearance of descendant :class:`~flet.PopupMenuButton` controls. """ color: Optional[ColorValue] = None @@ -2845,7 +2850,7 @@ class PopupMenuTheme: @value class SearchBarTheme: """ - Customizes the appearance of :class:`~flet.SearchBar` controls across the app. + Customizes the appearance of descendant :class:`~flet.SearchBar` controls. """ bgcolor: Optional[ColorValue] = None @@ -2920,7 +2925,8 @@ class SearchBarTheme: @value class SearchViewTheme: """ - Customizes the appearance of :class:`~flet.SearchBar` controls across the app. + Customizes the appearance of descendant search views presented by + :class:`~flet.SearchBar`. """ bgcolor: Optional[ColorValue] = None @@ -3295,15 +3301,43 @@ class Theme: """ appbar_theme: Optional[AppBarTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.AppBar` controls. + """ + badge_theme: Optional[BadgeTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.Badge` controls. + """ + banner_theme: Optional[BannerTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.Banner` controls. + """ + bottom_appbar_theme: Optional[BottomAppBarTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.BottomAppBar` controls. + """ + bottom_sheet_theme: Optional[BottomSheetTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.BottomSheet` controls. + """ + card_theme: Optional[CardTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.Card` controls. + """ + checkbox_theme: Optional[CheckboxTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.Checkbox` controls. + """ + chip_theme: Optional[ChipTheme] = None """ - Customizes the appearance of :class:`~flet.Chip` across the app. + Customizes the appearance of descendant :class:`~flet.Chip` controls. """ color_scheme: Optional[ColorScheme] = None @@ -3313,17 +3347,17 @@ class Theme: data_table_theme: Optional[DataTableTheme] = None """ - Customizes the appearance of :class:`~flet.DataTable` across the app. + Customizes the appearance of descendant :class:`~flet.DataTable` controls. """ date_picker_theme: Optional[DatePickerTheme] = None """ - Customizes the appearance of :class:`~flet.DatePicker` across the app. + Customizes the appearance of descendant :class:`~flet.DatePicker` controls. """ dialog_theme: Optional[DialogTheme] = None """ - Customizes the appearance of :class:`~flet.AlertDialog` across the app. + Customizes the appearance of descendant :class:`~flet.AlertDialog` controls. """ divider_theme: Optional[DividerTheme] = None @@ -3344,87 +3378,227 @@ class Theme: dropdown_theme: Optional[DropdownTheme] = None """ - Customizes the appearance of :class:`~flet.Dropdown` across the app. + Customizes the appearance of descendant :class:`~flet.Dropdown` controls. """ button_theme: Optional[ButtonTheme] = None """ - Customizes the appearance of :class:`~flet.Button` across the app. + Customizes the appearance of descendant :class:`~flet.Button` controls. """ outlined_button_theme: Optional[OutlinedButtonTheme] = None """ - Customizes the appearance of :class:`~flet.OutlinedButton` across the app. + Customizes the appearance of descendant :class:`~flet.OutlinedButton` + controls. """ text_button_theme: Optional[TextButtonTheme] = None """ - Customizes the appearance of :class:`~flet.TextButton` across the app. + Customizes the appearance of descendant :class:`~flet.TextButton` controls. """ filled_button_theme: Optional[FilledButtonTheme] = None """ - Customizes the appearance of :class:`~flet.FilledButton` across the app. + Customizes the appearance of descendant :class:`~flet.FilledButton` controls. """ icon_button_theme: Optional[IconButtonTheme] = None """ - Customizes the appearance of :class:`~flet.IconButton` across the app. + Customizes the appearance of descendant :class:`~flet.IconButton` controls. """ expansion_tile_theme: Optional[ExpansionTileTheme] = None """ - Customizes the appearance of :class:`~flet.ExpansionTile` across the app. + Customizes the appearance of descendant :class:`~flet.ExpansionTile` + controls. """ floating_action_button_theme: Optional[FloatingActionButtonTheme] = None """ - Customizes the appearance of :class:`~flet.FloatingActionButton` - across the app. + Customizes the appearance of descendant :class:`~flet.FloatingActionButton` + controls. """ icon_theme: Optional[IconTheme] = None """ - Customizes the appearance of :class:`~flet.Icon` across the app. + Customizes the appearance of descendant :class:`~flet.Icon` controls. """ list_tile_theme: Optional[ListTileTheme] = None """ - Customizes the appearance of :class:`~flet.ListTile` across the app. + Customizes the appearance of descendant :class:`~flet.ListTile` controls. """ navigation_bar_theme: Optional[NavigationBarTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.NavigationBar` controls. + """ + navigation_drawer_theme: Optional[NavigationDrawerTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.NavigationDrawer` + controls. + """ + navigation_rail_theme: Optional[NavigationRailTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.NavigationRail` controls. + """ + page_transitions: PageTransitionsTheme = field(default_factory=PageTransitionsTheme) + """ + Configures the default page transition presets used for route changes. + """ + popup_menu_theme: Optional[PopupMenuTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.PopupMenuButton` + controls. + """ + splash_color: Optional[ColorValue] = None + """ + The color of ink splashes. + """ + highlight_color: Optional[ColorValue] = None + """ + The highlight color used during ink splash animations or to indicate a selected \ + menu item. + """ + hover_color: Optional[ColorValue] = None + """ + The color used to indicate that a pointer is hovering over a control. + """ + focus_color: Optional[ColorValue] = None + """ + The color used to indicate that a control has input focus. + """ + unselected_control_color: Optional[ColorValue] = None + """ + The color used for controls in their inactive but enabled state, such as an \ + unchecked :class:`~flet.Checkbox`. + """ + disabled_color: Optional[ColorValue] = None + """ + The color used for disabled controls and text. + """ + canvas_color: Optional[ColorValue] = None + """ + The default color for canvas surfaces behind Material controls. + """ + scaffold_bgcolor: Optional[ColorValue] = None """ - Customizes the page background color. + The default background color for scaffold-like page surfaces. """ + card_bgcolor: Optional[ColorValue] = None + """ + The default background color for :class:`~flet.Card` controls. + """ + hint_color: Optional[ColorValue] = None + """ + The color used for hint or placeholder text, for example in + :class:`~flet.TextField` controls. + """ + secondary_header_color: Optional[ColorValue] = None + """ + The color used for secondary headers, such as the header of a paginated data table + when rows are selected. + """ + primary_text_theme: Optional[TextTheme] = None + """ + A text theme that contrasts with the theme's primary color. + """ + progress_indicator_theme: Optional[ProgressIndicatorTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.ProgressBar` and + :class:`~flet.ProgressRing` controls. + """ + radio_theme: Optional[RadioTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.Radio` controls. + """ + scrollbar_theme: Optional[ScrollbarTheme] = None + """ + Customizes the appearance of descendant scrollbars. + """ + search_bar_theme: Optional[SearchBarTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.SearchBar` controls. + """ + search_view_theme: Optional[SearchViewTheme] = None + """ + Customizes the appearance of the search view presented by + :class:`~flet.SearchBar`. + """ + segmented_button_theme: Optional[SegmentedButtonTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.SegmentedButton` + controls. + """ + slider_theme: Optional[SliderTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.Slider` and + :class:`~flet.RangeSlider` controls. + """ + snackbar_theme: Optional[SnackBarTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.SnackBar` controls. + """ + switch_theme: Optional[SwitchTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.Switch` controls. + """ + system_overlay_style: Optional[SystemOverlayStyle] = None + """ + Customizes the appearance of the system status bar and navigation bar on mobile \ + platforms. + """ + tab_bar_theme: Optional[TabBarTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.TabBar` controls. + """ + text_theme: Optional[TextTheme] = None + """ + The default text styles for descendant controls. + """ + time_picker_theme: Optional[TimePickerTheme] = None + """ + Customizes the appearance of descendant :class:`~flet.TimePicker` controls. + """ + tooltip_theme: Optional[TooltipTheme] = None + """ + Customizes the appearance of descendant tooltips. + """ + visual_density: Optional[VisualDensity] = None + """ + Specifies how compact descendant Material controls should be. + + Negative density values make supported controls denser and more compact, while + positive values make them more spacious. See :class:`~flet.VisualDensity`. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/types.py b/sdk/python/packages/flet/src/flet/controls/types.py index cd54debbae..a745290e6f 100644 --- a/sdk/python/packages/flet/src/flet/controls/types.py +++ b/sdk/python/packages/flet/src/flet/controls/types.py @@ -21,32 +21,102 @@ class AppView(Enum): """ - TBD + Defines how an app launched with :func:`flet.run` or :func:`flet.run_async` + should be displayed. """ WEB_BROWSER = "web_browser" + """ + Runs the app as a web server and opens it in the user's web browser. + """ + FLET_APP = "flet_app" + """ + Runs the app in a Flet desktop window. + """ + FLET_APP_WEB = "flet_app_web" + """ + Runs the app in a Flet desktop window backed by the web server mode. + """ + FLET_APP_HIDDEN = "flet_app_hidden" + """ + Starts the Flet desktop window hidden. + """ class WebRenderer(Enum): """ - TBD + Selects which Flutter web renderer should be used for a web-hosted app. + + Use this with the `web_renderer` argument of :func:`flet.run` or + :func:`flet.run_async`. + + Note: + The available renderer choices depend on how the web frontend was built. + A default web build provides CanvasKit. A WebAssembly build can make both + CanvasKit and skwasm available. """ AUTO = "auto" + """ + Lets the runtime choose the renderer automatically. + + In WebAssembly builds, Chromium-based browsers prefer skwasm and other + browsers fall back to CanvasKit; in default web builds, CanvasKit is used. + """ CANVAS_KIT = "canvaskit" + """ + Uses the CanvasKit renderer. + + CanvasKit is broadly compatible with modern browsers and is the default + renderer for web builds. Compared to skwasm, it is significantly faster + at exchanging byte buffers between JavaScript and Dart, which Flet apps + do on every UI update. + """ SKWASM = "skwasm" + """ + Uses the skwasm renderer. + + skwasm is available for WebAssembly web builds and can provide better + rendering performance, at the cost of slower byte-buffer exchange across + the JavaScript/Dart boundary. Browsers and servers must meet the + requirements for WebAssembly support, and multi-threaded rendering + additionally requires the necessary SharedArrayBuffer security setup. + """ class RouteUrlStrategy(Enum): """ - TBD + Controls how routes are represented in the browser URL for web apps. + + Use this with the `route_url_strategy` argument of :func:`flet.run` or + :func:`flet.run_async`. + + Note: + This setting affects web-hosted apps only. """ PATH = "path" + """ + Stores routes in the browser pathname. + + URLs look like `https://example.com/store`. + + Note: + This strategy usually requires the web server to rewrite unmatched requests to + `index.html` so deep links and page reloads continue to work. + """ HASH = "hash" + """ + Stores routes in the URL fragment after `#`. + + URLs look like `https://example.com/#/store`. + + This strategy is useful when you cannot configure the hosting server for + pathname-based routing. + """ class UrlTarget(Enum): @@ -190,11 +260,36 @@ def __post_init__(self): @value class AutomaticNotchShape(NotchShape): """ - A notch sahpe created from :class:`~flet.ShapeBorder`s. + A notch shape created from :class:`~flet.ShapeBorder` values. + + It uses one shape as the outer outline and optionally subtracts a second shape + to form the notch. This is commonly used for controls such as + :class:`~flet.BottomAppBar` that need to make room for a floating action button. """ host: "ShapeBorder" + """ + The shape of the control that uses the notch. + + This is typically the outer shape of the host control, such as a + :class:`~flet.BottomAppBar`. + + Note: + The shape must not depend on text direction. + """ guest: Optional["ShapeBorder"] = None + """ + The shape to subtract from :attr:`host` to create the notch. + + This is typically the shape of the control the notch should accommodate, such as + a :class:`~flet.FloatingActionButton`. + + If this is `None`, no notch is cut out even when space for a guest control is + available. + + Note: + The shape must not depend on text direction. + """ def __post_init__(self): self._type = "auto" @@ -328,6 +423,9 @@ class VerticalAlignment(Enum): """ NONE = None + """ + Use the default vertical alignment. + """ START = -1.0 """ @@ -347,7 +445,7 @@ class VerticalAlignment(Enum): class LabelPosition(Enum): """ - Position of label in a :class:`~flet.Checkbox`, :class:`~flet.Radio` or \ + Position of label in a :class:`~flet.Checkbox`, :class:`~flet.Radio` or :class:`~flet.Switch` """ @@ -364,40 +462,186 @@ class LabelPosition(Enum): class BlendMode(Enum): """ - See [BlendMode](https://api.flutter.dev/flutter/dart-ui/BlendMode.html) from \ - Flutter documentation for blend mode examples. + Algorithms used to combine source and destination pixels during painting. + + The source is the content being drawn and the destination is the content already + present behind it. """ CLEAR = "clear" + """ + Drops both the source and destination, leaving a fully transparent result. + """ + COLOR = "color" + """ + Takes the hue and saturation from the source and the luminosity from the + destination. + """ + COLOR_BURN = "colorBurn" + """ + Darkens the destination by dividing the inverse destination by the source and + then inverting the result. + """ + COLOR_DODGE = "colorDodge" + """ + Brightens the destination by dividing it by the inverse of the source. + """ + DARKEN = "darken" + """ + Chooses the darker value from each source and destination color channel. + """ + DIFFERENCE = "difference" + """ + Subtracts the smaller channel value from the larger one. + + Compositing black has no effect, while compositing white inverts the other image. + """ + DST = "dst" + """ + Drops the source and keeps only the destination. + """ + DST_A_TOP = "dstATop" + """ + Draws the destination over the source, but only where they overlap. + """ + DST_IN = "dstIn" + """ + Keeps the destination only where the source and destination overlap. + + The source acts as an opacity mask. + """ + DST_OUT = "dstOut" + """ + Keeps the destination only where the source and destination do not overlap. + + The source acts as an opacity mask. + """ + DST_OVER = "dstOver" + """ + Draws the source underneath the destination. + """ + EXCLUSION = "exclusion" + """ + Produces an effect similar to :attr:`DIFFERENCE`, but softer. + """ + HARD_LIGHT = "hardLight" + """ + Combines multiply and screen-style blending while favoring the source image. + """ + HUE = "hue" + """ + Takes the hue from the source and the saturation and luminosity from the + destination. + """ + LIGHTEN = "lighten" + """ + Chooses the lighter value from each source and destination color channel. + """ + LUMINOSITY = "luminosity" + """ + Takes the luminosity from the source and the hue and saturation from the + destination. + """ + MODULATE = "modulate" + """ + Multiplies the source and destination color channels without multiplying alpha. + """ + MULTIPLY = "multiply" + """ + Multiplies the source and destination color channels, including alpha. + """ + OVERLAY = "overlay" + """ + Combines multiply and screen-style blending while favoring the destination image. + """ + PLUS = "plus" + """ + Adds the source and destination channel values together. + + This is useful for cross-fading between two images. + """ + SATURATION = "saturation" + """ + Takes the saturation from the source and the hue and luminosity from the + destination. + """ + SCREEN = "screen" + """ + Multiplies the inverted source and destination values, then inverts the result. + + This can only produce the same or lighter colors. + """ + SOFT_LIGHT = "softLight" + """ + Applies a softer lighting effect than :attr:`OVERLAY`. + """ + SRC = "src" + """ + Drops the destination and keeps only the source. + """ + SRC_A_TOP = "srcATop" + """ + Draws the source over the destination, but only where they overlap. + """ + SRC_IN = "srcIn" + """ + Keeps the source only where the source and destination overlap. + + The destination acts as an opacity mask. + """ + SRC_OUT = "srcOut" + """ + Keeps the source only where the source and destination do not overlap. + + The destination acts as an opacity mask. + """ + SRC_OVER = "srcOver" + """ + Draws the source over the destination. + + This is the default painting behavior. + """ + VALUES = "values" + """ + Not a usable blend mode. + + Warning: + This member exists in the Python enum surface but does not map to a runtime + blend mode. Do not use it for painting or image composition. + """ + XOR = "xor" + """ + Uses an exclusive-or composition so overlapping areas become transparent. + """ class TextAlign(Enum): @@ -564,24 +808,51 @@ class PagePlatform(Enum): """ IOS = "ios" + """ + Apple iOS. + """ ANDROID = "android" + """ + Android phones and tablets. + """ ANDROID_TV = "android_tv" + """ + Android TV devices. + """ MACOS = "macos" + """ + Apple macOS. + """ WINDOWS = "windows" + """ + Microsoft Windows. + """ LINUX = "linux" + """ + Linux desktop environments. + """ def is_apple(self) -> bool: - """Whether this PagePlatform instance is an Apple (iOS or macOS) platform.""" + """ + Whether this platform is one of Apple's platforms. + + Returns `True` for :attr:`IOS` and :attr:`MACOS`. + """ return self in {PagePlatform.IOS, PagePlatform.MACOS} def is_mobile(self) -> bool: - """Whether this PagePlatform instance is a mobile (iOS or Android) platform.""" + """ + Whether this platform is a mobile platform. + + Returns `True` for :attr:`IOS` and :attr:`ANDROID`. + """ return self in {PagePlatform.IOS, PagePlatform.ANDROID} def is_desktop(self) -> bool: """ - Whether this PagePlatform instance is a desktop (macOS, Windows, Linux) \ - platform. + Whether this platform is a desktop platform. + + Returns `True` for :attr:`MACOS`, :attr:`WINDOWS`, and :attr:`LINUX`. """ return self in {PagePlatform.MACOS, PagePlatform.WINDOWS, PagePlatform.LINUX} @@ -675,30 +946,161 @@ class DeviceOrientation(Enum): class FloatingActionButtonLocation(Enum): """ Defines a position for the :class:`~flet.FloatingActionButton`. - - See [FloatingActionButtonLocation](https://api.flutter.dev/flutter/material/FloatingActionButtonLocation-class.html) - from Flutter documentation for placement location examples. """ # noqa: E501 CENTER_DOCKED = "centerDocked" + """ + Centered :class:`~flet.FloatingActionButton`, floating over a bottom navigation \ + control so the button's center lines up with the top of that control. + + Not typically useful for apps without a bottom navigation control. + """ + CENTER_FLOAT = "centerFloat" + """ + Centered :class:`~flet.FloatingActionButton`, floating at the bottom of the \ + screen. + + Use :attr:`MINI_CENTER_FLOAT` for mini buttons. + """ + CENTER_TOP = "centerTop" + """ + Centered :class:`~flet.FloatingActionButton`, floating over the transition \ + between the :class:`~flet.AppBar` and the page body. + + Not typically useful for apps without a top :class:`~flet.AppBar`. + """ + END_CONTAINED = "endContained" + """ + End-aligned :class:`~flet.FloatingActionButton`, floating over a bottom \ + navigation control so the button lines up with that control's center. + + Not typically useful for apps with a :class:`~flet.NavigationBar` or a \ + non-Material 3 :class:`~flet.BottomAppBar`. + """ + END_DOCKED = "endDocked" + """ + End-aligned :class:`~flet.FloatingActionButton`, floating over a bottom \ + navigation control so the button's center lines up with the top of that control. + + Not typically useful for apps without a bottom navigation control. + """ + END_FLOAT = "endFloat" + """ + End-aligned :class:`~flet.FloatingActionButton`, floating at the bottom of the \ + screen. + + This is the default alignment in Material apps. Use :attr:`MINI_END_FLOAT` for \ + mini buttons. + """ + END_TOP = "endTop" + """ + End-aligned :class:`~flet.FloatingActionButton`, floating over the transition \ + between the :class:`~flet.AppBar` and the page body. + + Not typically useful for apps without a top :class:`~flet.AppBar`. + """ + MINI_CENTER_DOCKED = "miniCenterDocked" + """ + Centered mini :class:`~flet.FloatingActionButton`, floating over a bottom \ + navigation control so the button's center lines up with the top of that control. + + Intended for use with mini buttons. + """ + MINI_CENTER_FLOAT = "miniCenterFloat" + """ + Centered mini :class:`~flet.FloatingActionButton`, floating at the bottom of the \ + screen. + + Intended for use with mini buttons. + """ + MINI_CENTER_TOP = "miniCenterTop" + """ + Centered mini :class:`~flet.FloatingActionButton`, floating over the transition \ + between the :class:`~flet.AppBar` and the page body. + + Intended for use with mini buttons. + """ + MINI_END_DOCKED = "miniEndDocked" + """ + End-aligned mini :class:`~flet.FloatingActionButton`, floating over a bottom \ + navigation control so the button's center lines up with the top of that control. + + Intended for use with mini buttons. + """ + MINI_END_FLOAT = "miniEndFloat" + """ + End-aligned mini :class:`~flet.FloatingActionButton`, floating at the bottom of \ + the screen. + + Intended for use with mini buttons. + """ + MINI_END_TOP = "miniEndTop" + """ + End-aligned mini :class:`~flet.FloatingActionButton`, floating over the \ + transition between the :class:`~flet.AppBar` and the page body. + + Intended for use with mini buttons. + """ + MINI_START_DOCKED = "miniStartDocked" + """ + Start-aligned mini :class:`~flet.FloatingActionButton`, floating over a bottom \ + navigation control so the button's center lines up with the top of that control. + + Intended for use with mini buttons. + """ + MINI_START_FLOAT = "miniStartFloat" + """ + Start-aligned mini :class:`~flet.FloatingActionButton`, floating at the bottom \ + of the screen. + + Intended for use with mini buttons. + """ + MINI_START_TOP = "miniStartTop" + """ + Start-aligned mini :class:`~flet.FloatingActionButton`, floating over the \ + transition between the :class:`~flet.AppBar` and the page body. + + Intended for use with mini buttons. + """ + START_DOCKED = "startDocked" + """ + Start-aligned :class:`~flet.FloatingActionButton`, floating over a bottom \ + navigation control so the button's center lines up with the top of that control. + + Not typically useful for apps without a bottom navigation control. + """ + START_FLOAT = "startFloat" + """ + Start-aligned :class:`~flet.FloatingActionButton`, floating at the bottom of the \ + screen. + + Use :attr:`MINI_START_FLOAT` for mini buttons. + """ + START_TOP = "startTop" + """ + Start-aligned :class:`~flet.FloatingActionButton`, floating over the transition \ + between the :class:`~flet.AppBar` and the page body. + + Not typically useful for apps without a top :class:`~flet.AppBar`. + """ class AppLifecycleState(Enum): diff --git a/sdk/python/packages/flet/src/flet/data_channel.py b/sdk/python/packages/flet/src/flet/data_channel.py new file mode 100644 index 0000000000..ae3065c12d --- /dev/null +++ b/sdk/python/packages/flet/src/flet/data_channel.py @@ -0,0 +1,153 @@ +"""Widget-facing byte-channel API. + +A `DataChannel` is a dedicated bidirectional byte transport between a +single widget's Dart side and its Python counterpart, separate from the +Flet control protocol. Used for bulk binary data — image frames, audio +buffers, ML tensors — that would otherwise pay MsgPack encode/decode +overhead through the regular protocol channel. + +The transport implementation is chosen by the active Connection subclass: + +- `FletDartBridgeServer` (embedded native via `dart_bridge`): each + channel rides its own dedicated PythonBridge native port (4–7 GiB/s on + M2 Pro). +- `FletSocketServer` / `flet_web.fastapi.FletApp` (dev mode, web with + Python server): bytes are muxed over the active Flet protocol + transport with a 1-byte type discriminator (0x01) + 4-byte channel id. + +Allocation lives on the Dart side. The widget's Dart code calls +`FletBackend.of(context).openDataChannel()` in `initState`, then fires a +`data_channel_open` control event carrying `{channel_name, channel_id}`. +The Python widget declares `on_data_channel_open: +Optional[ft.EventHandler[DataChannelOpenEvent]] = None` and inside the +handler calls `self.get_data_channel(e.channel_id)` to attach. +""" + +from __future__ import annotations + +import contextlib +from abc import ABC, abstractmethod +from dataclasses import dataclass +from typing import TYPE_CHECKING, Callable + +from flet.controls.control_event import Event + +if TYPE_CHECKING: + from flet.messaging.connection import Connection + + +@dataclass +class DataChannelOpenEvent(Event["BaseControl"]): + """Fired by Dart when it opens a DataChannel for a control. Carry the + channel id (Dart native port in embedded mode, monotonic u32 in muxed + fallback) plus a user-defined `channel_name` so widgets that open + several channels can dispatch. + + Note: the field is `channel_name`, not `name`, because `Event.name` + already carries the event's own name (`"data_channel_open"`). + """ + + channel_name: str = "" + channel_id: int = 0 + + +class DataChannel(ABC): + """Abstract widget-facing byte channel.""" + + @abstractmethod + def on_bytes(self, handler: Callable[[bytes], None] | None) -> None: + """Register a handler for bytes pushed from Dart. Pass `None` to + clear. The handler runs synchronously on whatever thread the + transport delivers from — push heavy work to a queue/worker.""" + ... + + @abstractmethod + def send(self, payload: bytes) -> None: + """Send bytes Python → Dart. Fire-and-forget.""" + ... + + @abstractmethod + def close(self) -> None: + """Release the channel. Idempotent.""" + ... + + +class _DartBridgeDataChannel(DataChannel): + """Embedded native mode: bytes flow over a dedicated PythonBridge port. + `channel_id` is the Dart native port number minted on the Dart side. + """ + + def __init__(self, port: int) -> None: + import dart_bridge # type: ignore — built-in module from libdart_bridge + + self._port = port + self._dart_bridge = dart_bridge + self._handler: Callable[[bytes], None] | None = None + self._closed = False + + def on_bytes(self, handler: Callable[[bytes], None] | None) -> None: + self._handler = handler + self._dart_bridge.set_enqueue_handler_func(self._port, handler) + + def send(self, payload: bytes) -> None: + if self._closed: + return + self._dart_bridge.send_bytes(self._port, payload) + + def close(self) -> None: + if self._closed: + return + self._closed = True + if self._handler is not None: + with contextlib.suppress(Exception): + self._dart_bridge.set_enqueue_handler_func(self._port, None) + self._handler = None + + +class _ProtocolMuxedDataChannel(DataChannel): + """Non-embedded modes: bytes ride the Flet protocol transport as + `[0x01][channel_id:u32 LE][payload]` frames. The owning Connection + routes inbound frames here via `_deliver()`. + """ + + def __init__(self, channel_id: int, conn: Connection) -> None: + self._id = channel_id + self._conn = conn + self._handler: Callable[[bytes], None] | None = None + self._closed = False + + def on_bytes(self, handler: Callable[[bytes], None] | None) -> None: + self._handler = handler + + def send(self, payload: bytes) -> None: + if self._closed: + return + # Connection knows the wire format for its transport (length + # prefix on stream transports, none on message transports). + self._conn.send_data_channel_frame(self._id, payload) + + def _deliver(self, payload: bytes) -> None: + if self._closed: + return + handler = self._handler + if handler is not None: + try: + handler(payload) + except Exception: + import logging + + logging.getLogger("flet").exception( + "DataChannel handler raised; channel id=%s", self._id + ) + + def close(self) -> None: + if self._closed: + return + self._closed = True + # Connection's unregister is best-effort — duplicate unregisters + # are safe. + unreg = getattr(self._conn, "unregister_data_channel", None) + if unreg is not None: + with contextlib.suppress(Exception): + unreg(self._id) + self._handler = None diff --git a/sdk/python/packages/flet/src/flet/messaging/connection.py b/sdk/python/packages/flet/src/flet/messaging/connection.py index aa80edd72d..7ccbae4b7c 100644 --- a/sdk/python/packages/flet/src/flet/messaging/connection.py +++ b/sdk/python/packages/flet/src/flet/messaging/connection.py @@ -21,6 +21,11 @@ class Connection: def __init__(self): self.page_name: str = "" self.page_url: Optional[str] = None + # True when the connected client runs on the same machine (or in the + # same process), so DataChannel bytes move at local-IPC / memcpy + # speed. Widgets may use this to prefer uncompressed payloads over + # encoded ones. + self.local_data_transport: bool = False self.__pubsubhub = None self.__loop: Optional[AbstractEventLoop] = None self.__executor: Optional[ThreadPoolExecutor] = None @@ -120,3 +125,39 @@ def dispose(self): Subclasses can override this method to clean up transport-specific state. """ pass + + # ------------------------------------------------------------------ + # DataChannel transport hooks. Subclasses implement these for the + # transports that carry widget byte channels: dart_bridge mode (each + # channel = a dedicated PythonBridge port), socket / WebSocket modes + # (channel frames muxed over the same protocol transport). + # ------------------------------------------------------------------ + + def data_channel_for(self, channel_id: int): + """Return the `DataChannel` for `channel_id` allocated on the Dart + side. Idempotent — subsequent calls with the same id return the + same instance within the session. + + Called by `Control.get_data_channel(id)` after a `data_channel_open` + event arrives. + """ + raise NotImplementedError( + f"{type(self).__name__} does not support DataChannel " + "(transport-specific implementation missing)." + ) + + def send_data_channel_frame(self, channel_id: int, payload: bytes) -> None: + """Send a raw DataChannel frame for `channel_id`. Used by the + protocol-muxed implementation only — dart_bridge channels go + through their own dedicated `dart_bridge.send_bytes(port, ...)` + call instead. + """ + raise NotImplementedError( + f"{type(self).__name__} does not implement send_data_channel_frame." + ) + + def unregister_data_channel(self, channel_id: int) -> None: + """Best-effort drop of `channel_id` from the mux registry. Default + is a no-op so subclasses that don't keep one don't need to override. + """ + pass diff --git a/sdk/python/packages/flet/src/flet/messaging/flet_dart_bridge_server.py b/sdk/python/packages/flet/src/flet/messaging/flet_dart_bridge_server.py new file mode 100644 index 0000000000..a232a06efe --- /dev/null +++ b/sdk/python/packages/flet/src/flet/messaging/flet_dart_bridge_server.py @@ -0,0 +1,293 @@ +""" +In-process dart_bridge transport for Flet's embedded mode. + +`FletDartBridgeServer` is an alternative to `FletSocketServer` that exchanges +the same MsgPack-framed protocol over an in-process byte channel rather than a +Unix-domain socket. The channel is provided by the `dart_bridge` built-in +Python module, registered with CPython via `PyImport_AppendInittab` by +`libdart_bridge` (the native artifact in `flet-dev/dart-bridge`). + +Activation: `flet.app.run_async` instantiates this server when +`FLET_DART_BRIDGE_PORT` is set AND `is_embedded()` is true. The Dart-side port +acts as the channel key in both directions: + +- inbound (Dart → Python): dart_bridge invokes `__on_bytes(payload)` from C + under the GIL whenever the Dart side calls `bridge.send(bytes)`. +- outbound (Python → Dart): `send_message` calls `dart_bridge.send_bytes( + port, packed)` which non-blockingly posts to the Dart native port. + +The MsgPack protocol layer is identical to `FletSocketServer`; only the byte +transport differs. +""" + +import asyncio +import contextlib +import inspect +import logging +import traceback +from collections.abc import Awaitable +from concurrent.futures import ThreadPoolExecutor +from typing import TYPE_CHECKING, Any, Callable, Optional + +import dart_bridge # type: ignore # provided by libdart_bridge inittab +import msgpack + +from flet.controls.base_control import BaseControl +from flet.messaging.connection import Connection +from flet.messaging.protocol import ( + ClientAction, + ClientMessage, + ControlEventBody, + InvokeMethodResponseBody, + RegisterClientRequestBody, + RegisterClientResponseBody, + UpdateControlPropsBody, + configure_encode_object_for_msgpack, + decode_ext_from_msgpack, +) +from flet.messaging.session import Session +from flet.pubsub.pubsub_hub import PubSubHub + +if TYPE_CHECKING: + from flet.app import AppCallable + +logger = logging.getLogger("flet") +transport_log = logging.getLogger("flet_transport") + + +class FletDartBridgeServer(Connection): + """ + Connection transport that uses the `dart_bridge` built-in module instead + of an asyncio Unix-domain socket. See module docstring for the rationale. + + Lifecycle: `start()` registers a byte handler with `dart_bridge`; bytes + arrive synchronously on whatever OS thread Dart called `bridge.send` from, + so the handler is just a thread-safe enqueue onto an asyncio.Queue that an + inbound coroutine drains on the event loop. + """ + + def __init__( + self, + loop: asyncio.AbstractEventLoop, + port: int, + on_session_created: Optional[Callable[[Session], Awaitable[Any]]] = None, + before_main: Optional["AppCallable"] = None, + executor: Optional[ThreadPoolExecutor] = None, + ): + super().__init__() + self.__port = port + self.__on_session_created = on_session_created + self.__before_main = before_main + self.session: Optional[Session] = None + self.__inbound_queue: asyncio.Queue[bytes] = asyncio.Queue() + self.__inbound_task: Optional[asyncio.Task] = None + self.__running_tasks: set[asyncio.Task] = set() + # In-process transport — DataChannel bytes move at memcpy speed. + self.local_data_transport = True + self.loop = loop + self.executor = executor + self.pubsubhub = PubSubHub(loop=loop, executor=executor) + self.page_url = f"dartbridge://{port}" + + async def start(self): + """ + Registers the inbound byte handler with `dart_bridge` and schedules + the inbound dispatch coroutine. Returns immediately — there is no + per-client handshake at the transport level (the first + REGISTER_CLIENT frame from Dart is the application-level handshake). + """ + logger.info("Starting up dart_bridge server on port %s", self.__port) + dart_bridge.set_enqueue_handler_func(self.__port, self.__on_bytes) + self.__inbound_task = asyncio.create_task(self.__inbound_loop()) + + def __on_bytes(self, payload: bytes) -> None: + """ + Receives a byte frame from `dart_bridge`. Called synchronously under + the GIL from C — may run on a non-loop thread, so we marshal onto + the loop via `call_soon_threadsafe`. + """ + self.loop.call_soon_threadsafe(self.__inbound_queue.put_nowait, payload) + + async def __inbound_loop(self): + """ + Drains the inbound queue and dispatches each packet. Each dart_bridge + send delivers one complete packet — `[type:u8][payload]`. type=0x00 + is a MsgPack-encoded Flet control frame, decoded and dispatched as + a protocol message; type=0x01 is a raw DataChannel frame, but on + the dart_bridge transport that *only* carries the Flet protocol — + DataChannels in embedded mode get their own dedicated PythonBridge, + so a 0x01 here would be an error and we log+drop. + """ + try: + while True: + packet = await self.__inbound_queue.get() + if not packet: + continue + ptype = packet[0] + if ptype == 0x00: + try: + msg = msgpack.unpackb( + packet[1:], ext_hook=decode_ext_from_msgpack + ) + await self.__on_message(msg) + except Exception: + logger.error( + "Error dispatching dart_bridge frame", exc_info=True + ) + elif ptype == 0x01: + logger.debug( + "dart_bridge channel received a 0x01 data frame; " + "DataChannels in embedded mode should use a dedicated " + "PythonBridge, not the protocol channel." + ) + else: + logger.debug( + "dart_bridge channel received packet with unknown type 0x%02x", + ptype, + ) + except asyncio.CancelledError: + logger.debug("dart_bridge inbound loop cancelled.") + + async def __on_message(self, data: Any): + """ + Protocol dispatch — identical to `FletSocketServer.__on_message`. + Duplicated here to keep the two transports decoupled; refactor into + a shared base once both have stabilised. + """ + action = ClientAction(data[0]) + body = data[1] + transport_log.debug("_on_message: %s %s", action, body) + task = None + if action == ClientAction.REGISTER_CLIENT: + req = RegisterClientRequestBody(**body) + + # create new session + self.session = Session(self) + + # apply page patch + if not req.session_id: + self.session.apply_page_patch(req.page) + + register_error = "" + try: + if inspect.iscoroutinefunction(self.__before_main): + await self.__before_main(self.session.page) + elif callable(self.__before_main): + self.__before_main(self.session.page) + except Exception as e: + register_error = f"{e}\n{traceback.format_exc()}" + logger.error("Unhandled error in before_main() handler", exc_info=True) + + # register response + self.send_message( + ClientMessage( + ClientAction.REGISTER_CLIENT, + RegisterClientResponseBody( + session_id=self.session.id, + page_patch=self.session.get_page_patch(), + error=register_error, + ), + ) + ) + + if register_error: + self.session.error(register_error) + elif self.__on_session_created is not None: + task = asyncio.create_task(self.__on_session_created(self.session)) + + elif action == ClientAction.CONTROL_EVENT: + req = ControlEventBody(**body) + task = asyncio.create_task( + self.session.dispatch_event(req.target, req.name, req.data) + ) + + elif action == ClientAction.UPDATE_CONTROL_PROPS: + req = UpdateControlPropsBody(**body) + self.session.apply_patch(req.id, req.props) + + elif action == ClientAction.INVOKE_METHOD: + req = InvokeMethodResponseBody(**body) + self.session.handle_invoke_method_results( + req.control_id, req.call_id, req.result, req.error + ) + + else: + raise RuntimeError(f'Unknown message "{action}": {body}') + + if task: + self.__running_tasks.add(task) + task.add_done_callback(self.__running_tasks.discard) + + def send_message(self, message: ClientMessage): + """ + Encodes a protocol message and posts it to the Dart side via + `dart_bridge.send_bytes`. Non-blocking; ordering is preserved by the + Dart VM's port queue. Wire format: `[0x00][msgpack body]` — no + length prefix (the bridge preserves message boundaries). + """ + transport_log.debug("send_message: %s", message) + body = msgpack.packb( + [message.action, message.body], + default=configure_encode_object_for_msgpack(BaseControl), + ) + packet = b"\x00" + body + try: + dart_bridge.send_bytes(self.__port, packet) + except Exception: + logger.error("dart_bridge.send_bytes failed", exc_info=True) + + def data_channel_for(self, channel_id: int): + """Resolve the DataChannel for `channel_id`. In embedded native mode + each DataChannel rides its own dedicated PythonBridge native port + (the `channel_id` *is* the port). Idempotent. + """ + from flet.data_channel import _DartBridgeDataChannel + + # No registry needed: _DartBridgeDataChannel is stateless wrt port + # and the dart_bridge module routes by port number internally. We + # still cache per port to avoid duplicate handler registrations. + if not hasattr(self, "_data_channels"): + self._data_channels: dict[int, Any] = {} + existing = self._data_channels.get(channel_id) + if existing is not None: + return existing + channel = _DartBridgeDataChannel(channel_id) + self._data_channels[channel_id] = channel + return channel + + async def close(self): + """ + Releases the dart_bridge handler registration and cancels pending + inbound work. Mirrors `FletSocketServer.close()` so the caller side + in `flet.app.run_async` can treat both transports uniformly. + """ + logger.debug("Closing dart_bridge server...") + try: + dart_bridge.set_enqueue_handler_func(self.__port, None) + except Exception: + logger.debug("Error unregistering dart_bridge handler", exc_info=True) + + session = self.session + self.session = None + if session is not None: + try: + session.close() + except Exception: + logger.debug("Error closing session", exc_info=True) + + if self.__inbound_task and not self.__inbound_task.done(): + self.__inbound_task.cancel() + with contextlib.suppress(asyncio.CancelledError, Exception): + await self.__inbound_task + + for task in list(self.__running_tasks): + if not task.done(): + task.cancel() + if self.__running_tasks: + await asyncio.gather(*self.__running_tasks, return_exceptions=True) + self.__running_tasks.clear() + + if self.executor: + self.executor.shutdown(wait=False, cancel_futures=True) + + logger.debug("dart_bridge server closed.") diff --git a/sdk/python/packages/flet/src/flet/messaging/flet_socket_server.py b/sdk/python/packages/flet/src/flet/messaging/flet_socket_server.py index 73596cb4bc..ee7935034f 100644 --- a/sdk/python/packages/flet/src/flet/messaging/flet_socket_server.py +++ b/sdk/python/packages/flet/src/flet/messaging/flet_socket_server.py @@ -71,6 +71,12 @@ def __init__( self.__before_main = before_main self.__blocking = blocking self.__running_tasks = set() + # DataChannel mux registry. Keyed by channel_id minted on the Dart + # side; populated lazily on the first Control.get_data_channel(id) + # call. Frames for unknown ids are silently dropped. + self._data_channels: dict[int, Any] = {} + # UDS or localhost TCP only — always same-machine. + self.local_data_transport = True self.loop = loop self.executor = executor self.pubsubhub = PubSubHub(loop=loop, executor=executor) @@ -244,7 +250,12 @@ async def __terminate_active_connection_locked(self, reason: str) -> None: async def __receive_loop(self, reader: asyncio.StreamReader, connection_token: int): """ - Reads and dispatches inbound MsgPack frames from the socket. + Reads and dispatches inbound packets from the socket. + + Wire format on the byte stream: each packet is prefixed with a 4-byte + little-endian length, then `[type:u8][payload]`. type=0x00 is a + MsgPack-encoded Flet protocol frame; type=0x01 is a raw DataChannel + frame (`[channel_id:u32 LE][bytes]`). The loop exits when: - socket EOF is reached; @@ -255,17 +266,34 @@ async def __receive_loop(self, reader: asyncio.StreamReader, connection_token: i reader: Socket stream reader to consume bytes from. connection_token: Token identifying the connection generation. """ - unpacker = msgpack.Unpacker(ext_hook=decode_ext_from_msgpack) try: while True: - buf = await reader.read(1024 * 1024) - if not buf: + try: + header = await reader.readexactly(4) + except asyncio.IncompleteReadError: + break # EOF mid-stream or clean close + length = int.from_bytes(header, "little", signed=False) + if length == 0: + continue + try: + packet = await reader.readexactly(length) + except asyncio.IncompleteReadError: + logger.debug("Truncated packet read; aborting receive loop.") break - unpacker.feed(buf) - for msg in unpacker: - if self.__connection_token != connection_token: - return + if self.__connection_token != connection_token: + return + ptype = packet[0] + if ptype == 0x00: + msg = msgpack.unpackb(packet[1:], ext_hook=decode_ext_from_msgpack) await self.__on_message(msg) + elif ptype == 0x01: + if len(packet) < 5: + logger.debug("Dropping malformed data-channel frame.") + continue + channel_id = int.from_bytes(packet[1:5], "little", signed=False) + self.__on_data_channel_frame(channel_id, packet[5:]) + else: + logger.debug("Dropping packet with unknown type 0x%02x", ptype) except asyncio.CancelledError: logger.debug("Receive loop cancelled.") except Exception as e: @@ -273,6 +301,14 @@ async def __receive_loop(self, reader: asyncio.StreamReader, connection_token: i finally: logger.debug("Receive loop exiting.") + def __on_data_channel_frame(self, channel_id: int, payload: bytes) -> None: + """Routes an inbound `[0x01][channel_id][payload]` frame to its + registered DataChannel. Silently drops frames for unknown ids + (handles unmount races).""" + channel = self._data_channels.get(channel_id) + if channel is not None: + channel._deliver(payload) + async def __send_loop( self, writer: asyncio.StreamWriter, @@ -390,18 +426,56 @@ def send_message(self, message: ClientMessage): """ Encodes and queues an outbound message for the active connection. + Wire format: `[length:u32 LE][0x00][msgpack body]`. The send loop + writes the bytes verbatim to the socket. + If no active send queue exists (no connected client), the message is dropped. Args: message: Protocol message to send. """ transport_log.debug("send_message: %s", message) - m = msgpack.packb( + body = msgpack.packb( [message.action, message.body], default=configure_encode_object_for_msgpack(BaseControl), ) + packet = b"\x00" + body + framed = len(packet).to_bytes(4, "little", signed=False) + packet + if self.__send_queue is not None: + self.__send_queue.put_nowait(framed) + + def send_data_channel_frame(self, channel_id: int, payload: bytes) -> None: + """Send a raw DataChannel frame `[length][0x01][channel_id:u32 LE][bytes]`. + Called by `_ProtocolMuxedDataChannel.send` on the Python side.""" + # Single-copy assembly — sequential concats would copy the + # (potentially multi-MB) payload twice. + framed = b"".join( + [ + (5 + len(payload)).to_bytes(4, "little", signed=False), + b"\x01", + channel_id.to_bytes(4, "little", signed=False), + payload, + ] + ) if self.__send_queue is not None: - self.__send_queue.put_nowait(m) + self.__send_queue.put_nowait(framed) + + def data_channel_for(self, channel_id: int): + """Resolve or construct the muxed DataChannel for `channel_id`. + Idempotent — returns the same instance per id within the session. + Called from `Control.get_data_channel(id)`. + """ + from flet.data_channel import _ProtocolMuxedDataChannel + + existing = self._data_channels.get(channel_id) + if existing is not None: + return existing + channel = _ProtocolMuxedDataChannel(channel_id, self) + self._data_channels[channel_id] = channel + return channel + + def unregister_data_channel(self, channel_id: int) -> None: + self._data_channels.pop(channel_id, None) async def close(self): """ diff --git a/sdk/python/packages/flet/src/flet/messaging/pyodide_connection.py b/sdk/python/packages/flet/src/flet/messaging/pyodide_connection.py index ee51c4f589..5de5bfa55b 100644 --- a/sdk/python/packages/flet/src/flet/messaging/pyodide_connection.py +++ b/sdk/python/packages/flet/src/flet/messaging/pyodide_connection.py @@ -50,6 +50,12 @@ def __init__( self.__before_main = before_main flet_js.start_connection = self.connect self.__running_tasks = set() + # DataChannel mux registry. Pyodide mode has no dart_bridge, so + # DataChannels ride the same postMessage transport as the Flet + # protocol — disambiguated by the wire-format type byte. + self._data_channels: dict[int, Any] = {} + # postMessage inside the browser — same-machine, memcpy-class. + self.local_data_transport = True self.pubsubhub = PubSubHub() self.loop = asyncio.get_running_loop() @@ -69,15 +75,32 @@ async def connect(self, send_callback): async def receive_loop(self): """ - Continuously receives, decodes, and dispatches inbound client messages. + Continuously receives, decodes, and dispatches inbound packets. - This loop waits for raw messages queued by `send_from_js()`, decodes MsgPack - payloads, and forwards parsed protocol frames to `__on_message()`. + Wire format on the postMessage transport: each packet from Dart is + `[type:u8][payload]`. type=0x00 is a MsgPack-encoded Flet protocol + frame; type=0x01 is a raw DataChannel frame + (`[channel_id:u32 LE][bytes]`). """ while True: data = await self.__receive_queue.get() - message = msgpack.unpackb(data.to_py(), ext_hook=decode_ext_from_msgpack) - await self.__on_message(message) + packet = bytes(data.to_py()) + if not packet: + continue + ptype = packet[0] + if ptype == 0x00: + message = msgpack.unpackb(packet[1:], ext_hook=decode_ext_from_msgpack) + await self.__on_message(message) + elif ptype == 0x01: + if len(packet) < 5: + logger.debug("Dropping malformed data-channel frame.") + continue + channel_id = int.from_bytes(packet[1:5], "little", signed=False) + channel = self._data_channels.get(channel_id) + if channel is not None: + channel._deliver(packet[5:]) + else: + logger.debug("Dropping packet with unknown type 0x%02x", ptype) def send_from_js(self, message: Any): """ @@ -173,12 +196,37 @@ def send_message(self, message: ClientMessage): """ Serializes and sends an outbound protocol message to JavaScript. + Wire format: `[0x00][msgpack body]`. postMessage preserves message + boundaries, so no length prefix. + Args: message: Client message to serialize with MsgPack and send. """ transport_log.debug("send_message: %s", message) - m = msgpack.packb( + body = msgpack.packb( [message.action, message.body], default=configure_encode_object_for_msgpack(BaseControl), ) - self.send_callback(m) + self.send_callback(b"\x00" + body) + + def send_data_channel_frame(self, channel_id: int, payload: bytes) -> None: + """Send a raw DataChannel frame `[0x01][channel_id:u32 LE][bytes]` + over postMessage. Called by `_ProtocolMuxedDataChannel.send`.""" + header = b"\x01" + channel_id.to_bytes(4, "little", signed=False) + self.send_callback(header + payload) + + def data_channel_for(self, channel_id: int): + """Resolve or construct the muxed DataChannel for `channel_id`. + Idempotent — same id returns the same instance within the session. + """ + from flet.data_channel import _ProtocolMuxedDataChannel + + existing = self._data_channels.get(channel_id) + if existing is not None: + return existing + channel = _ProtocolMuxedDataChannel(channel_id, self) + self._data_channels[channel_id] = channel + return channel + + def unregister_data_channel(self, channel_id: int) -> None: + self._data_channels.pop(channel_id, None) diff --git a/sdk/python/packages/flet/src/flet/messaging/session.py b/sdk/python/packages/flet/src/flet/messaging/session.py index 460e800431..5674acbfbc 100644 --- a/sdk/python/packages/flet/src/flet/messaging/session.py +++ b/sdk/python/packages/flet/src/flet/messaging/session.py @@ -5,9 +5,8 @@ import traceback import weakref from datetime import datetime, timedelta, timezone -from typing import Any, Optional +from typing import TYPE_CHECKING, Any, Optional -from flet.components.hooks.use_effect import EffectHook from flet.controls.base_control import BaseControl from flet.controls.context import _context_page, context from flet.controls.object_patch import ObjectPatch @@ -25,6 +24,11 @@ from flet.utils.object_model import patch_dataclass from flet.utils.strings import random_string +if TYPE_CHECKING: + # Annotation-only (quoted at use site): deferred so a Session doesn't eagerly + # pull the components/hooks subsystem (cold-start import cost). + from flet.components.hooks.use_effect import EffectHook + logger = logging.getLogger("flet") patch_logger = logging.getLogger("flet_object_patch") @@ -243,8 +247,9 @@ def patch_control( for c in removed_controls: patch_logger.debug(" %s", c) + added_ids = {added_control._i for added_control in added_controls} for removed_control in removed_controls: - if not any(added._i == removed_control._i for added in added_controls): + if removed_control._i not in added_ids: removed_control.will_unmount() self.__index.pop(removed_control._i, None) @@ -260,9 +265,10 @@ def patch_control( for ac in added_controls: patch_logger.debug(" %s", ac) + removed_ids = {removed_control._i for removed_control in removed_controls} for added_control in added_controls: self.__index[added_control._i] = added_control - if not any(removed._i == added_control._i for removed in removed_controls): + if added_control._i not in removed_ids: added_control.did_mount() def apply_patch(self, control_id: int, patch: dict[str, Any]): @@ -631,7 +637,7 @@ def schedule_update(self, control: BaseControl): self.__pending_updates.add(control) self.__updates_ready.set() - def schedule_effect(self, hook: EffectHook, is_cleanup: bool): + def schedule_effect(self, hook: "EffectHook", is_cleanup: bool): """ Queues an effect hook setup/cleanup operation for scheduler execution. diff --git a/sdk/python/packages/flet/src/flet/pubsub/pubsub_client.py b/sdk/python/packages/flet/src/flet/pubsub/pubsub_client.py index bca036655e..60f8e839dc 100644 --- a/sdk/python/packages/flet/src/flet/pubsub/pubsub_client.py +++ b/sdk/python/packages/flet/src/flet/pubsub/pubsub_client.py @@ -57,7 +57,7 @@ def send_others_on_topic(self, topic: str, message: Any): """ self.__pubsub.send_others_on_topic(self.__session_id, topic, message) - def subscribe(self, handler: Callable): + def subscribe(self, handler: Callable[[Any], Any]): """ Subscribes this session to global messages. @@ -68,7 +68,7 @@ def subscribe(self, handler: Callable): """ self.__pubsub.subscribe(self.__session_id, handler) - def subscribe_topic(self, topic: str, handler: Callable): + def subscribe_topic(self, topic: str, handler: Callable[[str, Any], Any]): """ Subscribes this session to a topic. diff --git a/sdk/python/packages/flet/src/flet/pytest_plugin.py b/sdk/python/packages/flet/src/flet/pytest_plugin.py new file mode 100644 index 0000000000..9ef8afa2b5 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/pytest_plugin.py @@ -0,0 +1,147 @@ +""" +Pytest plugin that exposes Flet integration-testing fixtures. + +Registered as a ``pytest11`` entry point in flet's ``pyproject.toml`` so that any +test under a Flet app's ``tests/`` directory gets the ``flet_app`` / +``flet_app_function`` fixtures with zero conftest boilerplate. + +Because a ``pytest11`` plugin is auto-loaded in *every* pytest run wherever +``flet`` is installed, this module must stay lightweight: it lives at the flet +top level (not under ``flet.testing``) so loading it does not pull in +``FletTestApp`` (numpy/Pillow/scikit-image). It imports nothing heavy at module +load time — ``flet.testing`` and ``flet_cli`` are imported lazily inside the +fixtures. ``pytest_asyncio`` is imported defensively — if it is missing, the +plugin loads as a no-op so it never breaks unrelated projects' pytest runs. +""" + +import os +from pathlib import Path + +try: + import pytest_asyncio + + _HAS_ASYNCIO = True +except ImportError: # pragma: no cover - plugin degrades to a no-op + _HAS_ASYNCIO = False + + +def _is_device_mode() -> bool: + # Device mode (app under test runs on-device with embedded Python) is the + # default for `flet test` / `uv run pytest`. The Flet repo's own host-mode + # tests opt out by setting FLET_TEST_DEVICE_MODE=0 (and override these + # fixtures from their conftest anyway). + return os.environ.get("FLET_TEST_DEVICE_MODE", "1").lower() not in ( + "0", + "false", + "no", + "", + ) + + +def _import_app_main(app_path: str, module_name: str): + """Import the user's app `main` callable from `app_path/.py`.""" + import importlib + import sys + + app_path = str(Path(app_path).resolve()) + if app_path not in sys.path: + sys.path.insert(0, app_path) + module = importlib.import_module(module_name) + return module.main + + +def _resolve_flutter_test_host(device_mode: bool): + """Return the Flutter test host dir, provisioning it on demand if needed.""" + host = os.environ.get("FLET_TEST_FLUTTER_APP_DIR") + if host: + return host + if not device_mode: + raise RuntimeError( + "FLET_TEST_FLUTTER_APP_DIR is not set. Run tests with `flet test`, " + "or set the environment variable to a Flutter test host directory." + ) + # Lazily provision a built test host via flet-cli (cached by input hash). + # The target platform/device come from FLET_TEST_PLATFORM / FLET_TEST_DEVICE + # so `uv run pytest` can target a mobile emulator/device too (defaults to the + # current desktop platform when unset). + try: + from flet_cli.commands.test_host import provision_test_host + except ImportError as e: + raise RuntimeError( + "Provisioning a Flutter test host requires flet-cli. Install it " + "with `pip install flet-cli` or run your tests with `flet test`." + ) from e + return str( + provision_test_host( + project_dir=os.getcwd(), + platform_name=os.environ.get("FLET_TEST_PLATFORM"), + device_id=os.environ.get("FLET_TEST_DEVICE"), + ) + ) + + +def _create_flet_app(request): + import flet.testing as ftt + + params = getattr(request, "param", {}) + device_mode = _is_device_mode() + flutter_app_dir = _resolve_flutter_test_host(device_mode) + + flet_app_main = params.get("flet_app_main") + if not device_mode and flet_app_main is None: + app_path = os.environ.get("FLET_TEST_APP_PATH") + if app_path: + module_name = os.environ.get("FLET_TEST_APP_MODULE", "main") + flet_app_main = _import_app_main(app_path, module_name) + + assets_dir = params.get("assets_dir") or os.environ.get("FLET_TEST_ASSETS_DIR") + + return ftt.FletTestApp( + flutter_app_dir=flutter_app_dir, + device_mode=device_mode, + flet_app_main=flet_app_main, + test_path=request.fspath, + skip_pump_and_settle=params.get("skip_pump_and_settle", False), + assets_dir=assets_dir, + ) + + +if _HAS_ASYNCIO: + + @pytest_asyncio.fixture + async def flet_app(request): + """ + Function-scoped Flet app fixture: each test gets a fresh, isolated app. + + Does not bind `ft.context.page`. Use `flet_app.tester` to drive the UI. + Function scope keeps the fixture on the same event loop as the test (the + default with `asyncio_mode = "auto"`), which is required so the tester + transport is serviced while the test awaits. + """ + app = _create_flet_app(request) + await app.start() + yield app + await app.teardown() + + @pytest_asyncio.fixture(scope="function") + async def flet_app_function(request): + """ + Function-scoped Flet app fixture. + + Binds and resets `ft.context.page` per test (host mode). In device mode + the bound page is the tester session, not the on-device app page. + """ + from flet.controls.context import _context_page, context + + app = _create_flet_app(request) + await app.start() + + token = _context_page.set(app.page) + context.reset_auto_update() + + try: + yield app + finally: + _context_page.reset(token) + context.disable_components_mode() + await app.teardown() diff --git a/sdk/python/packages/flet/src/flet/testing/flet_test_app.py b/sdk/python/packages/flet/src/flet/testing/flet_test_app.py index 8777d98855..593efadf0f 100644 --- a/sdk/python/packages/flet/src/flet/testing/flet_test_app.py +++ b/sdk/python/packages/flet/src/flet/testing/flet_test_app.py @@ -16,6 +16,7 @@ import flet as ft from flet.controls.control import Control +from flet.testing.remote_tester import RemoteTester from flet.testing.tester import Tester from flet.utils.network import get_free_tcp_port from flet.utils.platform_utils import get_bool_env_var @@ -114,6 +115,14 @@ class FletTestApp: skip_pump_and_settle: If `True`, the initial `pump_and_settle` after app start is skipped. + device_mode: + If `True`, the app under test runs on-device with embedded Python + (over dart_bridge), as produced by `flet build`. This session then + hosts only the `Tester` over a dedicated channel and does not run + `flet_app_main`. If `False` (default), the app runs here in-process + (host mode) against the dev `client` shell. + Env override: `FLET_TEST_DEVICE_MODE=1`. + Environment Variables: - `FLET_TEST_PLATFORM`: Overrides `test_platform`. - `FLET_TEST_DEVICE`: Overrides `test_device`. @@ -140,6 +149,7 @@ def __init__( use_http: bool = False, disable_fvm: bool = False, skip_pump_and_settle: bool = False, + device_mode: bool = False, ): self.test_platform = os.getenv("FLET_TEST_PLATFORM", test_platform) self.test_device = os.getenv("FLET_TEST_DEVICE", test_device) @@ -157,6 +167,7 @@ def __init__( ) self.__disable_fvm = get_bool_env_var("FLET_TEST_DISABLE_FVM") or disable_fvm self.__use_http = get_bool_env_var("FLET_TEST_USE_HTTP") or use_http + self.__device_mode = get_bool_env_var("FLET_TEST_DEVICE_MODE") or device_mode self.__test_path = test_path self.__flet_app_main = flet_app_main self.__skip_pump_and_settle = skip_pump_and_settle @@ -164,8 +175,10 @@ def __init__( self.__assets_dir = assets_dir or "assets" self.__tcp_port = tcp_port self.__flutter_process: Optional[asyncio.subprocess.Process] = None + self.__flutter_output = bytearray() + self.__flutter_output_task: Optional[asyncio.Task] = None self.__page = None - self.__tester: Tester | None = None + self.__tester: Union[Tester, RemoteTester, None] = None @property def page(self) -> ft.Page: @@ -177,10 +190,11 @@ def page(self) -> ft.Page: return self.__page @property - def tester(self) -> Tester: + def tester(self) -> Union[Tester, RemoteTester]: """ - Returns an instance of `Tester` class that programmatically \ - interacts with page controls and the test environment. + Returns the tester that programmatically interacts with page controls \ + and the test environment. In device mode this is a `RemoteTester` \ + driving the app over a socket. """ if self.__tester is None: raise RuntimeError("tester is not initialized") @@ -205,10 +219,14 @@ async def main(page: ft.Page): page.theme_mode = ft.ThemeMode.LIGHT page.update() - if inspect.iscoroutinefunction(self.__flet_app_main): - await self.__flet_app_main(page) - elif callable(self.__flet_app_main): - self.__flet_app_main(page) + # In device mode the app under test runs on-device (embedded Python + # over dart_bridge); this session is tester-only and must NOT run + # the user's app. In host mode the app runs here in-process. + if not self.__device_mode: + if inspect.iscoroutinefunction(self.__flet_app_main): + await self.__flet_app_main(page) + elif callable(self.__flet_app_main): + self.__flet_app_main(page) if not self.__skip_pump_and_settle: await self.__pump_and_settle_with_timeout("start") ready.set() @@ -216,23 +234,43 @@ async def main(page: ft.Page): if not self.__tcp_port: self.__tcp_port = get_free_tcp_port() - if self.__use_http: - os.environ["FLET_FORCE_WEB_SERVER"] = "true" - - asyncio.create_task( - ft.run_async( - main, port=self.__tcp_port, assets_dir=str(self.__assets_dir), view=None + if self.__device_mode: + # Device mode: the app runs on-device (embedded Python over + # dart_bridge). This process only hosts the independent RemoteTester + # socket that drives the on-device WidgetTester — no Flet server, + # no app run here. + remote = RemoteTester() + self.__tcp_port = await remote.start(host="127.0.0.1", port=self.__tcp_port) + self.__tester = remote + print(f"Started remote tester on 127.0.0.1:{self.__tcp_port}") + else: + if self.__use_http: + os.environ["FLET_FORCE_WEB_SERVER"] = "true" + + asyncio.create_task( + ft.run_async( + main, + port=self.__tcp_port, + assets_dir=str(self.__assets_dir), + view=None, + ) ) + print("Started Flet app") + + # Stream the Flutter test process output to the console when verbose + # (set by `flet test -v`) or when debug logging is on; otherwise + # capture it into a buffer so it can be dumped if the process fails. + verbose = ( + get_bool_env_var("FLET_TEST_VERBOSE") + or logging.getLogger().getEffectiveLevel() == logging.DEBUG ) - print("Started Flet app") + stdout = None if verbose else asyncio.subprocess.PIPE + stderr = None if verbose else asyncio.subprocess.STDOUT - stdout = asyncio.subprocess.DEVNULL - stderr = asyncio.subprocess.DEVNULL - if logging.getLogger().getEffectiveLevel() == logging.DEBUG: - stdout = None - stderr = None - - flutter_args = ["fvm", "flutter", "test", "integration_test"] + # The resolved Flutter executable (full path, `flutter.bat` on Windows) + # is passed by `flet test`; fall back to a bare "flutter" on PATH. + flutter_exe = os.getenv("FLET_TEST_FLUTTER_EXE", "flutter") + flutter_args = ["fvm", flutter_exe, "test", self.__flutter_test_target()] if self.__disable_fvm: flutter_args.pop(0) @@ -254,15 +292,27 @@ async def main(page: ft.Page): flutter_args += ["-d", self.test_device] app_url = f"{protocol}://{tcp_addr}:{self.__tcp_port}" - flutter_args += [f"--dart-define=FLET_TEST_APP_URL={app_url}"] - if not self.__use_http: - temp_path = Path(tempfile.gettempdir()) / "flet_app_pid.txt" - flutter_args += [f"--dart-define=FLET_TEST_PID_FILE_PATH={temp_path}"] - if self.__assets_dir: - flutter_args += [ - f"--dart-define=FLET_TEST_ASSETS_DIR={self.__assets_dir}" - ] + if self.__device_mode: + # The app under test runs on-device over dart_bridge and ships its + # own assets in app.zip. The RemoteWidgetTester connects to our + # RemoteTester server over an independent socket. FLET_TEST=true lets + # the embedded app know it is running under test (page.test == True). + server_url = f"tcp://{tcp_addr}:{self.__tcp_port}" + flutter_args += [ + f"--dart-define=FLET_TEST_SERVER_URL={server_url}", + "--dart-define=FLET_TEST=true", + ] + else: + flutter_args += [f"--dart-define=FLET_TEST_APP_URL={app_url}"] + + if not self.__use_http: + temp_path = Path(tempfile.gettempdir()) / "flet_app_pid.txt" + flutter_args += [f"--dart-define=FLET_TEST_PID_FILE_PATH={temp_path}"] + if self.__assets_dir: + flutter_args += [ + f"--dart-define=FLET_TEST_ASSETS_DIR={self.__assets_dir}" + ] self.__flutter_process = await asyncio.create_subprocess_exec( *flutter_args, @@ -271,17 +321,91 @@ async def main(page: ft.Page): stderr=stderr, ) + if self.__flutter_process.stdout is not None: + self.__flutter_output_task = asyncio.create_task( + self.__read_flutter_output(self.__flutter_process.stdout) + ) + print("Started Flutter test process.") - print("Waiting for a Flet client to connect...") + print("Waiting for the Flutter app to connect...") + + def connected() -> bool: + if self.__device_mode: + return self.__tester is not None and self.__tester.is_connected() + return ready.is_set() - while not ready.is_set(): + while not connected(): await asyncio.sleep(0.2) if self.__flutter_process.returncode is not None: + self.__dump_flutter_output() raise RuntimeError( "Flutter process exited early with code " f"{self.__flutter_process.returncode}" ) + async def __read_flutter_output(self, stream: asyncio.StreamReader): + # Read in chunks, not lines: the Flet client's debug output includes + # very long lines (e.g. screenshot bytes) that overflow StreamReader's + # per-line limit. Overlong lines are cut and only the output tail is + # kept to bound memory. + line = bytearray() + truncated = False + while True: + chunk = await stream.read(65536) + if not chunk: + break + for part in chunk.splitlines(keepends=True): + line.extend(part) + if line.endswith((b"\n", b"\r")): + self.__append_flutter_output_line(line, truncated) + line.clear() + truncated = False + elif len(line) > self.__flutter_output_line_limit: + del line[self.__flutter_output_line_limit :] + truncated = True + if line: + self.__append_flutter_output_line(line, truncated) + + def __append_flutter_output_line(self, line: bytearray, truncated: bool): + if len(line) > self.__flutter_output_line_limit: + line = line[: self.__flutter_output_line_limit] + truncated = True + self.__flutter_output.extend(line.rstrip(b"\r\n")) + if truncated: + self.__flutter_output.extend(b" ...") + self.__flutter_output.extend(b"\n") + if len(self.__flutter_output) > self.__flutter_output_limit: + del self.__flutter_output[: -self.__flutter_output_limit] + + def __dump_flutter_output(self): + if not self.__flutter_output: + return + output = self.__flutter_output.decode(errors="replace") + print("---------- Flutter test process output (tail) ----------") + print(output) + print("---------- End of Flutter test process output ----------") + + def __flutter_test_target(self) -> str: + # In device mode the driver (`integration_test/app_test.dart`) is + # generated from the template; validate it exists and is non-empty so a + # missing/empty driver surfaces as a clear error instead of a confusing + # "No tests were found" from `flutter test`. The directory target is + # used either way. + if self.__device_mode: + app_test_path = ( + Path(self.__flutter_app_dir) / "integration_test" / "app_test.dart" + ) + if not app_test_path.is_file(): + raise RuntimeError( + f"Flutter integration test driver was not generated: " + f"{app_test_path}" + ) + if not app_test_path.read_text(encoding="utf-8").strip(): + raise RuntimeError( + f"Flutter integration test driver is empty: {app_test_path}" + ) + return "integration_test" + async def teardown(self): """ Teardown Flutter integration test process. @@ -291,11 +415,13 @@ async def teardown(self): except (RuntimeError, TimeoutError) as e: print(f"Tester teardown failed: {e}") + flutter_returncode: Optional[int] = None if self.__flutter_process: print("\nWaiting for Flutter test process to exit...") try: await asyncio.wait_for(self.__flutter_process.wait(), timeout=10) - print("Flutter test process has exited.") + flutter_returncode = self.__flutter_process.returncode + print(f"Flutter test process has exited (code {flutter_returncode}).") except asyncio.TimeoutError: print("Flutter test process did not exit in time, terminating it...") self.__flutter_process.terminate() @@ -306,6 +432,27 @@ async def teardown(self): print("Force killing Flutter test process...") self.__flutter_process.kill() + if self.__flutter_output_task: + try: + await asyncio.wait_for(self.__flutter_output_task, timeout=5) + except asyncio.TimeoutError: + self.__flutter_output_task.cancel() + + # Stop the RemoteTester socket server (device mode). + if isinstance(self.__tester, RemoteTester): + await self.__tester.stop() + + # The host-side commands can all succeed while the on-device Flutter + # integration test itself fails (e.g. a widget exception fails the + # `testWidgets` body even though our find/tap assertions passed). Surface + # that as a test failure — otherwise the run is falsely green. + if flutter_returncode is not None and flutter_returncode != 0: + self.__dump_flutter_output() + raise RuntimeError( + f"Flutter integration test process failed with exit code " + f"{flutter_returncode}. See the Flutter test output above." + ) + def resize_page(self, width: float, height: float): """ Resizes the page window to the specified width and height. @@ -329,8 +476,10 @@ async def wrap_page_controls_in_screenshot( """ controls = list(self.page.controls) self.page.controls = [ - scr := ft.Screenshot( - ft.Column(controls, margin=margin, intrinsic_width=True) + self.__scrollable_screenshot_host( + scr := ft.Screenshot( + ft.Column(controls, margin=margin, intrinsic_width=True) + ) ) ] # type: ignore self.page.update() @@ -379,7 +528,11 @@ async def assert_control_screenshot( # add control and take screenshot screenshot = ft.Screenshot(control, expand=expand_screenshot) - self.page.add(screenshot) + self.page.add( + screenshot + if expand_screenshot + else self.__scrollable_screenshot_host(screenshot) + ) await self.__pump_and_settle_with_timeout("assert_control_screenshot-add") for _ in range(0, pump_times): await self.tester.pump(duration=pump_duration) @@ -389,6 +542,24 @@ async def assert_control_screenshot( similarity_threshold=similarity_threshold, ) + def __scrollable_screenshot_host( + self, screenshot: ft.Screenshot + ) -> Union[ft.Screenshot, ft.Column]: + # A scrollable page cannot overflow; an expanded host inside it would + # be flex-in-unbounded-height and fail layout instead. + if self.page.scroll is not None: + return screenshot + # Host the screenshot in a scrollable column: content taller than the + # window then scrolls instead of overflowing the page (an overflow + # error fails the Flutter test process). The child sees the same + # unbounded-height constraints as in the page column, so captures are + # unaffected. + return ft.Column( + expand=True, + scroll=ft.ScrollMode.HIDDEN, + controls=[screenshot], + ) + async def __pump_and_settle_with_timeout(self, stage: str): try: await self.tester.pump_and_settle(timeout=self.__pump_and_settle_timeout) @@ -523,7 +694,7 @@ def create_gif( same directory as the source frames. frames: Iterable of PNG-encoded frame bytes to use directly, in the order they should appear in the animation. Typically paired - with :meth:`Page.take_animation`. + with :meth:`~flet.BasePage.take_animation`. duration: Frame duration in milliseconds. Either a single `int` applied to every frame, or a sequence of `int` with one entry per frame. Pass the same list used for @@ -758,3 +929,5 @@ def _compare_gifs( return min(similarities), None __pump_and_settle_timeout = 10.0 + __flutter_output_limit = 262144 + __flutter_output_line_limit = 2048 diff --git a/sdk/python/packages/flet/src/flet/testing/remote_tester.py b/sdk/python/packages/flet/src/flet/testing/remote_tester.py new file mode 100644 index 0000000000..0670e27c19 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/testing/remote_tester.py @@ -0,0 +1,282 @@ +import asyncio +import base64 +import contextlib +import json +from dataclasses import asdict, is_dataclass +from typing import Any, Optional + +from flet.controls.duration import DurationValue +from flet.controls.keys import KeyValue +from flet.controls.types import IconData +from flet.testing.finder import Finder + +__all__ = ["RemoteTester", "RemoteTesterError"] + + +class RemoteTesterError(RuntimeError): + """Error returned from a remote tester invocation.""" + + def __init__(self, message: str, stack: Optional[str] = None): + super().__init__(message) + self.stack = stack + + +class RemoteTester: + """ + TCP server that drives the Flutter integration-test ``WidgetTester`` over an + independent line-delimited JSON protocol (separate from Flet's own + transport). The on-device app's ``RemoteWidgetTester`` connects to this + server and executes the commands. + """ + + def __init__(self): + self._server: Optional[asyncio.AbstractServer] = None + self._reader: Optional[asyncio.StreamReader] = None + self._writer: Optional[asyncio.StreamWriter] = None + self._connected = asyncio.Event() + self._closed = asyncio.Event() + self._closed.set() + self._pending: dict[int, asyncio.Future[Any]] = {} + self._request_id = 0 + self._reader_task: Optional[asyncio.Task[Any]] = None + self._send_lock = asyncio.Lock() + self.host = "127.0.0.1" + self.port: Optional[int] = None + + async def start(self, host: str = "127.0.0.1", port: Optional[int] = None) -> int: + """ + Starts the TCP server accepting a connection from the Flutter app. + + Returns: + Bound TCP port. + """ + if self._server is not None: + raise RuntimeError("RemoteTester server is already running.") + + self.host = host + self._server = await asyncio.start_server(self._handle_client, host, port) + sock = self._server.sockets[0] + self.port = sock.getsockname()[1] + return self.port + + async def _handle_client( + self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter + ): + if self._reader is not None: + writer.close() + await writer.wait_closed() + return + + self._reader = reader + self._writer = writer + self._closed.clear() + self._connected.set() + self._reader_task = asyncio.create_task(self._read_loop()) + + try: + await self._reader_task + finally: + self._cleanup_connection() + + async def _read_loop(self): + assert self._reader is not None + reader = self._reader + max_frame_length = 64 * 1024 * 1024 + while True: + try: + header = await reader.readexactly(4) + except asyncio.IncompleteReadError: + break + length = int.from_bytes(header, "big") + if length > max_frame_length: + raise ValueError("Incoming frame exceeds allowed size.") + try: + payload = await reader.readexactly(length) + except asyncio.IncompleteReadError: + break + message = json.loads(payload.decode("utf-8")) + self._dispatch_message(message) + + def _dispatch_message(self, message: Any): + request_id = message.get("id") + future = self._pending.pop(request_id, None) + if future is None: + return + if "error" in message: + future.set_exception( + RemoteTesterError(message["error"], message.get("stack")) + ) + else: + future.set_result(message.get("result")) + + def _cleanup_connection(self): + for future in self._pending.values(): + if not future.done(): + future.set_exception( + ConnectionError("Remote tester connection was closed.") + ) + self._pending.clear() + self._reader = None + self._writer = None + self._reader_task = None + self._connected.clear() + self._closed.set() + + async def stop(self): + """Stops the TCP server and releases any bound resources.""" + # Tear down the active client connection first. `_read_loop` blocks on + # `readexactly` until it sees EOF, and the on-device app's socket close + # does not always deliver that to us (observed on Linux), so without this + # `Server.wait_closed()` below would hang forever waiting for the still + # running `_handle_client`. Cancelling the read task lets `_handle_client` + # finish; the timeout is a final safety net. + if self._reader_task is not None and not self._reader_task.done(): + self._reader_task.cancel() + if self._writer is not None: + with contextlib.suppress(Exception): + self._writer.close() + if self._server is not None: + self._server.close() + with contextlib.suppress(asyncio.TimeoutError): + await asyncio.wait_for(self._server.wait_closed(), timeout=5) + self._server = None + + async def _ensure_connected(self): + await self._connected.wait() + if self._writer is None: + raise ConnectionError("Remote tester is not connected.") + + async def _invoke( + self, + method: str, + params: Optional[dict[str, Any]] = None, + timeout: Optional[float] = 60, + ): + await self._ensure_connected() + self._request_id += 1 + request_id = self._request_id + + loop = asyncio.get_running_loop() + future: asyncio.Future[Any] = loop.create_future() + self._pending[request_id] = future + + payload: dict[str, Any] = {"id": request_id, "method": method} + if params: + payload["params"] = params + + async with self._send_lock: + assert self._writer is not None + data = json.dumps(payload).encode("utf-8") + self._writer.write(len(data).to_bytes(4, "big") + data) + await self._writer.drain() + + try: + if timeout is not None: + return await asyncio.wait_for(future, timeout=timeout) + return await future + except asyncio.TimeoutError: + self._pending.pop(request_id, None) + raise TimeoutError( + f"Timeout waiting for remote tester method {method}({params})" + ) from None + + async def pump(self, duration: Optional[DurationValue] = None): + await self._invoke( + "pump", _with_optional("duration", _serialize_duration(duration)) + ) + + async def pump_and_settle(self, duration: Optional[DurationValue] = None): + await self._invoke( + "pump_and_settle", + _with_optional("duration", _serialize_duration(duration)), + ) + + async def find_by_text(self, text: str) -> Finder: + finder = await self._invoke("find_by_text", {"text": text}) + return Finder(**finder) + + async def find_by_text_containing(self, pattern: str) -> Finder: + finder = await self._invoke("find_by_text_containing", {"pattern": pattern}) + return Finder(**finder) + + async def find_by_key(self, key: KeyValue) -> Finder: + finder = await self._invoke("find_by_key", {"key": _serialize_key(key)}) + return Finder(**finder) + + async def find_by_tooltip(self, value: str) -> Finder: + finder = await self._invoke("find_by_tooltip", {"value": value}) + return Finder(**finder) + + async def find_by_icon(self, icon: IconData) -> Finder: + finder = await self._invoke("find_by_icon", {"icon": _serialize_icon(icon)}) + return Finder(**finder) + + async def take_screenshot(self, name: str) -> bytes: + data = await self._invoke("take_screenshot", {"name": name}) + return base64.b64decode(data) + + async def tap(self, finder: Finder): + await self._invoke("tap", _finder_params(finder)) + + async def long_press(self, finder: Finder): + await self._invoke("long_press", _finder_params(finder)) + + async def enter_text(self, finder: Finder, text: str): + await self._invoke("enter_text", {**_finder_params(finder), "text": text}) + + async def mouse_hover(self, finder: Finder): + await self._invoke("mouse_hover", _finder_params(finder)) + + async def teardown(self, timeout: Optional[float] = None): + if not self.is_connected(): + return + try: + await self._invoke("teardown") + finally: + await self.wait_closed() + + async def wait_closed(self): + await self._closed.wait() + + def is_connected(self) -> bool: + return self._connected.is_set() + + async def wait_for_connection(self, timeout: Optional[float] = None): + if timeout is not None: + await asyncio.wait_for(self._connected.wait(), timeout) + else: + await self._connected.wait() + + +def _finder_params(finder: Finder) -> dict[str, Any]: + return {"finder_id": finder.id, "finder_index": finder.index} + + +def _with_optional(key: str, value: Any) -> dict[str, Any]: + return {key: value} if value is not None else {} + + +def _serialize_duration(duration: Optional[DurationValue]) -> Any: + if duration is None: + return None + if is_dataclass(duration) and not isinstance(duration, type): + return asdict(duration) + if isinstance(duration, (int, float)): + return int(duration) + return duration + + +def _serialize_key(value: KeyValue) -> Any: + if value is None: + return None + if is_dataclass(value) and not isinstance(value, type): + return asdict(value) + return value + + +def _serialize_icon(icon: IconData) -> Any: + if icon is None: + return None + if hasattr(icon, "value"): + return int(icon) + return icon diff --git a/sdk/python/packages/flet/src/flet/version.py b/sdk/python/packages/flet/src/flet/version.py index 3f0a090f49..3e50c2eb5b 100644 --- a/sdk/python/packages/flet/src/flet/version.py +++ b/sdk/python/packages/flet/src/flet/version.py @@ -13,7 +13,6 @@ "flet_version", "flutter_version", "from_git", - "pyodide_version", ] # set by CI @@ -37,12 +36,6 @@ `.fvmrc` file when available. """ -PYODIDE_VERSION = "0.27.7" -""" -The Pyodide version being used when packaging -with [`flet build web`](https://flet.dev/docs/cli/flet-build/). -""" - def from_git() -> Optional[str]: """Try to get the version from Git tags.""" @@ -61,6 +54,8 @@ def from_git() -> Optional[str]: capture_output=True, text=True, check=True, + # Prevent console-window-flashes per git invocation on Windows. + creationflags=sp.CREATE_NO_WINDOW if is_windows() else 0, ) tag = result.stdout.strip() return tag[1:] if tag.startswith("v") else tag @@ -141,6 +136,5 @@ def get_flutter_version() -> str: flutter_version = get_flutter_version() -pyodide_version = PYODIDE_VERSION flet_version = get_flet_version() __version__ = flet_version diff --git a/sdk/python/packages/flet/tests/test_deprecated.py b/sdk/python/packages/flet/tests/test_deprecated.py index 3185ebd5a0..9069dc4f2c 100644 --- a/sdk/python/packages/flet/tests/test_deprecated.py +++ b/sdk/python/packages/flet/tests/test_deprecated.py @@ -8,7 +8,6 @@ import pytest -import flet as ft from flet.utils.deprecated import deprecated, deprecated_class, deprecated_warning @@ -161,14 +160,3 @@ def test_deprecated_warning_points_to_user_code_through_flet_frames(): warning = captured[0] assert warning.filename == __file__ assert warning.lineno == expected_line - - -def test_dropdownm2_warns_with_removal_version(): - with pytest.warns( - DeprecationWarning, - match=re.escape( - "DropdownM2 is deprecated since version 0.84.0 and will be removed in " - "version 1.0. Use Dropdown instead." - ), - ): - ft.DropdownM2() diff --git a/sdk/python/packages/flet/tests/test_raw_image_pixels.py b/sdk/python/packages/flet/tests/test_raw_image_pixels.py new file mode 100644 index 0000000000..1546ed6569 --- /dev/null +++ b/sdk/python/packages/flet/tests/test_raw_image_pixels.py @@ -0,0 +1,133 @@ +import asyncio + +import pytest + +import flet as ft +from flet.controls.core.raw_image import ( + RawImage, + _encode_raw_packet, + _premultiply_pil, + _rgba_is_opaque, +) + + +def test_encode_raw_packet_layout(): + rgba = bytes(range(8)) + pkt = _encode_raw_packet(2, 1, rgba) + assert pkt[0] == 0x04 + assert int.from_bytes(pkt[1:5], "little") == 2 + assert int.from_bytes(pkt[5:9], "little") == 1 + assert pkt[9:] == rgba + assert len(pkt) == 9 + len(rgba) + + +def test_rgba_is_opaque(): + assert _rgba_is_opaque(b"") + assert _rgba_is_opaque(b"\x01\x02\x03\xff" * 100) + assert not _rgba_is_opaque(b"\x01\x02\x03\xff" * 99 + b"\x01\x02\x03\xfe") + + +def test_premultiply_pil_opaque_is_noop(): + PILImage = pytest.importorskip("PIL.Image") + img = PILImage.new("RGBA", (4, 4), (10, 20, 30, 255)) + assert _premultiply_pil(img) is img + + +def test_premultiply_pil_matches_integer_math(): + PILImage = pytest.importorskip("PIL.Image") + img = PILImage.new("RGBA", (1, 3)) + src = [(200, 100, 50, 128), (255, 255, 255, 0), (8, 16, 32, 255)] + img.putdata(src) + raw = _premultiply_pil(img).tobytes() + out = [tuple(raw[i : i + 4]) for i in range(0, len(raw), 4)] + for (r, g, b, a), (pr, pg, pb, pa) in zip(src, out): + assert pa == a + # ImageChops.multiply rounds a*b/255; allow off-by-one vs floor. + for straight, pre in ((r, pr), (g, pg), (b, pb)): + assert abs(pre - straight * a // 255) <= 1 + + +def test_premultiply_pil_parity_with_numpy_math(): + PILImage = pytest.importorskip("PIL.Image") + np = pytest.importorskip("numpy") + rng = np.random.default_rng(7) + arr = rng.integers(0, 256, size=(16, 16, 4), dtype=np.uint8) + img = PILImage.frombuffer("RGBA", (16, 16), arr.tobytes()) + pil_out = np.frombuffer(_premultiply_pil(img).tobytes(), dtype=np.uint8) + pil_out = pil_out.reshape(16, 16, 4).astype(np.int16) + # The numpy premultiply used by the matplotlib Agg backend. + a = arr[:, :, 3:4].astype(np.uint16) + expected = arr.copy() + expected[:, :, :3] = (arr[:, :, :3].astype(np.uint16) * a // 255).astype(np.uint8) + assert np.abs(pil_out - expected.astype(np.int16)).max() <= 1 + + +def test_array_packet_premultiplies_straight_alpha(): + np = pytest.importorskip("numpy") + arr = np.zeros((1, 2, 4), dtype=np.uint8) + arr[0, 0] = (200, 100, 50, 128) + arr[0, 1] = (10, 20, 30, 255) + pkt = RawImage._array_packet(np, arr, premultiplied=False) + assert int.from_bytes(pkt[1:5], "little") == 2 # width + assert int.from_bytes(pkt[5:9], "little") == 1 # height + assert tuple(pkt[9:13]) == ( + 200 * 128 // 255, + 100 * 128 // 255, + 50 * 128 // 255, + 128, + ) + assert tuple(pkt[13:17]) == (10, 20, 30, 255) # opaque pixel untouched + + +def test_array_packet_opaque_frame_is_passthrough(): + np = pytest.importorskip("numpy") + arr = np.full((2, 2, 4), 255, dtype=np.uint8) + arr[:, :, :3] = 42 + pkt = RawImage._array_packet(np, arr, premultiplied=False) + assert pkt[9:] == arr.tobytes() + + +def test_render_rejects_unknown_input(): + ri = ft.RawImage() + + async def run(): + with pytest.raises(TypeError, match="PIL.Image.Image"): + await ri.render("not an image") + + asyncio.run(run()) + + +def test_render_rgba_rejects_wrong_length(): + ri = ft.RawImage() + + async def run(): + with pytest.raises(ValueError, match="width \\* height \\* 4"): + await ri.render_rgba(2, 2, b"\x00" * 15) + + asyncio.run(run()) + + +class _SilentChannel: + """A channel that accepts frames but never acks — a dead client.""" + + def __init__(self): + self.sent = [] + + def send(self, payload: bytes) -> None: + self.sent.append(payload) + + +def test_render_times_out_without_ack(): + ri = ft.RawImage(ack_timeout=0.05) + + async def run(): + ri._channel = _SilentChannel() + ri._ready.set() + with pytest.raises(TimeoutError, match="not acknowledged"): + await ri.render_rgba(1, 1, b"\x00\x00\x00\xff") + # The abandoned future is withdrawn so a late ack can't resolve + # the wrong frame's wait. + assert not ri._pending_acks + assert len(ri._channel.sent) == 1 + + asyncio.run(run()) diff --git a/sdk/python/pyproject.toml b/sdk/python/pyproject.toml index 66bed0b632..100f98b5c0 100644 --- a/sdk/python/pyproject.toml +++ b/sdk/python/pyproject.toml @@ -22,6 +22,7 @@ dependencies = [ "flet-geolocator", "flet-lottie", "flet-map", + "flet-mcp", "flet-permission-handler", "flet-rive", "flet-secure-storage", @@ -40,19 +41,20 @@ flet-audio = { workspace = true } flet-audio-recorder = { workspace = true } flet-camera = { workspace = true } flet-charts = { workspace = true } +flet-code-editor = { workspace = true } +flet-color-pickers = { workspace = true } flet-datatable2 = { workspace = true } flet-flashlight = { workspace = true } flet-geolocator = { workspace = true } flet-lottie = { workspace = true } flet-map = { workspace = true } +flet-mcp = { workspace = true } flet-permission-handler = { workspace = true } flet-rive = { workspace = true } flet-secure-storage = { workspace = true } flet-spinkit = { workspace = true } flet-video = { workspace = true } flet-webview = { workspace = true } -flet-code-editor = { workspace = true } -flet-color-pickers = { workspace = true } [tool.uv.workspace] members = ["packages/*"] @@ -83,6 +85,10 @@ docs-coverage = [ docs = [ { include-group = 'docs-coverage' }, ] +mcp-build = [ + "markdownify >=0.14.1", + "griffe >=1.6.2", +] all = [ { include-group = 'dev' }, { include-group = 'docs' }, @@ -116,11 +122,12 @@ isort = { known-first-party = [ "flet_geolocator", "flet_lottie", "flet_map", + "flet_mcp", "flet_permission_handler", "flet_rive", "flet_secure_storage", "flet_video", - "flet_webview" + "flet_webview", ] } preview = true select = [ diff --git a/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/.gitignore b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/.gitignore index fdc62e4b44..dc5254c056 100644 --- a/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/.gitignore +++ b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/.gitignore @@ -25,4 +25,4 @@ storage/ .vscode/ # macOS -.DS_Store +.DS_Store \ No newline at end of file diff --git a/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/pyproject.toml b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/pyproject.toml index 28ce4eda91..09a0e12e24 100644 --- a/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/pyproject.toml +++ b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/pyproject.toml @@ -16,8 +16,15 @@ dev = [ "flet-cli>={{cookiecutter.flet_version}}", "flet-desktop>={{cookiecutter.flet_version}}", "flet-web>={{cookiecutter.flet_version}}", + # Integration testing with `flet test` / pytest. The `test` extra brings in + # pytest, pytest-asyncio and the screenshot-comparison dependencies. + "flet[test]>={{cookiecutter.flet_version}}", ] +[tool.pytest.ini_options] +asyncio_mode = "auto" +testpaths = ["tests"] + [tool.flet] {%- if cookiecutter.platform == "linux" %} desktop_flavor = "light" # Change to "full" to use flet-audio and flet-video diff --git a/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/src/main.py b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/src/main.py index f8dda08180..21959dfc5a 100644 --- a/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/src/main.py +++ b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/src/main.py @@ -4,12 +4,12 @@ def main(page: ft.Page): counter = ft.Text("0", size=50, data=0) - def increment_click(e): + def increment_click(e: ft.Event[ft.FloatingActionButton]): counter.data += 1 counter.value = str(counter.data) page.floating_action_button = ft.FloatingActionButton( - icon=ft.Icons.ADD, on_click=increment_click + icon=ft.Icons.ADD, key="increment", on_click=increment_click ) page.add( ft.SafeArea( @@ -22,4 +22,5 @@ def increment_click(e): ) -ft.run(main) +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/tests/test_main.py b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/tests/test_main.py new file mode 100644 index 0000000000..858e8fef00 --- /dev/null +++ b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/tests/test_main.py @@ -0,0 +1,22 @@ +import flet.testing as ftt + + +async def test_increment(flet_app: ftt.FletTestApp): + """Counter sample: tap the FAB and assert the counter goes 0 -> 1. + + The `flet_app` fixture is provided automatically by the flet pytest plugin. + Run with `flet test` (or `uv run pytest`) from the project directory. + """ + tester = flet_app.tester + + await tester.pump_and_settle() + + # Initial state + assert (await tester.find_by_text("0")).count == 1 + + # Tap the increment button (found by its key) and let the UI settle + await tester.tap(await tester.find_by_key("increment")) + await tester.pump_and_settle() + + # New state + assert (await tester.find_by_text("1")).count == 1 diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/README.md b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/README.md index 00c9c68e54..b5eb9fdd29 100644 --- a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/README.md +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/README.md @@ -1,37 +1,85 @@ # {{cookiecutter.project_name}} -{{cookiecutter.control_name}} control for Flet -## Installation +{{cookiecutter.project_name}} [Flet](https://flet.dev) extension. +{% if cookiecutter.description %} +{{ cookiecutter.description }} +{% endif %} + -Add dependency to `pyproject.toml` of your Flet app: +## Platform Support -* **Git dependency** + -Link to git repository: +| Platform | iOS | Android | Web | Windows | macOS | Linux | +|-----------|-----|---------|-----|---------|-------|-------| +| Supported | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -``` +## Usage + +### Installation + +Add `{{cookiecutter.project_name}}` dependency to the `pyproject.toml` of your Flet project: + +* **From Git** + +```toml dependencies = [ - "{{cookiecutter.project_name}} @ git+https://github.com/MyGithubAccount/{{cookiecutter.project_name}}", + "{{cookiecutter.project_name}} @ git+https://github.com/MY_GITHUB_ACCOUNT/{{cookiecutter.project_name}}", "flet>={{cookiecutter.flet_version}}", ] ``` -* **uv/pip dependency** + -If the package is published on pypi.org: +* **From PyPI** -``` +```toml dependencies = [ "{{cookiecutter.project_name}}", "flet>={{cookiecutter.flet_version}}", ] ``` -Build your app: +### Run your app + +A Flet extension has two sides: its Python controls/services and the native Flutter/Dart widgets behind them. +That native code must be compiled into a Flet client before your controls can render, and the +prebuilt client that a plain `flet run` uses does **not** include this extension. + +So run your app in one of these two ways: + +**1. [`flet debug`](https://flet.dev/docs/cli/flet-debug)** — all platforms: *Windows, macOS, Linux, Web, iOS, Android* + +Compiles the extension and launches your app on the target you pick. +The simplest option, and the way to go for mobile and web: + +```bash +flet debug macos # desktop & web: no device needed +flet debug android -d # mobile: connect a device/emulator first ``` -flet build macos -v + +For iOS and Android, pass `-d ` (run `flet debug --show-devices` to list connected devices). +Edits to your **Python** code are picked up the next time you run `flet debug`. + +**2. [`flet build`](https://flet.dev/docs/cli/flet-build) once, then [`flet run`](https://flet.dev/docs/cli/flet-run)** — desktop only: *Windows, macOS, Linux* + +Build a custom client that bundles the extension **once**, then use `flet run` for a fast hot-reload loop while you edit Python: + +```bash +flet build macos # or: flet build windows / flet build linux +flet run # run from the folder where build/ was created, so it reuses that client ``` -## Documentation +`flet run` auto-detects the client under `build//`, so your Python edits hot-reload instantly. +Rebuild only when the extension's **Dart** code changes. + +### Examples + +See the [examples](examples) directory. + +### Documentation + + -[Link to documentation](https://MyGithubAccount.github.io/{{cookiecutter.project_name}}/) +Detailed documentation for this package can be found [here](https://MY_GITHUB_ACCOUNT.github.io/{{cookiecutter.project_name}}/). diff --git a/sdk/python/templates/build/cookiecutter.json b/sdk/python/templates/build/cookiecutter.json index 405dfb8dfa..a2f0345032 100644 --- a/sdk/python/templates/build/cookiecutter.json +++ b/sdk/python/templates/build/cookiecutter.json @@ -27,9 +27,12 @@ "pwa_background_color": "#FFFFFF", "pwa_theme_color": "#0175C2", "split_per_abi": false, + "test_mode": false, "no_cdn": false, "no_wasm": false, + "pyodide_version": "", "options": null, "pyproject": null, + "boot_screen": null, "_extensions": ["cookiecutter_extensions.FletExtension"] } diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/build.gradle.kts b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/build.gradle.kts index 0e25dd99ee..9cc68c758f 100644 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/build.gradle.kts +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/build.gradle.kts @@ -2,8 +2,9 @@ import java.util.Properties plugins { id("com.android.application") - id("org.jetbrains.kotlin.android") - // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + // Kotlin is provided by the Flutter Gradle Plugin (Built-in Kotlin), so the + // app no longer applies the Kotlin Gradle Plugin itself. + // The Flutter Gradle Plugin must be applied after the Android Gradle plugin. id("dev.flutter.flutter-gradle-plugin") } @@ -22,15 +23,33 @@ android { compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion + // serious_python loads Python extension modules memory-mapped directly from the + // APK (no extraction) and ships pure Python in stored asset zips, so + // `useLegacyPackaging` / `keepDebugSymbols` from earlier Flet templates are no + // longer needed at minSdk 23+. The `pickFirsts` and `excludes` blocks below + // address two unrelated multi-source jniLibs issues that AGP can't resolve on + // its own. packaging { jniLibs { - useLegacyPackaging = true - keepDebugSymbols += listOf( - "*/arm64-v8a/libpython*.so", - "*/armeabi-v7a/libpython*.so", - "*/x86/libpython*.so", - "*/x86_64/libpython*.so", - ) + // serious_python_android ships libc++_shared.so as part of the Python runtime payload + // (the cross-compiled wheels on pypi.flet.dev depend on it at link time). Many third-party + // Flutter plugins (ultralytics_yolo, sentry_flutter, several ML / CV / audio plugins) also + // bundle their own copy. When an app pulls in both, Gradle's mergeNativeLibs task aborts + // with "N files found with path 'lib//libc++_shared.so'" because AGP refuses to silently + // choose between duplicate native libraries (the right default for most .so files). + // + // libc++_shared.so is a documented exception: the NDK has held strict ABI compatibility on it + // since r17, so whichever copy wins input ordering, every consumer that linked against libc++_shared + // will work against it. pickFirsts is the narrowly-scoped escape hatch for exactly this case -- it + // only opens a hole for the matching glob; any other future duplicate-native-lib conflict still fails loudly. + pickFirsts += listOf("**/libc++_shared.so") + +// flet: excluded_abis {% if cookiecutter.options.android_excluded_abis %} + // Strip native libs of ABIs not requested via `target_arch`. + // `ndk.abiFilters` alone can't do this: the Flutter Gradle plugin adds all default + // ABIs as buildType-level filters and AGP merges the two levels as a union. + excludes += listOf({% for abi in cookiecutter.options.android_excluded_abis %}"lib/{{ abi }}/**"{% if not loop.last %}, {% endif %}{% endfor %}) +// flet: end of excluded_abis {% endif %} } } @@ -39,10 +58,6 @@ android { targetCompatibility = JavaVersion.VERSION_17 } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_17.toString() - } - sourceSets["main"].java.srcDir("src/main/kotlin") {% set min_sdk_version = get_pyproject("tool.flet.android.min_sdk_version") %} @@ -96,6 +111,12 @@ android { } } +kotlin { + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 + } +} + flutter { source = "../.." } diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/integration_test/app_test.dart b/sdk/python/templates/build/{{cookiecutter.out_dir}}/integration_test/app_test.dart new file mode 100644 index 0000000000..9a7fa7fd77 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/integration_test/app_test.dart @@ -0,0 +1,8 @@ +{% if cookiecutter.test_mode %}import 'package:flet_integration_test/flet_integration_test.dart'; +import 'package:{{ cookiecutter.project_name }}/main.dart' as app; + +// Device-mode integration test entry point. The app under test runs on-device +// with embedded Python over dart_bridge; a RemoteWidgetTester drives it over a +// raw socket connected to the pytest RemoteTester server (FLET_TEST_SERVER_URL). +void main() => runFletDeviceTest(appMain: app.main); +{% endif %} \ No newline at end of file diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/flet_generated.dart b/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/flet_generated.dart new file mode 100644 index 0000000000..48c6f63621 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/flet_generated.dart @@ -0,0 +1,33 @@ +// GENERATED FILE — do not edit. +// +// All build-time (cookiecutter / jinja) declarations live here so that +// `main.dart` stays plain, editable Dart with no template noise. + +import 'dart:convert'; + +import 'package:flet/flet.dart'; + +{% for dep in cookiecutter.flutter.dependencies %} +import 'package:{{ dep }}/{{ dep }}.dart' as {{ dep }}; +{% endfor %} + +{% set hide_window_on_start = get_pyproject("tool.flet." ~ cookiecutter.options.config_platform ~ ".app.hide_window_on_start") + or get_pyproject("tool.flet.app.hide_window_on_start") %} + +const pythonModuleName = "{{ cookiecutter.python_module_name }}"; + +final hideWindowOnStart = + bool.tryParse("{{ hide_window_on_start }}".toLowerCase()) ?? false; + +const bootScreenName = "{{ cookiecutter.boot_screen.name }}"; + +final bootScreenOptions = (jsonDecode(utf8 + .decode(base64Decode("{{ cookiecutter.boot_screen.options_b64 }}"))) + as Map) + .cast(); + +List extensions = [ +{% for dep in cookiecutter.flutter.dependencies %} + {{ dep }}.Extension(), +{% endfor %} +]; diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/main.dart b/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/main.dart index a4adf44dcf..ca345ba1c9 100644 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/main.dart +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/main.dart @@ -5,58 +5,33 @@ import 'dart:ui'; import 'package:flet/flet.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:package_info_plus/package_info_plus.dart'; import 'package:path/path.dart' as path; import 'package:path_provider/path_provider.dart' as path_provider; -import 'package:serious_python/serious_python.dart'; import 'package:flutter_web_plugins/url_strategy.dart'; import 'package:window_manager/window_manager.dart'; -import "python.dart"; +// `dart:ffi` (and therefore `package:serious_python/bridge.dart`, +// `package:serious_python/serious_python.dart`) isn't available on web. +// The conditional import below loads the real PythonBridge-backed runtime +// on platforms where FFI exists; on web it resolves to a stub of the same +// shape that just throws if invoked. `main` guards every use with +// `kIsWeb` so the stub is never actually called. +import 'native_runtime_stub.dart' + if (dart.library.ffi) 'native_runtime.dart' as nrt; -{% for dep in cookiecutter.flutter.dependencies %} -import 'package:{{ dep }}/{{ dep }}.dart' as {{ dep }}; -{% endfor %} - -/* -{% set show_boot_screen = get_pyproject("tool.flet." ~ cookiecutter.options.config_platform ~ ".app.boot_screen.show") - or get_pyproject("tool.flet.app.boot_screen.show") - or False %} -{% set boot_screen_message = get_pyproject("tool.flet." ~ cookiecutter.options.config_platform ~ ".app.boot_screen.message") - or get_pyproject("tool.flet.app.boot_screen.message") %} - -{% set show_startup_screen = get_pyproject("tool.flet." ~ cookiecutter.options.config_platform ~ ".app.startup_screen.show") - or get_pyproject("tool.flet.app.startup_screen.show") - or False %} -{% set startup_screen_message = get_pyproject("tool.flet." ~ cookiecutter.options.config_platform ~ ".app.startup_screen.message") - or get_pyproject("tool.flet.app.startup_screen.message") %} - -{% set hide_window_on_start = get_pyproject("tool.flet." ~ cookiecutter.options.config_platform ~ ".app.hide_window_on_start") - or get_pyproject("tool.flet.app.hide_window_on_start") %} - -show_boot_screen: {{ show_boot_screen }} -boot_screen_message: {{ boot_screen_message }} -show_startup_screen: {{ show_startup_screen }} -startup_screen_message: {{ startup_screen_message }} -hide_window_on_start: {{ hide_window_on_start }} -*/ +// All build-time (cookiecutter / jinja) declarations — extension imports and +// list, python module name, boot screen config — live in this generated file +// so that main.dart stays plain, editable Dart. +import 'flet_generated.dart'; const bool isRelease = bool.fromEnvironment('dart.vm.product'); -const assetPath = "app/app.zip"; -const pythonModuleName = "{{ cookiecutter.python_module_name }}"; -final showAppBootScreen = bool.tryParse("{{ show_boot_screen }}".toLowerCase()) ?? false; -const appBootScreenMessage = '{{ boot_screen_message | default("Preparing the app for its first launch…", true) }}'; -final showAppStartupScreen = bool.tryParse("{{ show_startup_screen }}".toLowerCase()) ?? false; -const appStartupScreenMessage = '{{ startup_screen_message | default("Getting things ready…", true) }}'; -final hideWindowOnStart = bool.tryParse("{{ hide_window_on_start }}".toLowerCase()) ?? false; - -List extensions = [ -{% for dep in cookiecutter.flutter.dependencies %} -{{ dep }}.Extension(), -{% endfor %} -]; +// Drives the boot screen before any FletBackend exists. Seeded to `startingUp` +// so the "preparing" stage never flashes on platforms/launches that don't +// unpack the app bundle. Only Android's first launch after install/update +// actually unpacks (see `_boot`), and only then is it switched to `preparing`. +final ValueNotifier _bootStatus = + ValueNotifier(const BootStatus(BootStage.startingUp)); String outLogFilename = ""; @@ -68,6 +43,19 @@ String appDir = ""; Map environmentVariables = Map.from(Platform.environment); void main(List args) async { + // On web the URL strategy must be selected before ANYTHING reads the initial + // location: FletDeepLinkingBootstrap.install() (below) calls + // WidgetsFlutterBinding.ensureInitialized() and starts observing route pushes, + // and the first runApp() wires up the router. Whatever strategy is active at + // that point latches how the cold-start URL maps to a route — under Flutter's + // default hash strategy a hard refresh of `/apps/x` reads an empty fragment + // (route "/"), so the deep link is lost and the app rewrites the URL to "/". + // Applying the strategy that `flet build` baked into window.flet here, as the + // very first statement, keeps both the running URLs (no `/#/`) and cold-start + // deep links on the path strategy. + if (kIsWeb && getFletRouteUrlStrategy() == "path") { + usePathUrlStrategy(); + } FletDeepLinkingBootstrap.install(); @@ -82,51 +70,244 @@ void main(List args) async { ext.ensureInitialized(); } - runApp(FutureBuilder( + if (const bool.fromEnvironment("FLET_TEST")) { + // Under integration test (`flet test`), `BootHost` (a StatefulWidget whose + // initState awaits prepareApp() then setState()s) deadlocks the + // WidgetTester: `tester.pump()` blocks waiting for a frame that never + // arrives during this boot. Use the simpler FutureBuilder boot path (no + // animated boot-screen overlay), which the tester drives cleanly. The app + // itself — embedded Python over dart_bridge, FletApp — is identical. + runApp(FutureBuilder( future: prepareApp(), - builder: (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.hasData) { - // OK - start Python program - return kIsWeb || (isDesktopPlatform() && _args.isNotEmpty) - ? FletApp( - pageUrl: pageUrl, - assetsDir: assetsDir, - showAppStartupScreen: showAppStartupScreen, - appStartupScreenMessage: appStartupScreenMessage, - extensions: extensions) - : FutureBuilder( - future: runPythonApp(args), - builder: - (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.hasData || snapshot.hasError) { - // error or premature finish - return MaterialApp( - builder: (context, _) => ErrorScreen( - title: "Error running app", - text: snapshot.data ?? snapshot.error.toString()), - ); - } else { - // no result of error - return FletApp( - pageUrl: pageUrl, - assetsDir: assetsDir, - showAppStartupScreen: showAppStartupScreen, - appStartupScreenMessage: appStartupScreenMessage, - extensions: extensions); - } - }); - } else if (snapshot.hasError) { - // error - return MaterialApp( - builder: (context, _) => ErrorScreen( - title: "Error starting app", - text: snapshot.error.toString())); - } else { - // loading - return MaterialApp( - builder: (context, _) => showAppBootScreen ? const BootScreen() : const BlankScreen()); + builder: (context, snapshot) { + if (snapshot.connectionState != ConnectionState.done) { + return const SizedBox.shrink(); } - })); + if (kIsWeb || (isDesktopPlatform() && _args.isNotEmpty)) { + return FletApp( + pageUrl: pageUrl, + assetsDir: assetsDir, + bootScreenName: bootScreenName, + bootScreenOptions: bootScreenOptions, + bootStatus: _bootStatus, + extensions: extensions, + ); + } + return _ProdApp(args: args); + }, + )); + return; + } + + runApp(BootHost(args: args)); +} + +/// Hosts the app together with a persistent boot screen overlay. +/// +/// The boot screen is rendered once, at a fixed position above the app tree, so +/// its animation runs continuously across both boot phases (preparing → starting +/// up) instead of restarting when `prepareApp()` completes and the app tree is +/// built underneath. The overlay fades out once the app reports it is ready. +class BootHost extends StatefulWidget { + final List args; + + const BootHost({super.key, required this.args}); + + @override + State createState() => _BootHostState(); +} + +class _BootHostState extends State { + bool _prepared = false; + + @override + void initState() { + super.initState(); + _boot(); + } + + Future _boot() async { + // The "preparing" stage is only meaningful while the app bundle is being + // unpacked, which happens on Android's first launch after install/update. + // Everywhere else prepareApp() is fast, so staying in `startingUp` avoids + // flashing "Preparing…" every launch. Only switch to `preparing` if + // prepareApp is actually slow on Android (i.e. it's unpacking). + Timer? preparingTimer; + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + preparingTimer = Timer(const Duration(milliseconds: 400), () { + _bootStatus.value = const BootStatus(BootStage.preparing); + }); + } + try { + await prepareApp(); + } catch (e) { + preparingTimer?.cancel(); + _bootStatus.value = BootStatus(BootStage.preparing, error: e.toString()); + return; + } + preparingTimer?.cancel(); + // Unpacking (if any) is done — hand off to the starting-up stage. + _bootStatus.value = const BootStatus(BootStage.startingUp); + if (!mounted) return; + setState(() => _prepared = true); + } + + @override + Widget build(BuildContext context) { + return Directionality( + textDirection: TextDirection.ltr, + child: Stack( + children: [ + // The app builds underneath the overlay; while preparing it is just + // an empty placeholder (the opaque overlay covers it anyway). + _prepared ? _buildApp() : const SizedBox.shrink(), + _BootOverlay(status: _bootStatus), + ], + ), + ); + } + + Widget _buildApp() { + // In web + dev modes FletApp connects over its URL-scheme transport + // (websocket / TCP / UDS). In production prepareApp() created the native + // FFI bridges and we additionally run the embedded Python program. + if (kIsWeb || (isDesktopPlatform() && _args.isNotEmpty)) { + return FletApp( + pageUrl: pageUrl, + assetsDir: assetsDir, + bootScreenName: bootScreenName, + bootScreenOptions: bootScreenOptions, + bootStatus: _bootStatus, + extensions: extensions, + ); + } + return _ProdApp(args: widget.args); + } +} + +/// Production host: runs the embedded Python program alongside [FletApp] over +/// the in-process PythonBridge FFI transport. If the program exits or errors, +/// the failure is surfaced on the boot screen via [_bootStatus]. +class _ProdApp extends StatefulWidget { + final List args; + + const _ProdApp({required this.args}); + + @override + State<_ProdApp> createState() => _ProdAppState(); +} + +class _ProdAppState extends State<_ProdApp> { + @override + void initState() { + super.initState(); + // A completed future means the Python program returned/exited prematurely + // (it normally runs the event loop until the app quits). On process reuse + // runPythonApp() returns a never-completing future, so this never fires. + runPythonApp(widget.args).then((result) { + if (!mounted) return; + _bootStatus.value = BootStatus(BootStage.startingUp, + error: result ?? "The app exited unexpectedly."); + }).catchError((Object e) { + if (!mounted) return; + _bootStatus.value = BootStatus(BootStage.startingUp, error: e.toString()); + }); + } + + @override + Widget build(BuildContext context) { + return FletApp( + pageUrl: pageUrl, + assetsDir: assetsDir, + bootScreenName: bootScreenName, + bootScreenOptions: bootScreenOptions, + bootStatus: _bootStatus, + // PythonBridge-backed protocol channel + dedicated byte channels. + channelBuilder: nrt.channelBuilder, + dataChannelFactory: nrt.dataChannelFactory, + extensions: extensions, + ); + } +} + +/// Persistent boot screen overlay. Renders the boot screen once (so its +/// animation never remounts across boot phases), then fades out when [status] +/// reports `done`. Once dismissed it stays gone — later reconnects are handled +/// by the app's own loading UI. +class _BootOverlay extends StatefulWidget { + final ValueNotifier status; + + const _BootOverlay({required this.status}); + + @override + State<_BootOverlay> createState() => _BootOverlayState(); +} + +class _BootOverlayState extends State<_BootOverlay> { + bool _fadingOut = false; + bool _removed = false; + + @override + void initState() { + super.initState(); + widget.status.addListener(_onStatus); + _onStatus(); + } + + void _onStatus() { + if (_fadingOut || !widget.status.value.done) return; + // With a zero fade duration the AnimatedOpacity below completes + // synchronously, firing onEnd (and its setState) in the middle of this + // widget's own rebuild, which trips the framework's `!_dirty` assert in + // debug mode. Skip the animation and remove the overlay in one step. + final fadeMs = parseInt(bootScreenOptions["fade_out_duration"], 0)!; + setState(() { + _fadingOut = true; + if (fadeMs == 0) _removed = true; + }); + } + + @override + void dispose() { + widget.status.removeListener(_onStatus); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + if (_removed) return const SizedBox.shrink(); + // Fade-out duration (ms) when the app becomes ready; 0 (default) = instant. + final fadeMs = parseInt(bootScreenOptions["fade_out_duration"], 0)!; + return IgnorePointer( + ignoring: _fadingOut, + child: AnimatedOpacity( + opacity: _fadingOut ? 0.0 : 1.0, + duration: Duration(milliseconds: fadeMs), + onEnd: () { + if (_fadingOut && !_removed) setState(() => _removed = true); + }, + // resolveBootScreen is built once here (status changes update the + // message via the screen's own ValueListenableBuilder), so the spinner + // keeps animating across preparing → starting up. + // Use `builder:` rather than `home:` so this MaterialApp creates NO + // Navigator. A MaterialApp with `home` builds a Navigator with + // `reportsRouteUpdateToEngine: true`, which pushes the home route "/" + // to the browser URL on mount — clobbering a cold-start deep link + // (e.g. `/gallery`) before FletApp's real router reads it. The boot + // overlay never navigates, so it doesn't need a Navigator; this keeps + // theme/Directionality while leaving the URL untouched. + child: MaterialApp( + debugShowCheckedModeBanner: false, + builder: (context, _) => resolveBootScreen( + name: bootScreenName, + options: bootScreenOptions, + extensions: extensions, + status: widget.status, + ), + ), + ), + ); + } } Future prepareApp() async { @@ -137,15 +318,20 @@ Future prepareApp() async { _args.remove("--debug"); } - await setupDesktop(hideWindowOnStart: hideWindowOnStart); + // Linux desktop integration tests run under xvfb; waiting for the native + // ready-to-show callback can keep WidgetTester from reaching the remote + // tester connection. + await setupDesktop( + hideWindowOnStart: hideWindowOnStart, + waitUntilReadyToShow: + !(const bool.fromEnvironment("FLET_TEST") && + defaultTargetPlatform == TargetPlatform.linux), + ); if (kIsWeb) { - // web mode - connect via HTTP + // web mode - connect via HTTP. The URL strategy is applied in main() before + // runApp(); doing it here would be too late (see the note there). pageUrl = Uri.base.toString(); - var routeUrlStrategy = getFletRouteUrlStrategy(); - if (routeUrlStrategy == "path") { - usePathUrlStrategy(); - } assetsDir = getAssetsDir(); } else if (_args.isNotEmpty && isDesktopPlatform()) { // developer mode @@ -163,50 +349,49 @@ Future prepareApp() async { } } else { // production mode - // extract app from asset - appDir = await extractAssetZip(assetPath, checkHash: true); - - // set current directory to app path - Directory.current = appDir; + // resolve the app dir from the bundle (Android unpacks app.zip on first launch) + appDir = await nrt.getAppDir(); assetsDir = path.join(appDir, "assets"); - // configure apps DATA and TEMP directories + // configure the app's storage directories WidgetsFlutterBinding.ensureInitialized(); - var appTempPath = (await path_provider.getApplicationCacheDirectory()).path; - var appDataPath = - (await path_provider.getApplicationDocumentsDirectory()).path; - - if (defaultTargetPlatform != TargetPlatform.iOS && - defaultTargetPlatform != TargetPlatform.android) { - // append app name to the path and create dir - PackageInfo packageInfo = await PackageInfo.fromPlatform(); - appDataPath = path.join(appDataPath, "flet", packageInfo.packageName); - if (!await Directory(appDataPath).exists()) { - await Directory(appDataPath).create(recursive: true); - } + // FLET_APP_STORAGE_DATA — durable, app-private; also the cwd. Lives under + // the OS application-support dir (NOT the app bundle, which is read-only), + // so relative file writes / SQLite work and persist across app updates. + var appDataPath = path.join( + (await path_provider.getApplicationSupportDirectory()).path, "data"); + if (!await Directory(appDataPath).exists()) { + await Directory(appDataPath).create(recursive: true); } + Directory.current = appDataPath; + + // FLET_APP_STORAGE_CACHE — regenerable; the OS may purge it. + var appCachePath = (await path_provider.getApplicationCacheDirectory()).path; + // FLET_APP_STORAGE_TEMP — volatile OS temp; may vanish between launches. + var appTempPath = (await path_provider.getTemporaryDirectory()).path; environmentVariables.putIfAbsent("FLET_APP_STORAGE_DATA", () => appDataPath); + environmentVariables.putIfAbsent( + "FLET_APP_STORAGE_CACHE", () => appCachePath); environmentVariables.putIfAbsent("FLET_APP_STORAGE_TEMP", () => appTempPath); - outLogFilename = path.join(appTempPath, "console.log"); + outLogFilename = path.join(appCachePath, "console.log"); environmentVariables.putIfAbsent("FLET_APP_CONSOLE", () => outLogFilename); environmentVariables.putIfAbsent( "FLET_PLATFORM", () => defaultTargetPlatform.name.toLowerCase()); - if (defaultTargetPlatform == TargetPlatform.windows) { - // use TCP on Windows - var tcpPort = await getUnusedPort(); - pageUrl = "tcp://localhost:$tcpPort"; - environmentVariables.putIfAbsent("FLET_SERVER_PORT", () => tcpPort.toString()); - } else { - // use UDS on other platforms - pageUrl = "flet_$pid.sock"; - environmentVariables.putIfAbsent("FLET_SERVER_UDS_PATH", () => pageUrl); - } + // In production we use the in-process dart_bridge FFI transport (no UDS, + // no TCP — Python and Flutter share the process). Two bridges, both + // owned by `native_runtime.dart`: + // protocol bridge — the Flet MsgPack channel (Dart ↔ Python). + // exit bridge — Python-only outbound channel carrying the exit + // code when `sys.exit(code)` is called inside the + // embedded interpreter. Replaces the legacy + // stdout-callback socket. + pageUrl = nrt.initBridges(environmentVariables); } if (!kIsWeb && assetsDir.isNotEmpty) { @@ -217,170 +402,25 @@ Future prepareApp() async { } Future runPythonApp(List args) async { - var argvItems = args.map((a) => "\"${a.replaceAll('"', '\\"')}\""); - var argv = "[${argvItems.isNotEmpty ? argvItems.join(',') : '""'}]"; - var script = pythonScript - .replaceAll("{outLogFilename}", outLogFilename.replaceAll("\\", "\\\\")) - .replaceAll('{module_name}', pythonModuleName) - .replaceAll('{argv}', argv); - - var completer = Completer(); - - ServerSocket outSocketServer; - String socketAddr = ""; - StringBuffer pythonOut = StringBuffer(); - - if (defaultTargetPlatform == TargetPlatform.windows) { - var tcpAddr = "127.0.0.1"; - outSocketServer = await ServerSocket.bind(tcpAddr, 0); + // Process-reuse path: Android may keep the OS process alive across a + // back-button quit and restart only the Dart VM. libdart_bridge stays + // loaded, Python is still up. `initBridges()` already fired + // `dart_bridge_signal_dart_session` with the new ports — Python's + // session-restart handlers have rewired by now. Don't call into + // `SeriousPython.runProgram` again (it would no-op-return immediately + // anyway, but the never-completing-future park here keeps the + // FletApp's existing FutureBuilder rendering until the OS tears us + // down for real). + if (nrt.pythonAlreadyRunning) { debugPrint( - 'Python output TCP Server is listening on port ${outSocketServer.port}'); - socketAddr = "$tcpAddr:${outSocketServer.port}"; - } else { - socketAddr = "stdout_$pid.sock"; - if (await File(socketAddr).exists()) { - await File(socketAddr).delete(); - } - outSocketServer = await ServerSocket.bind( - InternetAddress(socketAddr, type: InternetAddressType.unix), 0); - debugPrint('Python output Socket Server is listening on $socketAddr'); - } - - environmentVariables.putIfAbsent("FLET_PYTHON_CALLBACK_SOCKET_ADDR", () => socketAddr); - - void closeOutServer() async { - outSocketServer.close(); - - int exitCode = int.tryParse(pythonOut.toString().trim()) ?? 0; - - if (exitCode == errorExitCode) { - var out = ""; - if (await File(outLogFilename).exists()) { - out = await File(outLogFilename).readAsString(); - } - completer.complete(out); - } else { - exit(exitCode); - } + "Python already initialized (process reuse) — skipping SeriousPython.runProgram"); + return Completer().future; } - - outSocketServer.listen((client) { - debugPrint( - 'Connection from: ${client.remoteAddress.address}:${client.remotePort}'); - client.listen((data) { - var s = String.fromCharCodes(data); - pythonOut.write(s); - }, onError: (error) { - client.close(); - closeOutServer(); - }, onDone: () { - client.close(); - closeOutServer(); - }); - }); - - // run python async - SeriousPython.runProgram(path.join(appDir, "$pythonModuleName.pyc"), - script: script, environmentVariables: environmentVariables); - - // wait for client connection to close - return completer.future; -} - -class ErrorScreen extends StatelessWidget { - final String title; - final String text; - - const ErrorScreen({super.key, required this.title, required this.text}); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: SafeArea( - child: Container( - padding: const EdgeInsets.all(8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - title, - style: Theme.of(context).textTheme.titleMedium, - ), - TextButton.icon( - onPressed: () { - Clipboard.setData(ClipboardData(text: text)); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Copied to clipboard')), - ); - }, - icon: const Icon( - Icons.copy, - size: 16, - ), - label: const Text("Copy"), - ) - ], - ), - Expanded( - child: SingleChildScrollView( - child: SelectableText(text, - style: Theme.of(context).textTheme.bodySmall), - )) - ], - ), - )), - ); - } -} - -class BootScreen extends StatelessWidget { - const BootScreen({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox( - width: 30, - height: 30, - child: CircularProgressIndicator(strokeWidth: 3), - ), - const SizedBox( - height: 10, - ), - Text(appBootScreenMessage, style: Theme.of(context).textTheme.bodySmall,) - ], - ), - ), - ); - } -} - -class BlankScreen extends StatelessWidget { - const BlankScreen({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return const Scaffold( - body: SizedBox.shrink(), - ); - } -} - -Future getUnusedPort() { - return ServerSocket.bind("127.0.0.1", 0).then((socket) { - var port = socket.port; - socket.close(); - return port; - }); + return nrt.runPython( + moduleName: pythonModuleName, + appDir: appDir, + outLogFilename: outLogFilename, + environmentVariables: environmentVariables, + args: args, + ); } diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/native_runtime.dart b/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/native_runtime.dart new file mode 100644 index 0000000000..e3124dbd24 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/native_runtime.dart @@ -0,0 +1,269 @@ +// Native-only embedded-Python runtime: PythonBridge transport, +// SeriousPython.runProgram, exit-bridge wiring. This file is selected by +// `main.dart`'s conditional import on platforms where `dart:ffi` exists +// (mobile, desktop). On web, `native_runtime_stub.dart` is used instead. +// +// Splitting this out is what lets `flet build web` compile — package +// `serious_python` pulls in `dart:ffi` / `Pointer<…>` types via +// `package:serious_python_platform_interface`, which are not part of the +// web SDK. Importing the module unconditionally from `main.dart` makes +// the web build fail with "Type 'Pointer' not found" et al., regardless +// of `kIsWeb` runtime gates. + +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flet/flet.dart'; +import 'package:flutter/foundation.dart'; +import 'package:path/path.dart' as path; +import 'package:serious_python/bridge.dart'; +import 'package:serious_python/serious_python.dart'; + +import 'python.dart'; + +// In production (embedded) mode the Flet protocol flows over an in-process +// PythonBridge — no socket file, no TCP. `_exitBridge` is a separate bridge +// dedicated to Python's exit-code transmission (replaces the legacy stdout- +// callback socket). Both stay null until [initBridges] runs. +PythonBridge? _bridge; +PythonBridge? _exitBridge; + +/// Allocate the protocol + exit bridges, stamp the required env vars onto +/// [envVars], and return the `dartbridge://` page URL. +/// +/// Also fires `dart_bridge_signal_dart_session` unconditionally. On a fresh +/// start where libdart_bridge hasn't initialized Python yet, the call is a +/// cheap no-op inside the C library. On Android process reuse — where the +/// OS kept this process alive across a Dart VM restart and Python is still +/// loaded with handlers on the previous (now-dead) ports — it dispatches +/// the new port numbers to the running Python session-restart subscribers +/// so they can rewire transparently. See libdart_bridge >= 1.3.0. +String initBridges(Map envVars) { + _bridge = PythonBridge(); + _exitBridge = PythonBridge(); + + // Signal the running Python (if any) about the new Dart native ports. + // The labels here match what `serious_python_run` reconstructs from + // env vars on its own reuse path — keep in sync. + DartBridge.instance.signalDartSession({ + "protocol": _bridge!.port, + "exit": _exitBridge!.port, + }); + + envVars.putIfAbsent("FLET_DART_BRIDGE_PORT", () => _bridge!.port.toString()); + envVars.putIfAbsent( + "FLET_DART_BRIDGE_EXIT_PORT", + () => _exitBridge!.port.toString(), + ); + return "dartbridge://${_bridge!.port}"; +} + +bool get bridgesActive => _bridge != null; + +/// True when libdart_bridge already has an embedded CPython up from a +/// previous Dart VM in the same OS process. On Android the OS may keep +/// the process alive across a back-button exit and restart only the Dart +/// VM on re-launch — this flag lets `runPythonApp` skip +/// `SeriousPython.runProgram` (which would otherwise wedge waiting on a +/// Python interpreter that's already running). Always false on a fresh +/// process, and false when running against pre-1.3.0 libdart_bridge. +bool get pythonAlreadyRunning => DartBridge.instance.isPythonInitialized; + +/// Resolve the bundled app directory (Android unpacks `app.zip` on first +/// launch; desktop/iOS read it in place from the bundle). Wraps +/// `SeriousPython.prepareApp()` so main.dart doesn't have to import the +/// FFI-touching package directly. +Future getAppDir() => SeriousPython.prepareApp(); + +/// FletApp's `channelBuilder` for the embedded-Python protocol — wraps the +/// in-process [PythonBridge] in a [FletBackendChannel]. Returns null until +/// [initBridges] has run. +FletBackendChannelBuilder? get channelBuilder => _bridge == null + ? null + : ({ + required FletBackendChannelOnPacketCallback onPacket, + required FletBackendChannelOnDisconnectCallback onDisconnect, + }) => _DartBridgeBackendChannel( + _bridge!, + onPacket: onPacket, + onDisconnect: onDisconnect, + ); + +/// FletApp's `dataChannelFactory` for high-throughput byte channels — +/// each `open()` mints a fresh [PythonBridge] (dedicated native port). +DataChannelFactory? get dataChannelFactory => _PythonBridgeDataChannelFactory(); + +/// Boot the embedded interpreter and wait for it to exit. Returns the +/// captured console output on error exit; calls `exit(code)` directly on +/// normal exit codes. +Future runPython({ + required String moduleName, + required String appDir, + required String outLogFilename, + required Map environmentVariables, + required List args, +}) async { + // JSON literals are valid Python literals, so every dynamic value is + // spliced into the boot script through jsonEncode: it correctly escapes + // backslashes (Windows paths), quotes, and non-ASCII. + var script = pythonScript + .replaceAll('{outLogFilename}', jsonEncode(outLogFilename)) + .replaceAll('{module_name}', jsonEncode(moduleName)) + .replaceAll('{argv}', jsonEncode(args.isNotEmpty ? args : [""])) + .replaceAll('{host_executable}', jsonEncode(Platform.resolvedExecutable)); + + var completer = Completer(); + + // Subscribe to the exit-code bridge. Python's `sys.exit(code)` is patched + // (in python.dart) to encode `code` as raw UTF-8 bytes and post them via + // `dart_bridge.send_bytes(FLET_DART_BRIDGE_EXIT_PORT, ...)`. We don't need + // a streaming codec here — the channel only ever carries a single short + // payload, then Python tears down. + StringBuffer pythonExitBuf = StringBuffer(); + StreamSubscription? exitSub; + + void onExitSignal() async { + await exitSub?.cancel(); + int exitCode = int.tryParse(pythonExitBuf.toString().trim()) ?? 0; + if (exitCode == errorExitCode) { + var out = ""; + if (await File(outLogFilename).exists()) { + out = await File(outLogFilename).readAsString(); + } + completer.complete(out); + } else { + exit(exitCode); + } + } + + exitSub = _exitBridge!.messages.listen( + (data) { + pythonExitBuf.write(String.fromCharCodes(data)); + onExitSignal(); + }, + onError: (error) { + debugPrint('Exit bridge error: $error'); + onExitSignal(); + }, + onDone: onExitSignal, + cancelOnError: false, + ); + + SeriousPython.runProgram( + path.join(appDir, "$moduleName.pyc"), + script: script, + environmentVariables: environmentVariables, + ); + + return completer.future; +} + +/// `FletBackendChannel` implementation backed by a [PythonBridge]. Bytes +/// flow Dart↔Python entirely in-process; no Unix socket, no kernel context +/// switch. Each PythonBridge `send` is one complete packet on the wire — +/// `[type:u8][payload]`. No framing layer needed (the bridge preserves +/// message boundaries). +class _DartBridgeBackendChannel implements FletBackendChannel { + _DartBridgeBackendChannel( + this._bridge, { + required FletBackendChannelOnPacketCallback onPacket, + required FletBackendChannelOnDisconnectCallback onDisconnect, + }) : _onPacket = onPacket, + _onDisconnect = onDisconnect; + + final PythonBridge _bridge; + final FletBackendChannelOnPacketCallback _onPacket; + final FletBackendChannelOnDisconnectCallback _onDisconnect; + StreamSubscription? _subscription; + + @override + Future connect() async { + _subscription = _bridge.messages.listen( + _onPacket, + onError: (error, stack) { + debugPrint("PythonBridge stream error: $error"); + _onDisconnect(); + }, + onDone: () { + debugPrint("PythonBridge stream closed."); + _onDisconnect(); + }, + cancelOnError: false, + ); + } + + @override + void send(Uint8List packet) { + // Retry loop covers the brief startup window where Python hasn't yet + // called `dart_bridge.set_enqueue_handler_func` — bridge.send returns + // false in that case. Once Flet's app.py registers the handler (which + // happens before `runpy.run_module` is dispatched), bridge.send returns + // true synchronously. + if (_bridge.send(packet)) return; + _retrySend(packet); + } + + void _retrySend(Uint8List packet) { + const interval = Duration(milliseconds: 50); + const deadline = Duration(seconds: 30); + final start = DateTime.now(); + Timer.periodic(interval, (timer) { + if (_bridge.send(packet)) { + timer.cancel(); + } else if (DateTime.now().difference(start) > deadline) { + timer.cancel(); + debugPrint( + "PythonBridge send timed out: Python handler never registered.", + ); + } + }); + } + + @override + bool get isLocalConnection => true; + + @override + int get defaultReconnectIntervalMs => 0; + + @override + void disconnect() { + _subscription?.cancel(); + _subscription = null; + } +} + +/// [DataChannel] backed by a dedicated [PythonBridge] — fast path for +/// embedded native mode. Each open() mints a fresh bridge with its own +/// native port; the bridge's `port` becomes the channel id we propagate +/// to Python (via the widget's `data_channel_open` event). +class _PythonBridgeDataChannel implements DataChannel { + _PythonBridgeDataChannel(this._bridge); + final PythonBridge _bridge; + bool _closed = false; + + @override + int get id => _bridge.port; + + @override + Stream get messages => _bridge.messages; + + @override + bool send(Uint8List bytes) { + if (_closed) return false; + return _bridge.send(bytes); + } + + @override + void close() { + if (_closed) return; + _closed = true; + _bridge.close(); + } +} + +class _PythonBridgeDataChannelFactory implements DataChannelFactory { + @override + DataChannel open() => _PythonBridgeDataChannel(PythonBridge()); +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/native_runtime_stub.dart b/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/native_runtime_stub.dart new file mode 100644 index 0000000000..dbfc67f390 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/native_runtime_stub.dart @@ -0,0 +1,33 @@ +// Web stub for `native_runtime.dart`. Selected by `main.dart`'s conditional +// import on platforms where `dart:ffi` is NOT available (web). +// +// All callers must guard with `kIsWeb` so the real native_runtime entry +// points are never invoked on web — but the stubs still need to exist for +// the file to compile. + +import 'package:flet/flet.dart'; + +String initBridges(Map envVars) => + throw UnsupportedError("Native bridges not available on web"); + +bool get bridgesActive => false; + +/// Always false on web — there's no embedded CPython to be "already +/// running". Mirrors `native_runtime.dart`'s getter so `main.dart`'s +/// process-reuse check compiles for the web target. +bool get pythonAlreadyRunning => false; + +Future getAppDir() => + throw UnsupportedError("App directory not available on web"); + +FletBackendChannelBuilder? get channelBuilder => null; + +DataChannelFactory? get dataChannelFactory => null; + +Future runPython({ + required String moduleName, + required String appDir, + required String outLogFilename, + required Map environmentVariables, + required List args, +}) => throw UnsupportedError("Native runtime not available on web"); diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/python.dart b/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/python.dart index 770dff1818..b141272535 100644 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/python.dart +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/python.dart @@ -1,7 +1,8 @@ const errorExitCode = 100; -const pythonScript = """ -import os, runpy, socket, sys, traceback +const pythonScript = + """ +import importlib.util, os, sys, traceback, types # fix for cryptography package os.environ["CRYPTOGRAPHY_OPENSSL_NO_LEGACY"] = "1" @@ -53,32 +54,168 @@ def initialize_ctypes(): ctypes.CDLL.__init__ = CDLL_init_override -initialize_ctypes() - -out_file = open("{outLogFilename}", "w+", buffering=1) -callback_socket_addr = os.getenv("FLET_PYTHON_CALLBACK_SOCKET_ADDR") -if ":" in callback_socket_addr: - addr, port = callback_socket_addr.split(":") - callback_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - callback_socket.connect((addr, int(port))) -else: - callback_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - callback_socket.connect(callback_socket_addr) +initialize_ctypes() -sys.stdout = sys.stderr = out_file +out_file = open( + {outLogFilename}, + "w+", + buffering=1, + encoding="utf-8", + errors="backslashreplace", # prevents encoding failures +) + +# libdart_bridge >= 1.3.0 installs native-log file-like wrappers as +# sys.stdout / sys.stderr right after Py_Initialize so prints land in +# logcat (Android) / os_log (iOS) / stderr (desktop). Tee here so the +# error-screen capture file ALSO gets the output — both paths matter. +# On older libdart_bridge (no native install) `_native_*` will be the +# default text streams; the tee still works as a plain duplicate write. +_native_stdout = sys.stdout +_native_stderr = sys.stderr + + +class _TeeWriter: + # The file half receives writes raw — preserves byte-for-byte parity + # with what Python wrote, so the error-screen capture file matches a + # plain `python` console run. + # + # The native (logcat / os_log) half is line-buffered so Python's + # `print(x)` doesn't produce two log entries — CPython implements + # `print` as `write(text)` + `write("\\n")`, and the standalone + # newline write would otherwise show as a blank logcat row after + # every print. We accumulate until we see "\\n", emit the line + # without the trailing newline, and skip purely empty lines (so + # `print()` with no args also stays out of the log). + def __init__(self, native, file_): + self._native = native + self._file = file_ + self._native_buf = "" + + def write(self, text): + if not text: + return 0 + try: + self._native_buf += text + while True: + nl = self._native_buf.find("\\n") + if nl < 0: + break + line = self._native_buf[:nl] + self._native_buf = self._native_buf[nl + 1:] + if line: + self._native.write(line) + except Exception: + pass + return self._file.write(text) + + def flush(self): + try: + # Drain any pending partial line (no trailing newline in the + # source stream — could happen if the user app calls + # `sys.stdout.flush()` mid-line). + if self._native_buf: + self._native.write(self._native_buf) + self._native_buf = "" + self._native.flush() + except Exception: + pass + self._file.flush() + + def isatty(self): + return False + + def fileno(self): + return self._file.fileno() + +sys.stdout = _TeeWriter(_native_stdout, out_file) +sys.stderr = _TeeWriter(_native_stderr, out_file) + +# Exit-code transport. The Dart side allocated a dedicated PythonBridge port +# (FLET_DART_BRIDGE_EXIT_PORT) and is listening on it. `flet_exit` posts the +# exit code as raw UTF-8 bytes through that bridge — the Dart side parses, +# then either renders the error screen (code == $errorExitCode) or terminates +# the host process (any other code) using the file we wrote to above. +# +# On Android process reuse (Dart VM restarts while libdart_bridge stays +# loaded), the exit-bridge port number changes. We keep `_exit_port` in a +# one-element list so the session-restart handler below can mutate it in +# place — `flet_exit` always reads the current value. +import dart_bridge # built-in module provided by libdart_bridge +_exit_port = [int(os.environ["FLET_DART_BRIDGE_EXIT_PORT"])] def flet_exit(code=0): - callback_socket.sendall(str(code).encode()) - out_file.close() - callback_socket.close() + try: + dart_bridge.send_bytes(_exit_port[0], str(code).encode()) + finally: + out_file.close() sys.exit = flet_exit +# Subscribe to new-Dart-VM signals if the running libdart_bridge supports +# them (>= 1.3.0). On process reuse, the new VM's port-map carries the +# fresh exit-bridge port number; rewire so flet_exit talks to the right +# Dart side. Older libdart_bridge doesn't expose the handler — fall +# through silently and the existing single-VM behaviour holds. +_add_restart = getattr(dart_bridge, "add_session_restart_handler", None) +if _add_restart is not None: + def _on_dart_session_restart(port_map): + new_exit = port_map.get("exit") + if new_exit is not None: + _exit_port[0] = int(new_exit) + _add_restart(_on_dart_session_restart) + + +def _sp_run_module_as_main(module_name): + # Execute with `python -m module_name` semantics, but inside the real + # sys.modules["__main__"]. `runpy.run_module(..., run_name="__main__")` + # isn't used here, as it uses a temporary namespace, causing pickle/multiprocessing + # not to reliably resolve top-level functions from the app module. + spec = importlib.util.find_spec(module_name) + if spec is None: + raise ImportError("module %r not found" % module_name) + + if spec.submodule_search_locations is not None: + # Package case: `python -m pkg` executes pkg.__main__. + main_name = module_name + ".__main__" + spec = importlib.util.find_spec(main_name) + if spec is None: + raise ImportError( + "%r is a package and cannot be directly executed: " + "no %r module" % (module_name, main_name) + ) + + if spec.loader is None or not hasattr(spec.loader, "get_code"): + raise ImportError("module %r cannot be executed" % module_name) + + code = spec.loader.get_code(spec.name) + if code is None: + raise ImportError("module %r has no executable Python code" % module_name) + + main = types.ModuleType("__main__") + main.__dict__.update( + __spec__=spec, + __file__=spec.origin, + __cached__=spec.cached, + __loader__=spec.loader, + __package__=spec.parent, + __builtins__=__builtins__, + ) + + sys.modules["__main__"] = main + sys.modules["__mp_main__"] = main # Match multiprocessing's spawn alias for the main module. + + # Prevent re-exec'd multiprocessing children from inheriting PYTHONINSPECT, or + # they may stay open in interactive mode after their command finishes. + os.environ.pop("PYTHONINSPECT", None) + + exec(code, main.__dict__) + + ex = None try: import certifi - + os.environ["REQUESTS_CA_BUNDLE"] = certifi.where() os.environ["SSL_CERT_FILE"] = certifi.where() @@ -95,10 +232,21 @@ try: ssl._create_default_https_context = create_default_context sys.argv = {argv} - runpy.run_module("{module_name}", run_name="__main__") + + # multiprocessing spawn/forkserver children re-execute sys.executable. In a + # packaged Flet app, that must be the host app binary, whose native runner + # detects multiprocessing argv and runs Python headlessly instead of opening + # another GUI window. Set it before user code can import multiprocessing, + # because multiprocessing snapshots the executable during import. + if _sp_host_exe := {host_executable}: + sys.executable = _sp_host_exe + sys._base_executable = _sp_host_exe + + # Execute the configured app module as the real __main__ module. + _sp_run_module_as_main({module_name}) except Exception as e: ex = e traceback.print_exception(e) -sys.exit(0 if ex is None else 100) +sys.exit(0 if ex is None else $errorExitCode) """; diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/CMakeLists.txt b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/CMakeLists.txt index c72838044f..208fce2ac7 100644 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/CMakeLists.txt +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/CMakeLists.txt @@ -73,6 +73,9 @@ apply_standard_settings(${BINARY_NAME}) # Add dependency libraries. Add any application-specific dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter) target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +# dlopen/dlsym for main.cc's multiprocessing child interception +# (a no-op with glibc >= 2.34, where libdl is merged into libc). +target_link_libraries(${BINARY_NAME} PRIVATE ${CMAKE_DL_LIBS}) # Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/main.cc b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/main.cc index e7c5c54370..f89420aa49 100644 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/main.cc +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/main.cc @@ -1,6 +1,52 @@ #include "my_application.h" +#include + +// Python's multiprocessing spawn/forkserver paths, including the resource +// tracker, create child processes by re-executing sys.executable with a +// CPython-style command line. In a flet-built Linux app, sys.executable is this +// app binary. Detect that argv shape before GTK/Flutter initialization and run +// the embedded interpreter headlessly instead of starting another GUI app. +// See: https://github.com/flet-dev/flet/issues/4283 +// +// These optional entry points live in libdart_bridge.so. Load the bridge early +// and resolve them dynamically so apps built with older dart_bridge versions +// still launch; they just won't have multiprocessing child interception. +// +// Returns true when this process was handled as a multiprocessing child. In +// that case, exit_code receives the interpreter process exit code. +static bool maybe_run_python_child(int argc, char** argv, int& exit_code) { + typedef int (*sp_argv_fn)(int, char**); + + // The shared library, and its Python dependency, would be loaded moments + // later by the plugin anyway, so eagerly loading it here does not add + // meaningful cost to the normal startup path. + void* bridge = dlopen("libdart_bridge.so", RTLD_NOW); + if (!bridge) { + return false; + } + + auto is_mp_invocation = reinterpret_cast( + dlsym(bridge, "serious_python_is_mp_invocation")); + auto run_python_main = + reinterpret_cast(dlsym(bridge, "serious_python_main")); + + if (is_mp_invocation && run_python_main && + is_mp_invocation(argc, argv) != 0) { + exit_code = run_python_main(argc, argv); + return true; + } + + return false; +} + int main(int argc, char** argv) { + // Multiprocessing child re-exec? Run it headlessly and exit, instead of starting Flutter GUI. + int mp_exit_code = 0; + if (maybe_run_python_child(argc, argv, mp_exit_code)) { + return mp_exit_code; + } + g_autoptr(MyApplication) app = my_application_new(); return g_application_run(G_APPLICATION(app), argc, argv); } diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/my_application.cc b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/my_application.cc index 633f33c6dc..7b0dd02c37 100644 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/my_application.cc +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/my_application.cc @@ -57,6 +57,11 @@ static void my_application_activate(GApplication* application) { gtk_widget_show(GTK_WIDGET(view)); gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + // Realize the Flutter view while the top-level window is still hidden; this + // lets Flutter render its first frames and lets integration tests attach + // before Dart decides whether the app window should be shown. + gtk_widget_realize(GTK_WIDGET(view)); + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); gtk_widget_grab_focus(GTK_WIDGET(view)); diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcodeproj/project.pbxproj b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcodeproj/project.pbxproj index bb413260d2..bbcba4a34e 100644 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcodeproj/project.pbxproj +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F12044A3C60003C046 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C046 /* main.swift */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; @@ -69,6 +70,7 @@ 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; 33CC10ED2044A3C60003C045 /* {{ cookiecutter.artifact_name }}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "{{ cookiecutter.artifact_name }}.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F02044A3C60003C046 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; @@ -166,6 +168,7 @@ isa = PBXGroup; children = ( 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC10F02044A3C60003C046 /* main.swift */, 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, 33E51913231747F40026EE4D /* DebugProfile.entitlements */, 33E51914231749380026EE4D /* Release.entitlements */, @@ -370,6 +373,7 @@ files = ( 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 33CC10F12044A3C60003C046 /* main.swift in Sources */, 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/AppDelegate.swift b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/AppDelegate.swift index b3c1761412..1c86ba9ccc 100644 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/AppDelegate.swift +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/AppDelegate.swift @@ -1,7 +1,8 @@ import Cocoa import FlutterMacOS -@main +// See main.swift for the entry point. + class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/main.swift b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/main.swift new file mode 100644 index 0000000000..7873ebf383 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/main.swift @@ -0,0 +1,38 @@ +import Cocoa + +// Python's multiprocessing spawn/forkserver paths, including the resource +// tracker, create child processes by re-executing sys.executable with a +// CPython-style command line. In a flet-built macOS app, sys.executable is this +// app binary. Detect that argv shape before AppKit/Flutter initialization and +// run the embedded interpreter headlessly instead of starting another GUI app. +// See: https://github.com/flet-dev/flet/issues/4283 +// +// These optional entry points live in dart_bridge, which is force-loaded into +// the host binary by serious_python_darwin. Resolve them dynamically from the +// current process image, similar to Dart FFI's DynamicLibrary.process(), so apps +// built with older dart_bridge versions still link and launch; they just won't +// have multiprocessing child interception. +private typealias SPArgvFn = @convention(c) ( + Int32, UnsafeMutablePointer?>? +) -> Int32 + +private let processHandle = dlopen(nil, RTLD_NOW) + +private func spResolve(_ name: String) -> SPArgvFn? { + guard let processHandle, + let sym = dlsym(processHandle, name) else { + return nil + } + return unsafeBitCast(sym, to: SPArgvFn.self) +} + +if let isMpInvocation = spResolve("serious_python_is_mp_invocation"), + let runPythonMain = spResolve("serious_python_main"), + isMpInvocation(CommandLine.argc, CommandLine.unsafeArgv) != 0 +{ + exit(runPythonMain(CommandLine.argc, CommandLine.unsafeArgv)) +} + +// Not a multiprocessing child process, or the interception hooks are unavailable: +// continue with the normal macOS Flutter app launch. +_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv) diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/pubspec.yaml b/sdk/python/templates/build/{{cookiecutter.out_dir}}/pubspec.yaml index 243eed7c66..430ccd15db 100644 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/pubspec.yaml +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/pubspec.yaml @@ -17,23 +17,23 @@ dependencies: flet: path: ../../../../../packages/flet - serious_python: 1.0.1 + + serious_python: 4.3.2 + + # MsgPack codec used by the dart_bridge FletBackendChannel implementation + # in lib/main.dart — matches the wire format flet's existing socket + # transport already speaks. + msgpack_dart: ^1.0.1 package_info_plus: ^9.0.0 path_provider: ^2.1.4 path: ^1.9.0 window_manager: ^0.5.1 -# {% if 'flet_geolocator' in cookiecutter.flutter.dependencies %} -# geolocator: ^12.0.0 -# geolocator_android: ^4.6.0 -# {% endif %} - dependency_overrides: flet: path: ../../../../../packages/flet - device_info_plus: 12.3.0 # remove that in May, 2026 once CI moved to macOS 26 - connectivity_plus: 7.0.0 # remove that in May, 2026 once CI moved to macOS 26 + screen_retriever: 0.2.1 # this one migrated to SPM, but 0.2.0 is used by some other packages dev_dependencies: flutter_launcher_icons: ^0.14.1 @@ -44,9 +44,9 @@ flutter: uses-material-design: true - assets: - - app/app.zip - - app/app.zip.hash + # The web (Pyodide) build gets `assets:` with app/app.zip injected here by + # `flet build`; on native platforms the app ships unpacked inside the bundle + # (placed by serious_python's platform build), so there is no app.zip asset. # dart run flutter_launcher_icons flutter_launcher_icons: diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/index.html b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/index.html index 53bb5e3961..891ee2f47d 100644 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/index.html +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/index.html @@ -29,7 +29,16 @@ assetBase: "{{ cookiecutter.base_url }}", routeUrlStrategy: "{{ cookiecutter.route_url_strategy }}", canvasKitBaseUrl: "/canvaskit/", - pyodideUrl: "/pyodide/pyodide.js", + // .mjs is required: python-worker.js is a module worker and loads + // the runtime via dynamic `import()`. Pyodide >= 0.29 also refuses + // to run in classic workers. Use the local copy that `flet build` + // drops into web/pyodide/ when --no-cdn is set; otherwise pull + // from jsdelivr so the build artifact can stay slim. + {% if cookiecutter.no_cdn == "True" %} + pyodideUrl: "/pyodide/pyodide.mjs", + {% else %} + pyodideUrl: "https://cdn.jsdelivr.net/pyodide/v{{ cookiecutter.pyodide_version }}/full/pyodide.mjs", + {% endif %} pythonModuleName: "{{ cookiecutter.python_module_name }}", webRenderer: "{{ cookiecutter.web_renderer }}", fontFallbackBaseUrl: "assets/fonts/", // for Noto Emoji, use Google CDN diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/ffi.d.ts b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/ffi.d.ts deleted file mode 100644 index d734a5b4f3..0000000000 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/ffi.d.ts +++ /dev/null @@ -1,1127 +0,0 @@ -// Generated by dts-bundle-generator v8.1.2 - -export type TypedArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array; -interface PyProxy { - [x: string]: any; -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` is an object that allows idiomatic use of a Python object from - * JavaScript. See :ref:`type-translations-pyproxy`. - */ -declare class PyProxy { - /** @private */ - $$flags: number; - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; - /** - * @hideconstructor - */ - constructor(); - /** @hidden */ - get [Symbol.toStringTag](): string; - /** - * The name of the type of the object. - * - * Usually the value is ``"module.name"`` but for builtins or - * interpreter-defined types it is just ``"name"``. As pseudocode this is: - * - * .. code-block:: python - * - * ty = type(x) - * if ty.__module__ == 'builtins' or ty.__module__ == "__main__": - * return ty.__name__ - * else: - * ty.__module__ + "." + ty.__name__ - * - */ - get type(): string; - /** - * Returns `str(o)` (unless `pyproxyToStringRepr: true` was passed to - * :js:func:`~globalThis.loadPyodide` in which case it will return `repr(o)`) - */ - toString(): string; - /** - * Destroy the :js:class:`~pyodide.ffi.PyProxy`. This will release the memory. Any further attempt - * to use the object will raise an error. - * - * In a browser supporting :js:data:`FinalizationRegistry`, Pyodide will - * automatically destroy the :js:class:`~pyodide.ffi.PyProxy` when it is garbage collected, however - * there is no guarantee that the finalizer will be run in a timely manner so - * it is better to destroy the proxy explicitly. - * - * @param options - * @param options.message The error message to print if use is attempted after - * destroying. Defaults to "Object has already been destroyed". - * - */ - destroy(options?: { - message?: string; - destroyRoundtrip?: boolean; - }): void; - /** - * Make a new :js:class:`~pyodide.ffi.PyProxy` pointing to the same Python object. - * Useful if the :js:class:`~pyodide.ffi.PyProxy` is destroyed somewhere else. - */ - copy(): PyProxy; - /** - * Converts the :js:class:`~pyodide.ffi.PyProxy` into a JavaScript object as best as possible. By - * default does a deep conversion, if a shallow conversion is desired, you can - * use ``proxy.toJs({depth : 1})``. See :ref:`Explicit Conversion of PyProxy - * ` for more info. - * @param options - * @return The JavaScript object resulting from the conversion. - */ - toJs({ depth, pyproxies, create_pyproxies, dict_converter, default_converter, eager_converter, }?: { - /** How many layers deep to perform the conversion. Defaults to infinite */ - depth?: number; - /** - * If provided, :js:meth:`toJs` will store all PyProxies created in this - * list. This allows you to easily destroy all the PyProxies by iterating - * the list without having to recurse over the generated structure. The most - * common use case is to create a new empty list, pass the list as - * ``pyproxies``, and then later iterate over ``pyproxies`` to destroy all of - * created proxies. - */ - pyproxies?: PyProxy[]; - /** - * If false, :js:meth:`toJs` will throw a - * :py:exc:`~pyodide.ffi.ConversionError` rather than producing a - * :js:class:`~pyodide.ffi.PyProxy`. - */ - create_pyproxies?: boolean; - /** - * A function to be called on an iterable of pairs ``[key, value]``. Convert - * this iterable of pairs to the desired output. For instance, - * :js:func:`Object.fromEntries` would convert the dict to an object, - * :js:func:`Array.from` converts it to an :js:class:`Array` of pairs, and - * ``(it) => new Map(it)`` converts it to a :js:class:`Map` (which is the - * default behavior). - */ - dict_converter?: (array: Iterable<[ - key: string, - value: any - ]>) => any; - /** - * Optional argument to convert objects with no default conversion. See the - * documentation of :meth:`~pyodide.ffi.to_js`. - */ - default_converter?: (obj: PyProxy, convert: (obj: PyProxy) => any, cacheConversion: (obj: PyProxy, result: any) => void) => any; - /** - * Optional callback to convert objects which gets called after ``str``, - * ``int``, ``float``, ``bool``, ``None``, and ``JsProxy`` are converted but - * *before* any default conversions are applied to standard data structures. - * - * Its arguments are the same as `dict_converter`. - * See the documentation of :meth:`~pyodide.ffi.to_js`. - */ - eager_converter?: (obj: PyProxy, convert: (obj: PyProxy) => any, cacheConversion: (obj: PyProxy, result: any) => void) => any; - }): any; -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object has a :meth:`~object.__len__` - * method. - */ -declare class PyProxyWithLength extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -interface PyProxyWithLength extends PyLengthMethods { -} -declare class PyLengthMethods { - /** - * The length of the object. - */ - get length(): number; -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object has a - * :meth:`~object.__getitem__` method. - */ -declare class PyProxyWithGet extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -interface PyProxyWithGet extends PyGetItemMethods { -} -declare class PyGetItemMethods { - /** - * This translates to the Python code ``obj[key]``. - * - * @param key The key to look up. - * @returns The corresponding value. - */ - get(key: any): any; - /** - * Returns the object treated as a json adaptor. - * - * With a JsonAdaptor: - * 1. property access / modification / deletion is implemented with - * :meth:`~object.__getitem__`, :meth:`~object.__setitem__`, and - * :meth:`~object.__delitem__` respectively. - * 2. If an attribute is accessed and the result implements - * :meth:`~object.__getitem__` then the result will also be a json - * adaptor. - * - * For instance, ``JSON.stringify(proxy.asJsJson())`` acts like an - * inverse to Python's :py:func:`json.loads`. - */ - asJsJson(): PyProxy & {}; -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object has a - * :meth:`~object.__setitem__` or :meth:`~object.__delitem__` method. - */ -declare class PyProxyWithSet extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -interface PyProxyWithSet extends PySetItemMethods { -} -declare class PySetItemMethods { - /** - * This translates to the Python code ``obj[key] = value``. - * - * @param key The key to set. - * @param value The value to set it to. - */ - set(key: any, value: any): void; - /** - * This translates to the Python code ``del obj[key]``. - * - * @param key The key to delete. - */ - delete(key: any): void; -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object has a - * :meth:`~object.__contains__` method. - */ -declare class PyProxyWithHas extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -interface PyProxyWithHas extends PyContainsMethods { -} -declare class PyContainsMethods { - /** - * This translates to the Python code ``key in obj``. - * - * @param key The key to check for. - * @returns Is ``key`` present? - */ - has(key: any): boolean; -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is :std:term:`iterable` - * (i.e., it has an :meth:`~object.__iter__` method). - */ -declare class PyIterable extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -interface PyIterable extends PyIterableMethods { -} -declare class PyIterableMethods { - /** - * This translates to the Python code ``iter(obj)``. Return an iterator - * associated to the proxy. See the documentation for - * :js:data:`Symbol.iterator`. - * - * This will be used implicitly by ``for(let x of proxy){}``. - */ - [Symbol.iterator](): Iterator; -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is :std:term:`asynchronous - * iterable` (i.e., has an :meth:`~object.__aiter__` method). - */ -declare class PyAsyncIterable extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -interface PyAsyncIterable extends PyAsyncIterableMethods { -} -declare class PyAsyncIterableMethods { - /** - * This translates to the Python code ``aiter(obj)``. Return an async iterator - * associated to the proxy. See the documentation for :js:data:`Symbol.asyncIterator`. - * - * This will be used implicitly by ``for(await let x of proxy){}``. - */ - [Symbol.asyncIterator](): AsyncIterator; -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is an :term:`iterator` - * (i.e., has a :meth:`~generator.send` or :meth:`~iterator.__next__` method). - */ -declare class PyIterator extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -interface PyIterator extends PyIteratorMethods { -} -declare class PyIteratorMethods { - /** @private */ - [Symbol.iterator](): this; - /** - * This translates to the Python code ``next(obj)``. Returns the next value of - * the generator. See the documentation for :js:meth:`Generator.next` The - * argument will be sent to the Python generator. - * - * This will be used implicitly by ``for(let x of proxy){}``. - * - * @param arg The value to send to the generator. The value will be assigned - * as a result of a yield expression. - * @returns An Object with two properties: ``done`` and ``value``. When the - * generator yields ``some_value``, ``next`` returns ``{done : false, value : - * some_value}``. When the generator raises a :py:exc:`StopIteration` - * exception, ``next`` returns ``{done : true, value : result_value}``. - */ - next(arg?: any): IteratorResult; -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is a :std:term:`generator` - * (i.e., it is an instance of :py:class:`~collections.abc.Generator`). - */ -declare class PyGenerator extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -interface PyGenerator extends PyGeneratorMethods { -} -declare class PyGeneratorMethods { - /** - * Throws an exception into the Generator. - * - * See the documentation for :js:meth:`Generator.throw`. - * - * @param exc Error The error to throw into the generator. Must be an - * instanceof ``Error``. - * @returns An Object with two properties: ``done`` and ``value``. When the - * generator yields ``some_value``, ``return`` returns ``{done : false, value - * : some_value}``. When the generator raises a - * ``StopIteration(result_value)`` exception, ``return`` returns ``{done : - * true, value : result_value}``. - */ - throw(exc: any): IteratorResult; - /** - * Throws a :py:exc:`GeneratorExit` into the generator and if the - * :py:exc:`GeneratorExit` is not caught returns the argument value ``{done: - * true, value: v}``. If the generator catches the :py:exc:`GeneratorExit` and - * returns or yields another value the next value of the generator this is - * returned in the normal way. If it throws some error other than - * :py:exc:`GeneratorExit` or :py:exc:`StopIteration`, that error is propagated. See - * the documentation for :js:meth:`Generator.return`. - * - * @param v The value to return from the generator. - * @returns An Object with two properties: ``done`` and ``value``. When the - * generator yields ``some_value``, ``return`` returns ``{done : false, value - * : some_value}``. When the generator raises a - * ``StopIteration(result_value)`` exception, ``return`` returns ``{done : - * true, value : result_value}``. - */ - return(v: any): IteratorResult; -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is an - * :std:term:`asynchronous iterator` - */ -declare class PyAsyncIterator extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -interface PyAsyncIterator extends PyAsyncIteratorMethods { -} -declare class PyAsyncIteratorMethods { - /** @private */ - [Symbol.asyncIterator](): this; - /** - * This translates to the Python code ``anext(obj)``. Returns the next value - * of the asynchronous iterator. The argument will be sent to the Python - * iterator (if it's a generator for instance). - * - * This will be used implicitly by ``for(let x of proxy){}``. - * - * @param arg The value to send to a generator. The value will be assigned as - * a result of a yield expression. - * @returns An Object with two properties: ``done`` and ``value``. When the - * iterator yields ``some_value``, ``next`` returns ``{done : false, value : - * some_value}``. When the giterator is done, ``next`` returns - * ``{done : true }``. - */ - next(arg?: any): Promise>; -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is an - * :std:term:`asynchronous generator` (i.e., it is an instance of - * :py:class:`~collections.abc.AsyncGenerator`) - */ -declare class PyAsyncGenerator extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -interface PyAsyncGenerator extends PyAsyncGeneratorMethods { -} -declare class PyAsyncGeneratorMethods { - /** - * Throws an exception into the Generator. - * - * See the documentation for :js:meth:`AsyncGenerator.throw`. - * - * @param exc Error The error to throw into the generator. Must be an - * instanceof ``Error``. - * @returns An Object with two properties: ``done`` and ``value``. When the - * generator yields ``some_value``, ``return`` returns ``{done : false, value - * : some_value}``. When the generator raises a - * ``StopIteration(result_value)`` exception, ``return`` returns ``{done : - * true, value : result_value}``. - */ - throw(exc: any): Promise>; - /** - * Throws a :py:exc:`GeneratorExit` into the generator and if the - * :py:exc:`GeneratorExit` is not caught returns the argument value ``{done: - * true, value: v}``. If the generator catches the :py:exc:`GeneratorExit` and - * returns or yields another value the next value of the generator this is - * returned in the normal way. If it throws some error other than - * :py:exc:`GeneratorExit` or :py:exc:`StopAsyncIteration`, that error is - * propagated. See the documentation for :js:meth:`AsyncGenerator.throw` - * - * @param v The value to return from the generator. - * @returns An Object with two properties: ``done`` and ``value``. When the - * generator yields ``some_value``, ``return`` returns ``{done : false, value - * : some_value}``. When the generator raises a :py:exc:`StopAsyncIteration` - * exception, ``return`` returns ``{done : true, value : result_value}``. - */ - return(v: any): Promise>; -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is an - * :py:class:`~collections.abc.Sequence` (i.e., a :py:class:`list`) - */ -declare class PySequence extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -interface PySequence extends PySequenceMethods { -} -declare class PySequenceMethods { - /** @hidden */ - get [Symbol.isConcatSpreadable](): boolean; - /** - * See :js:meth:`Array.join`. The :js:meth:`Array.join` method creates and - * returns a new string by concatenating all of the elements in the - * :py:class:`~collections.abc.Sequence`. - * - * @param separator A string to separate each pair of adjacent elements of the - * Sequence. - * - * @returns A string with all Sequence elements joined. - */ - join(separator?: string): string; - /** - * See :js:meth:`Array.slice`. The :js:meth:`Array.slice` method returns a - * shallow copy of a portion of a :py:class:`~collections.abc.Sequence` into a - * new array object selected from ``start`` to ``stop`` (`stop` not included) - * @param start Zero-based index at which to start extraction. Negative index - * counts back from the end of the Sequence. - * @param stop Zero-based index at which to end extraction. Negative index - * counts back from the end of the Sequence. - * @returns A new array containing the extracted elements. - */ - slice(start?: number, stop?: number): any; - /** - * See :js:meth:`Array.lastIndexOf`. Returns the last index at which a given - * element can be found in the Sequence, or -1 if it is not present. - * @param elt Element to locate in the Sequence. - * @param fromIndex Zero-based index at which to start searching backwards, - * converted to an integer. Negative index counts back from the end of the - * Sequence. - * @returns The last index of the element in the Sequence; -1 if not found. - */ - lastIndexOf(elt: any, fromIndex?: number): number; - /** - * See :js:meth:`Array.indexOf`. Returns the first index at which a given - * element can be found in the Sequence, or -1 if it is not present. - * @param elt Element to locate in the Sequence. - * @param fromIndex Zero-based index at which to start searching, converted to - * an integer. Negative index counts back from the end of the Sequence. - * @returns The first index of the element in the Sequence; -1 if not found. - */ - indexOf(elt: any, fromIndex?: number): number; - /** - * See :js:meth:`Array.forEach`. Executes a provided function once for each - * ``Sequence`` element. - * @param callbackfn A function to execute for each element in the ``Sequence``. Its - * return value is discarded. - * @param thisArg A value to use as ``this`` when executing ``callbackFn``. - */ - forEach(callbackfn: (elt: any) => void, thisArg?: any): void; - /** - * See :js:meth:`Array.map`. Creates a new array populated with the results of - * calling a provided function on every element in the calling ``Sequence``. - * @param callbackfn A function to execute for each element in the ``Sequence``. Its - * return value is added as a single element in the new array. - * @param thisArg A value to use as ``this`` when executing ``callbackFn``. - */ - map(callbackfn: (elt: any, index: number, array: any) => U, thisArg?: any): U[]; - /** - * See :js:meth:`Array.filter`. Creates a shallow copy of a portion of a given - * ``Sequence``, filtered down to just the elements from the given array that pass - * the test implemented by the provided function. - * @param predicate A function to execute for each element in the array. It - * should return a truthy value to keep the element in the resulting array, - * and a falsy value otherwise. - * @param thisArg A value to use as ``this`` when executing ``predicate``. - */ - filter(predicate: (elt: any, index: number, array: any) => boolean, thisArg?: any): any[]; - /** - * See :js:meth:`Array.some`. Tests whether at least one element in the - * ``Sequence`` passes the test implemented by the provided function. - * @param predicate A function to execute for each element in the - * ``Sequence``. It should return a truthy value to indicate the element - * passes the test, and a falsy value otherwise. - * @param thisArg A value to use as ``this`` when executing ``predicate``. - */ - some(predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): boolean; - /** - * See :js:meth:`Array.every`. Tests whether every element in the ``Sequence`` - * passes the test implemented by the provided function. - * @param predicate A function to execute for each element in the - * ``Sequence``. It should return a truthy value to indicate the element - * passes the test, and a falsy value otherwise. - * @param thisArg A value to use as ``this`` when executing ``predicate``. - */ - every(predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): boolean; - /** - * See :js:meth:`Array.reduce`. Executes a user-supplied "reducer" callback - * function on each element of the Sequence, in order, passing in the return - * value from the calculation on the preceding element. The final result of - * running the reducer across all elements of the Sequence is a single value. - * @param callbackfn A function to execute for each element in the ``Sequence``. Its - * return value is discarded. - */ - reduce(callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any) => any, initialValue?: any): any; - /** - * See :js:meth:`Array.reduceRight`. Applies a function against an accumulator - * and each value of the Sequence (from right to left) to reduce it to a - * single value. - * @param callbackfn A function to execute for each element in the Sequence. - * Its return value is discarded. - */ - reduceRight(callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any) => any, initialValue: any): any; - /** - * See :js:meth:`Array.at`. Takes an integer value and returns the item at - * that index. - * @param index Zero-based index of the Sequence element to be returned, - * converted to an integer. Negative index counts back from the end of the - * Sequence. - * @returns The element in the Sequence matching the given index. - */ - at(index: number): any; - /** - * The :js:meth:`Array.concat` method is used to merge two or more arrays. - * This method does not change the existing arrays, but instead returns a new - * array. - * @param rest Arrays and/or values to concatenate into a new array. - * @returns A new Array instance. - */ - concat(...rest: ConcatArray[]): any[]; - /** - * The :js:meth:`Array.includes` method determines whether a Sequence - * includes a certain value among its entries, returning true or false as - * appropriate. - * @param elt - * @returns - */ - includes(elt: any): any; - /** - * The :js:meth:`Array.entries` method returns a new iterator object that - * contains the key/value pairs for each index in the ``Sequence``. - * @returns A new iterator object. - */ - entries(): IterableIterator<[ - number, - any - ]>; - /** - * The :js:meth:`Array.keys` method returns a new iterator object that - * contains the keys for each index in the ``Sequence``. - * @returns A new iterator object. - */ - keys(): IterableIterator; - /** - * The :js:meth:`Array.values` method returns a new iterator object that - * contains the values for each index in the ``Sequence``. - * @returns A new iterator object. - */ - values(): IterableIterator; - /** - * The :js:meth:`Array.find` method returns the first element in the provided - * array that satisfies the provided testing function. - * @param predicate A function to execute for each element in the - * ``Sequence``. It should return a truthy value to indicate a matching - * element has been found, and a falsy value otherwise. - * @param thisArg A value to use as ``this`` when executing ``predicate``. - * @returns The first element in the ``Sequence`` that satisfies the provided - * testing function. - */ - find(predicate: (value: any, index: number, obj: any[]) => any, thisArg?: any): any; - /** - * The :js:meth:`Array.findIndex` method returns the index of the first - * element in the provided array that satisfies the provided testing function. - * @param predicate A function to execute for each element in the - * ``Sequence``. It should return a truthy value to indicate a matching - * element has been found, and a falsy value otherwise. - * @param thisArg A value to use as ``this`` when executing ``predicate``. - * @returns The index of the first element in the ``Sequence`` that satisfies - * the provided testing function. - */ - findIndex(predicate: (value: any, index: number, obj: any[]) => any, thisArg?: any): number; - toJSON(this: any): unknown[]; - /** - * Returns the object treated as a json adaptor. - * - * With a JsonAdaptor: - * 1. property access / modification / deletion is implemented with - * :meth:`~object.__getitem__`, :meth:`~object.__setitem__`, and - * :meth:`~object.__delitem__` respectively. - * 2. If an attribute is accessed and the result implements - * :meth:`~object.__getitem__` then the result will also be a json - * adaptor. - * - * For instance, ``JSON.stringify(proxy.asJsJson())`` acts like an - * inverse to Python's :py:func:`json.loads`. - */ - asJsJson(): PyProxy & {}; -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is an - * :py:class:`~collections.abc.MutableSequence` (i.e., a :py:class:`list`) - */ -declare class PyMutableSequence extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -interface PyMutableSequence extends PyMutableSequenceMethods { -} -declare class PyMutableSequenceMethods { - /** - * The :js:meth:`Array.reverse` method reverses a :js:class:`PyMutableSequence` in - * place. - * @returns A reference to the same :js:class:`PyMutableSequence` - */ - reverse(): PyMutableSequence; - /** - * The :js:meth:`Array.sort` method sorts the elements of a - * :js:class:`PyMutableSequence` in place. - * @param compareFn A function that defines the sort order. - * @returns A reference to the same :js:class:`PyMutableSequence` - */ - sort(compareFn?: (a: any, b: any) => number): PyMutableSequence; - /** - * The :js:meth:`Array.splice` method changes the contents of a - * :js:class:`PyMutableSequence` by removing or replacing existing elements and/or - * adding new elements in place. - * @param start Zero-based index at which to start changing the - * :js:class:`PyMutableSequence`. - * @param deleteCount An integer indicating the number of elements in the - * :js:class:`PyMutableSequence` to remove from ``start``. - * @param items The elements to add to the :js:class:`PyMutableSequence`, beginning from - * ``start``. - * @returns An array containing the deleted elements. - */ - splice(start: number, deleteCount?: number, ...items: any[]): any[]; - /** - * The :js:meth:`Array.push` method adds the specified elements to the end of - * a :js:class:`PyMutableSequence`. - * @param elts The element(s) to add to the end of the :js:class:`PyMutableSequence`. - * @returns The new length property of the object upon which the method was - * called. - */ - push(...elts: any[]): any; - /** - * The :js:meth:`Array.pop` method removes the last element from a - * :js:class:`PyMutableSequence`. - * @returns The removed element from the :js:class:`PyMutableSequence`; undefined if the - * :js:class:`PyMutableSequence` is empty. - */ - pop(): any; - /** - * The :js:meth:`Array.shift` method removes the first element from a - * :js:class:`PyMutableSequence`. - * @returns The removed element from the :js:class:`PyMutableSequence`; undefined if the - * :js:class:`PyMutableSequence` is empty. - */ - shift(): any; - /** - * The :js:meth:`Array.unshift` method adds the specified elements to the - * beginning of a :js:class:`PyMutableSequence`. - * @param elts The elements to add to the front of the :js:class:`PyMutableSequence`. - * @returns The new length of the :js:class:`PyMutableSequence`. - */ - unshift(...elts: any[]): any; - /** - * The :js:meth:`Array.copyWithin` method shallow copies part of a - * :js:class:`PyMutableSequence` to another location in the same :js:class:`PyMutableSequence` - * without modifying its length. - * @param target Zero-based index at which to copy the sequence to. - * @param start Zero-based index at which to start copying elements from. - * @param end Zero-based index at which to end copying elements from. - * @returns The modified :js:class:`PyMutableSequence`. - */ - copyWithin(target: number, start?: number, end?: number): any; - /** - * The :js:meth:`Array.fill` method changes all elements in an array to a - * static value, from a start index to an end index. - * @param value Value to fill the array with. - * @param start Zero-based index at which to start filling. Default 0. - * @param end Zero-based index at which to end filling. Default - * ``list.length``. - * @returns - */ - fill(value: any, start?: number, end?: number): any; -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is :ref:`awaitable - * ` (i.e., has an :meth:`~object.__await__` method). - */ -declare class PyAwaitable extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -interface PyAwaitable extends Promise { -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is - * :std:term:`callable` (i.e., has an :py:meth:`~object.__call__` method). - */ -declare class PyCallable extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyCallable; -} -interface PyCallable extends PyCallableMethods { - (...args: any[]): any; -} -declare class PyCallableMethods { - /** - * The ``apply()`` method calls the specified function with a given this - * value, and arguments provided as an array (or an array-like object). Like - * :js:meth:`Function.apply`. - * - * @param thisArg The ``this`` argument. Has no effect unless the - * :js:class:`~pyodide.ffi.PyCallable` has :js:meth:`captureThis` set. If - * :js:meth:`captureThis` is set, it will be passed as the first argument to - * the Python function. - * @param jsargs The array of arguments - * @returns The result from the function call. - */ - apply(thisArg: any, jsargs: any): any; - /** - * Calls the function with a given this value and arguments provided - * individually. See :js:meth:`Function.call`. - * - * @param thisArg The ``this`` argument. Has no effect unless the - * :js:class:`~pyodide.ffi.PyCallable` has :js:meth:`captureThis` set. If - * :js:meth:`captureThis` is set, it will be passed as the first argument to - * the Python function. - * @param jsargs The arguments - * @returns The result from the function call. - */ - call(thisArg: any, ...jsargs: any): any; - /** - * Call the Python function. The first parameter controls various parameters - * that change the way the call is performed. - * - * @param options - * @param options.kwargs If true, the last argument is treated as a collection - * of keyword arguments. - * @param options.promising If true, the call is made with stack switching - * enabled. Not needed if the callee is an async - * Python function. - * @param options.relaxed If true, extra arguments are ignored instead of - * raising a :py:exc:`TypeError`. - * @param jsargs Arguments to the Python function. - * @returns - */ - callWithOptions({ relaxed, kwargs, promising, }: { - relaxed?: boolean; - kwargs?: boolean; - promising?: boolean; - }, ...jsargs: any): any; - /** - * Call the function with keyword arguments. The last argument must be an - * object with the keyword arguments. - */ - callKwargs(...jsargs: any): any; - /** - * Call the function in a "relaxed" manner. Any extra arguments will be - * ignored. This matches the behavior of JavaScript functions more accurately. - * - * Any extra arguments will be ignored. This matches the behavior of - * JavaScript functions more accurately. Missing arguments are **NOT** filled - * with `None`. If too few arguments are passed, this will still raise a - * TypeError. - * - * This uses :py:func:`pyodide.code.relaxed_call`. - */ - callRelaxed(...jsargs: any): any; - /** - * Call the function with keyword arguments in a "relaxed" manner. The last - * argument must be an object with the keyword arguments. Any extra arguments - * will be ignored. This matches the behavior of JavaScript functions more - * accurately. - * - * Missing arguments are **NOT** filled with ``None``. If too few arguments are - * passed, this will still raise a :py:exc:`TypeError`. Also, if the same argument is - * passed as both a keyword argument and a positional argument, it will raise - * an error. - * - * This uses :py:func:`pyodide.code.relaxed_call`. - */ - callKwargsRelaxed(...jsargs: any): any; - /** - * Call the function with stack switching enabled. The last argument must be - * an object with the keyword arguments. Functions called this way can use - * :py:meth:`~pyodide.ffi.run_sync` to block until an - * :py:class:`~collections.abc.Awaitable` is resolved. Only works in runtimes - * with JS Promise integration. - * - * .. admonition:: Experimental - * :class: warning - * - * This feature is not yet stable. - * - * @experimental - */ - callPromising(...jsargs: any): Promise; - /** - * Call the function with stack switching enabled. The last argument must be - * an object with the keyword arguments. Functions called this way can use - * :py:meth:`~pyodide.ffi.run_sync` to block until an - * :py:class:`~collections.abc.Awaitable` is resolved. Only works in runtimes - * with JS Promise integration. - * - * .. admonition:: Experimental - * :class: warning - * - * This feature is not yet stable. - * - * @experimental - */ - callPromisingKwargs(...jsargs: any): Promise; - /** - * The ``bind()`` method creates a new function that, when called, has its - * ``this`` keyword set to the provided value, with a given sequence of - * arguments preceding any provided when the new function is called. See - * :js:meth:`Function.bind`. - * - * If the :js:class:`~pyodide.ffi.PyCallable` does not have - * :js:meth:`captureThis` set, the ``this`` parameter will be discarded. If it - * does have :js:meth:`captureThis` set, ``thisArg`` will be set to the first - * argument of the Python function. The returned proxy and the original proxy - * have the same lifetime so destroying either destroys both. - * - * @param thisArg The value to be passed as the ``this`` parameter to the - * target function ``func`` when the bound function is called. - * @param jsargs Extra arguments to prepend to arguments provided to the bound - * function when invoking ``func``. - * @returns - */ - bind(thisArg: any, ...jsargs: any): PyProxy; - /** - * Returns a :js:class:`~pyodide.ffi.PyProxy` that passes ``this`` as the first argument to the - * Python function. The returned :js:class:`~pyodide.ffi.PyProxy` has the internal ``captureThis`` - * property set. - * - * It can then be used as a method on a JavaScript object. The returned proxy - * and the original proxy have the same lifetime so destroying either destroys - * both. - * - * For example: - * - * .. code-block:: pyodide - * - * let obj = { a : 7 }; - * pyodide.runPython(` - * def f(self): - * return self.a - * `); - * // Without captureThis, it doesn't work to use f as a method for obj: - * obj.f = pyodide.globals.get("f"); - * obj.f(); // raises "TypeError: f() missing 1 required positional argument: 'self'" - * // With captureThis, it works fine: - * obj.f = pyodide.globals.get("f").captureThis(); - * obj.f(); // returns 7 - * - * @returns The resulting :js:class:`~pyodide.ffi.PyProxy`. It has the same lifetime as the - * original :js:class:`~pyodide.ffi.PyProxy` but passes ``this`` to the wrapped function. - * - */ - captureThis(): PyProxy; -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object supports the - * Python :external:doc:`c-api/buffer`. - * - * Examples of buffers include {py:class}`bytes` objects and numpy - * {external+numpy:ref}`arrays`. - */ -declare class PyBuffer extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyBuffer; -} -interface PyBuffer extends PyBufferMethods { -} -declare class PyBufferMethods { - /** - * Get a view of the buffer data which is usable from JavaScript. No copy is - * ever performed. - * - * We do not support suboffsets, if the buffer requires suboffsets we will - * throw an error. JavaScript nd array libraries can't handle suboffsets - * anyways. In this case, you should use the :js:meth:`~PyProxy.toJs` api or - * copy the buffer to one that doesn't use suboffsets (using e.g., - * :py:func:`numpy.ascontiguousarray`). - * - * If the buffer stores big endian data or half floats, this function will - * fail without an explicit type argument. For big endian data you can use - * :js:meth:`~PyProxy.toJs`. :js:class:`DataView` has support for big endian - * data, so you might want to pass ``'dataview'`` as the type argument in that - * case. - * - * @param type The type of the :js:attr:`~pyodide.ffi.PyBufferView.data` field - * in the output. Should be one of: ``"i8"``, ``"u8"``, ``"u8clamped"``, - * ``"i16"``, ``"u16"``, ``"i32"``, ``"u32"``, ``"i32"``, ``"u32"``, - * ``"i64"``, ``"u64"``, ``"f32"``, ``"f64"``, or ``"dataview"``. This argument - * is optional, if absent :js:meth:`~pyodide.ffi.PyBuffer.getBuffer` will try - * to determine the appropriate output type based on the buffer format string - * (see :std:ref:`struct-format-strings`). - */ - getBuffer(type?: string): PyBufferView; -} -/** - * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is a :py:class:`dict`. - */ -declare class PyDict extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -interface PyDict extends PyProxyWithGet, PyProxyWithSet, PyProxyWithHas, PyProxyWithLength, PyIterable { -} -/** - * A class to allow access to Python data buffers from JavaScript. These are - * produced by :js:meth:`~pyodide.ffi.PyBuffer.getBuffer` and cannot be constructed directly. - * When you are done, release it with the :js:func:`~PyBufferView.release` method. - * See the Python :external:doc:`c-api/buffer` documentation for more - * information. - * - * To find the element ``x[a_1, ..., a_n]``, you could use the following code: - * - * .. code-block:: js - * - * function multiIndexToIndex(pybuff, multiIndex) { - * if (multindex.length !== pybuff.ndim) { - * throw new Error("Wrong length index"); - * } - * let idx = pybuff.offset; - * for (let i = 0; i < pybuff.ndim; i++) { - * if (multiIndex[i] < 0) { - * multiIndex[i] = pybuff.shape[i] - multiIndex[i]; - * } - * if (multiIndex[i] < 0 || multiIndex[i] >= pybuff.shape[i]) { - * throw new Error("Index out of range"); - * } - * idx += multiIndex[i] * pybuff.stride[i]; - * } - * return idx; - * } - * console.log("entry is", pybuff.data[multiIndexToIndex(pybuff, [2, 0, -1])]); - * - * .. admonition:: Converting between TypedArray types - * :class: warning - * - * The following naive code to change the type of a typed array does not - * work: - * - * .. code-block:: js - * - * // Incorrectly convert a TypedArray. - * // Produces a Uint16Array that points to the entire WASM memory! - * let myarray = new Uint16Array(buffer.data.buffer); - * - * Instead, if you want to convert the output TypedArray, you need to say: - * - * .. code-block:: js - * - * // Correctly convert a TypedArray. - * let myarray = new Uint16Array( - * buffer.data.buffer, - * buffer.data.byteOffset, - * buffer.data.byteLength - * ); - */ -declare class PyBufferView { - /** - * The offset of the first entry of the array. For instance if our array - * is 3d, then you will find ``array[0,0,0]`` at - * ``pybuf.data[pybuf.offset]`` - */ - offset: number; - /** - * If the data is read only, you should not modify it. There is no way for us - * to enforce this, but it may cause very weird behavior. See - * :py:attr:`memoryview.readonly`. - */ - readonly: boolean; - /** - * The format string for the buffer. See :ref:`struct-format-strings` - * and :py:attr:`memoryview.format`. - */ - format: string; - /** - * How large is each entry in bytes? See :py:attr:`memoryview.itemsize`. - */ - itemsize: number; - /** - * The number of dimensions of the buffer. If ``ndim`` is 0, the buffer - * represents a single scalar or struct. Otherwise, it represents an - * array. See :py:attr:`memoryview.ndim`. - */ - ndim: number; - /** - * The total number of bytes the buffer takes up. This is equal to - * :js:attr:`buff.data.byteLength `. See - * :py:attr:`memoryview.nbytes`. - */ - nbytes: number; - /** - * The shape of the buffer, that is how long it is in each dimension. - * The length will be equal to ``ndim``. For instance, a 2x3x4 array - * would have shape ``[2, 3, 4]``. See :py:attr:`memoryview.shape`. - */ - shape: number[]; - /** - * An array of of length ``ndim`` giving the number of elements to skip - * to get to a new element in each dimension. See the example definition - * of a ``multiIndexToIndex`` function above. See :py:attr:`memoryview.strides`. - */ - strides: number[]; - /** - * The actual data. A typed array of an appropriate size backed by a segment - * of the WASM memory. - * - * The ``type`` argument of :js:meth:`~pyodide.ffi.PyBuffer.getBuffer` determines - * which sort of :js:class:`TypedArray` or :js:class:`DataView` to return. By - * default :js:meth:`~pyodide.ffi.PyBuffer.getBuffer` will look at the format string - * to determine the most appropriate option. Most often the result is a - * :js:class:`Uint8Array`. - * - * .. admonition:: Contiguity - * :class: warning - * - * If the buffer is not contiguous, the :js:attr:`~PyBufferView.readonly` - * TypedArray will contain data that is not part of the buffer. Modifying - * this data leads to undefined behavior. - * - * .. admonition:: Read only buffers - * :class: warning - * - * If :js:attr:`buffer.readonly ` is ``true``, you - * should not modify the buffer. Modifying a read only buffer leads to - * undefined behavior. - * - */ - data: TypedArray; - /** - * Is it C contiguous? See :py:attr:`memoryview.c_contiguous`. - */ - c_contiguous: boolean; - /** - * Is it Fortran contiguous? See :py:attr:`memoryview.f_contiguous`. - */ - f_contiguous: boolean; - /** - * @private - */ - _released: boolean; - /** - * @private - */ - _view_ptr: number; - /** @private */ - constructor(); - /** - * Release the buffer. This allows the memory to be reclaimed. - */ - release(): void; -} -/** - * A JavaScript error caused by a Python exception. - * - * In order to reduce the risk of large memory leaks, the :js:class:`PythonError` - * contains no reference to the Python exception that caused it. You can find - * the actual Python exception that caused this error as - * :py:data:`sys.last_exc`. - * - * See :ref:`type translations of errors ` for more - * information. - * - * .. admonition:: Avoid leaking stack Frames - * :class: warning - * - * If you make a :js:class:`~pyodide.ffi.PyProxy` of - * :py:data:`sys.last_exc`, you should be especially careful to - * :js:meth:`~pyodide.ffi.PyProxy.destroy` it when you are done. You may leak a large - * amount of memory including the local variables of all the stack frames in - * the traceback if you don't. The easiest way is to only handle the - * exception in Python. - * - * @hideconstructor - */ -declare class PythonError extends Error { - /** - * The address of the error we are wrapping. We may later compare this - * against sys.last_exc. - * WARNING: we don't own a reference to this pointer, dereferencing it - * may be a use-after-free error! - * @private - */ - __error_address: number; - /** - * The name of the Python error class, e.g, :py:exc:`RuntimeError` or - * :py:exc:`KeyError`. - */ - type: string; - constructor(type: string, message: string, error_address: number); -} -/** - * Foreign function interface classes. Can be used for typescript type - * annotations or at runtime for `instanceof` checks. - * @summaryLink :ref:`ffi ` - * @hidetype - * @omitFromAutoModule - */ -declare const ffi: { - PyProxy: typeof PyProxy; - PyProxyWithLength: typeof PyProxyWithLength; - PyProxyWithGet: typeof PyProxyWithGet; - PyProxyWithSet: typeof PyProxyWithSet; - PyProxyWithHas: typeof PyProxyWithHas; - PyDict: typeof PyDict; - PyIterable: typeof PyIterable; - PyAsyncIterable: typeof PyAsyncIterable; - PyIterator: typeof PyIterator; - PyAsyncIterator: typeof PyAsyncIterator; - PyGenerator: typeof PyGenerator; - PyAsyncGenerator: typeof PyAsyncGenerator; - PyAwaitable: typeof PyAwaitable; - PyCallable: typeof PyCallable; - PyBuffer: typeof PyBuffer; - PyBufferView: typeof PyBufferView; - PythonError: typeof PythonError; - PySequence: typeof PySequence; - PyMutableSequence: typeof PyMutableSequence; -}; - -export type {}; -export type {PyAsyncGenerator, PyAsyncIterable, PyAsyncIterator, PyAwaitable, PyBuffer, PyBufferView, PyCallable, PyDict, PyGenerator, PyIterable, PyIterator, PyMutableSequence, PyProxy, PyProxyWithGet, PyProxyWithHas, PyProxyWithLength, PyProxyWithSet, PySequence, PythonError}; diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/micropip-0.9.0-py3-none-any.whl b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/micropip-0.9.0-py3-none-any.whl deleted file mode 100644 index baa1d582bf..0000000000 Binary files a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/micropip-0.9.0-py3-none-any.whl and /dev/null differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/package.json b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/package.json deleted file mode 100644 index 0154697f64..0000000000 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/package.json +++ /dev/null @@ -1,137 +0,0 @@ -{ - "name": "pyodide", - "version": "0.27.7", - "description": "The Pyodide JavaScript package", - "keywords": [ - "python", - "webassembly" - ], - "homepage": "https://github.com/pyodide/pyodide", - "repository": { - "type": "git", - "url": "https://github.com/pyodide/pyodide" - }, - "bugs": { - "url": "https://github.com/pyodide/pyodide/issues" - }, - "license": "MPL-2.0", - "devDependencies": { - "@types/assert": "^1.5.6", - "@types/expect": "^24.3.0", - "@types/mocha": "^9.1.0", - "@types/node": "^20.8.4", - "@types/ws": "^8.5.3", - "chai": "^4.3.6", - "chai-as-promised": "^7.1.1", - "cross-env": "^7.0.3", - "dts-bundle-generator": "^8.1.1", - "esbuild": "^0.17.12", - "express": "^4.17.3", - "mocha": "^9.0.2", - "npm-run-all": "^4.1.5", - "nyc": "^15.1.0", - "prettier": "^2.2.1", - "sinon": "^18.0.0", - "ts-mocha": "^9.0.2", - "tsd": "^0.24.1", - "typedoc": "^0.27.6", - "typescript": "5.7", - "wabt": "^1.0.32" - }, - "main": "pyodide.js", - "exports": { - ".": { - "types": "./pyodide.d.ts", - "require": "./pyodide.js", - "import": "./pyodide.mjs" - }, - "./ffi": { - "types": "./ffi.d.ts" - }, - "./pyodide.asm.wasm": "./pyodide.asm.wasm", - "./pyodide.asm.js": "./pyodide.asm.js", - "./python_stdlib.zip": "./python_stdlib.zip", - "./pyodide.mjs": "./pyodide.mjs", - "./pyodide.js": "./pyodide.js", - "./package.json": "./package.json", - "./pyodide-lock.json": "./pyodide-lock.json" - }, - "files": [ - "pyodide.asm.js", - "pyodide.asm.wasm", - "python_stdlib.zip", - "pyodide.mjs", - "pyodide.js.map", - "pyodide.mjs.map", - "pyodide.d.ts", - "ffi.d.ts", - "pyodide-lock.json", - "console.html" - ], - "browser": { - "child_process": false, - "crypto": false, - "fs": false, - "fs/promises": false, - "path": false, - "url": false, - "vm": false, - "ws": false - }, - "scripts": { - "build-inner": "node esbuild.config.inner.mjs", - "build": "tsc --noEmit && node esbuild.config.outer.mjs", - "test": "npm-run-all test:*", - "test:unit": "cross-env TEST_NODE=1 ts-mocha --node-option=experimental-loader=./test/loader.mjs --node-option=experimental-wasm-stack-switching -p tsconfig.test.json \"test/unit/**\"", - "test:node": "cross-env TEST_NODE=1 mocha test/integration/**/*.test.js", - "test:browser": "mocha test/integration/**/*.test.js", - "tsc": "tsc --noEmit", - "coverage": "cross-env TEST_NODE=1 npm-run-all coverage:*", - "coverage:build": "nyc npm run test:node" - }, - "mocha": { - "bail": false, - "timeout": 30000, - "full-trace": true, - "inline-diffs": true, - "check-leaks": false, - "global": [ - "pyodide", - "page", - "chai" - ] - }, - "nyc": { - "reporter": [ - "html", - "text-summary" - ], - "include": [ - "*.ts" - ], - "all": true, - "clean": true, - "cache": false, - "instrument": false, - "checkCoverage": true, - "statements": 95, - "functions": 95, - "branches": 80, - "lines": 95 - }, - "tsd": { - "compilerOptions": { - "lib": [ - "ES2017", - "DOM" - ] - } - }, - "dependencies": { - "ws": "^8.5.0" - }, - "types": "./pyodide.d.ts", - "engines": { - "node": ">=18.0.0" - } -} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/packaging-24.2-py3-none-any.whl b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/packaging-24.2-py3-none-any.whl deleted file mode 100644 index ff72069a11..0000000000 Binary files a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/packaging-24.2-py3-none-any.whl and /dev/null differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide-lock.json b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide-lock.json deleted file mode 100644 index 03c7058474..0000000000 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide-lock.json +++ /dev/null @@ -1 +0,0 @@ -{"info": {"abi_version": "2024_0", "arch": "wasm32", "platform": "emscripten_3_1_58", "python": "3.12.7", "version": "0.27.7"}, "packages": {"affine": {"depends": [], "file_name": "affine-2.4.0-py3-none-any.whl", "imports": ["affine"], "install_dir": "site", "name": "affine", "package_type": "package", "sha256": "c9323a8bd2d1d98e41815810f66ecb749943728a192f25c2b80d0088bda8d823", "unvendored_tests": true, "version": "2.4.0"}, "affine-tests": {"depends": ["affine"], "file_name": "affine-tests.tar", "imports": [], "install_dir": "site", "name": "affine-tests", "package_type": "package", "sha256": "761c61558dfa1d429b4f6affaf4065ad1094997a7ebe1a68cf5a1cc0cfee90dc", "unvendored_tests": false, "version": "2.4.0"}, "aiohttp": {"depends": ["aiosignal", "async-timeout", "attrs", "charset-normalizer", "frozenlist", "multidict", "yarl"], "file_name": "aiohttp-3.9.5-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["aiohttp"], "install_dir": "site", "name": "aiohttp", "package_type": "package", "sha256": "b4bdd9c7329e0594fe6649b8b33daaf6773804eb5d79f8a8af3719e1c284b5d2", "unvendored_tests": true, "version": "3.9.5"}, "aiohttp-tests": {"depends": ["aiohttp"], "file_name": "aiohttp-tests.tar", "imports": [], "install_dir": "site", "name": "aiohttp-tests", "package_type": "package", "sha256": "deda3e43e0fb8e2125fe856e10d65de3403aada4cdf53530813cfe7f3b740c3e", "unvendored_tests": false, "version": "3.9.5"}, "aiosignal": {"depends": ["frozenlist"], "file_name": "aiosignal-1.3.1-py3-none-any.whl", "imports": ["aiosignal"], "install_dir": "site", "name": "aiosignal", "package_type": "package", "sha256": "1314574b5d7ab2c91dc5cfcd85e24fd0adf40e4dbf5845f347d17aa21f1aacfc", "unvendored_tests": false, "version": "1.3.1"}, "altair": {"depends": ["typing-extensions", "jinja2", "jsonschema", "packaging", "narwhals"], "file_name": "altair-5.4.1-py3-none-any.whl", "imports": ["altair"], "install_dir": "site", "name": "altair", "package_type": "package", "sha256": "d08aff5d4e101b7a0f9ae1d8ba1fe1d1f6bac0b1e9b1b90b7ccbd9ba3993f0f5", "unvendored_tests": false, "version": "5.4.1"}, "annotated-types": {"depends": [], "file_name": "annotated_types-0.6.0-py3-none-any.whl", "imports": ["annotated_types"], "install_dir": "site", "name": "annotated-types", "package_type": "package", "sha256": "9733de5d59580defb40ad7bd8a5d53a0fac03de7a13028d95cacc4e81945c97c", "unvendored_tests": true, "version": "0.6.0"}, "annotated-types-tests": {"depends": ["annotated-types"], "file_name": "annotated-types-tests.tar", "imports": [], "install_dir": "site", "name": "annotated-types-tests", "package_type": "package", "sha256": "691581bfe36b9e7351e1efa80f64ad970d0931ff468b05dd0bc1e229d6702916", "unvendored_tests": false, "version": "0.6.0"}, "anyio": {"depends": ["ssl", "sniffio", "typing-extensions"], "file_name": "anyio-4.9.0-py3-none-any.whl", "imports": ["anyio"], "install_dir": "site", "name": "anyio", "package_type": "package", "sha256": "e1d9180d4361fd71d1bc4a7007fea6cae1d18792dba9d07eaad89f2a8562f71c", "unvendored_tests": false, "version": "4.9.0"}, "apsw": {"depends": [], "file_name": "apsw-3.47.2.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["apsw"], "install_dir": "site", "name": "apsw", "package_type": "package", "sha256": "dedec1a73c98566d03b9e0985a531219387a780dbac9811fd56ae73394a7ef44", "unvendored_tests": false, "version": "3.47.2.0"}, "argon2-cffi": {"depends": ["argon2-cffi-bindings"], "file_name": "argon2_cffi-23.1.0-py3-none-any.whl", "imports": ["argon2"], "install_dir": "site", "name": "argon2-cffi", "package_type": "package", "sha256": "630137502ab48440d9bf8f5a206ba439e84728f686fb0326bcc08ab08750350d", "unvendored_tests": false, "version": "23.1.0"}, "argon2-cffi-bindings": {"depends": ["cffi"], "file_name": "argon2_cffi_bindings-21.2.0-cp312-abi3-pyodide_2024_0_wasm32.whl", "imports": ["_argon2_cffi_bindings"], "install_dir": "site", "name": "argon2-cffi-bindings", "package_type": "package", "sha256": "1657e6db06945e26809888c581ef511f27e3d6eb726d6108355133786cf4f5d9", "unvendored_tests": false, "version": "21.2.0"}, "arro3-compute": {"depends": ["arro3-core"], "file_name": "arro3_compute-0.4.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["arro3.compute"], "install_dir": "site", "name": "arro3-compute", "package_type": "package", "sha256": "6fbd4073d8728ee8a540a80e4311cce4a91057b8c85f2c05e3b6fddbf3cf5758", "unvendored_tests": false, "version": "0.4.1"}, "arro3-core": {"depends": [], "file_name": "arro3_core-0.4.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["arro3.core"], "install_dir": "site", "name": "arro3-core", "package_type": "package", "sha256": "249ecb1f0d38cdcff25f059625e676405579015363da8fc9cb6d53f4def999db", "unvendored_tests": false, "version": "0.4.1"}, "arro3-io": {"depends": ["arro3-core"], "file_name": "arro3_io-0.4.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["arro3.io"], "install_dir": "site", "name": "arro3-io", "package_type": "package", "sha256": "8bb9a2a9b9b16668097e0964d04292a2f37c0d4d43fad506a35427a10855d9da", "unvendored_tests": false, "version": "0.4.1"}, "asciitree": {"depends": [], "file_name": "asciitree-0.3.3-py3-none-any.whl", "imports": ["asciitree"], "install_dir": "site", "name": "asciitree", "package_type": "package", "sha256": "3ac0c8cd8b0dba1fd619696a55b30712839d114cb00ee6723bcf683758e54129", "unvendored_tests": false, "version": "0.3.3"}, "astropy": {"depends": ["packaging", "numpy", "pyerfa", "pyyaml", "astropy_iers_data"], "file_name": "astropy-7.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["astropy"], "install_dir": "site", "name": "astropy", "package_type": "package", "sha256": "b2c68b140367816c8b49f11f89baa461da557d5ee8d084b46c0d611cc41645ca", "unvendored_tests": false, "version": "7.0.0"}, "astropy-iers-data": {"depends": [], "file_name": "astropy_iers_data-0.2024.4.22.0.29.50-py3-none-any.whl", "imports": ["astropy_iers_data"], "install_dir": "site", "name": "astropy_iers_data", "package_type": "package", "sha256": "b6e215225866edbb309b05882ca29535b50ef5cb81a806481b11767e51ccb2b2", "unvendored_tests": true, "version": "0.2024.4.22.0.29.50"}, "astropy-iers-data-tests": {"depends": ["astropy_iers_data"], "file_name": "astropy-iers-data-tests.tar", "imports": [], "install_dir": "site", "name": "astropy_iers_data-tests", "package_type": "package", "sha256": "e3345f022de75aa46d54f3b30bcca6cf6d1e07e8b921c2d6f90634c7842f466d", "unvendored_tests": false, "version": "0.2024.4.22.0.29.50"}, "asttokens": {"depends": ["six"], "file_name": "asttokens-2.4.1-py2.py3-none-any.whl", "imports": ["asttokens"], "install_dir": "site", "name": "asttokens", "package_type": "package", "sha256": "bfeb9073458201c1f1c03a830e2154df70429d156d47844db30a19e2a7351e55", "unvendored_tests": false, "version": "2.4.1"}, "async-timeout": {"depends": [], "file_name": "async_timeout-4.0.3-py3-none-any.whl", "imports": ["async_timeout"], "install_dir": "site", "name": "async-timeout", "package_type": "package", "sha256": "7fa8d0e5425e7347978ff7d8ca5446748839177de98c0ae9930af03faf1fcc7a", "unvendored_tests": false, "version": "4.0.3"}, "atomicwrites": {"depends": [], "file_name": "atomicwrites-1.4.1-py2.py3-none-any.whl", "imports": ["atomicwrites"], "install_dir": "site", "name": "atomicwrites", "package_type": "package", "sha256": "f2518238e4f900f3c8adc48fc5e6dfe74db6bf650bb63698fa0a0d48e2567b9d", "unvendored_tests": false, "version": "1.4.1"}, "attrs": {"depends": ["six"], "file_name": "attrs-23.2.0-py3-none-any.whl", "imports": ["attr", "attrs"], "install_dir": "site", "name": "attrs", "package_type": "package", "sha256": "0ee53cdb902382d5ae8f13992baaa506073dcaef8bda1be86cfba145ee40cd22", "unvendored_tests": false, "version": "23.2.0"}, "autograd": {"depends": ["numpy", "future"], "file_name": "autograd-1.7.0-py3-none-any.whl", "imports": ["autograd"], "install_dir": "site", "name": "autograd", "package_type": "package", "sha256": "262af11549c493d3ac084030269e14696a9148b263539c681e5c60d35e223ec2", "unvendored_tests": true, "version": "1.7.0"}, "autograd-tests": {"depends": ["autograd"], "file_name": "autograd-tests.tar", "imports": [], "install_dir": "site", "name": "autograd-tests", "package_type": "package", "sha256": "cc6a9470407adba2109657547f39c9b4494c9769d5114545baed51ae499cc687", "unvendored_tests": false, "version": "1.7.0"}, "awkward-cpp": {"depends": ["numpy"], "file_name": "awkward_cpp-44-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["awkward_cpp"], "install_dir": "site", "name": "awkward-cpp", "package_type": "package", "sha256": "9092e80a0c9f6e933700423d45a0e2df8962cf6c638930d8b5099452f3ec0809", "unvendored_tests": false, "version": "44"}, "b2d": {"depends": ["numpy", "pydantic", "setuptools", "annotated-types"], "file_name": "b2d-0.7.4-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["b2d"], "install_dir": "site", "name": "b2d", "package_type": "package", "sha256": "0476a6ab1a6d9ae963d3a97aa317d660b79a571297fdde0158a2e504c3435786", "unvendored_tests": false, "version": "0.7.4"}, "bcrypt": {"depends": [], "file_name": "bcrypt-4.1.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["bcrypt"], "install_dir": "site", "name": "bcrypt", "package_type": "package", "sha256": "1836a80e3a030dec7ba3dd82a59c2f3162c83d0ea473972dce7f1a4702afdcd3", "unvendored_tests": false, "version": "4.1.2"}, "beautifulsoup4": {"depends": ["soupsieve"], "file_name": "beautifulsoup4-4.12.3-py3-none-any.whl", "imports": ["bs4"], "install_dir": "site", "name": "beautifulsoup4", "package_type": "package", "sha256": "dadfaf468a0acbd3068e5ad8cfce9f7c364a58161307ccc49ab2452b4956e13b", "unvendored_tests": true, "version": "4.12.3"}, "beautifulsoup4-tests": {"depends": ["beautifulsoup4"], "file_name": "beautifulsoup4-tests.tar", "imports": [], "install_dir": "site", "name": "beautifulsoup4-tests", "package_type": "package", "sha256": "d7a5f6a3236dcca4144c69a6eed6e36363adc6c6b9b4eac59dc92f869181860e", "unvendored_tests": false, "version": "4.12.3"}, "biopython": {"depends": ["numpy"], "file_name": "biopython-1.84-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["Bio", "BioSQL"], "install_dir": "site", "name": "biopython", "package_type": "package", "sha256": "35e88ba1455c9fdc02f78cdd7193137031c837d5efded493319e4acfb32cffb6", "unvendored_tests": false, "version": "1.84"}, "bitarray": {"depends": [], "file_name": "bitarray-2.9.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["bitarray"], "install_dir": "site", "name": "bitarray", "package_type": "package", "sha256": "56794ec14351c590ed4d9cedc9bef3cd0a3d28fbdfaed161d17c208bf7bbb766", "unvendored_tests": true, "version": "2.9.2"}, "bitarray-tests": {"depends": ["bitarray"], "file_name": "bitarray-tests.tar", "imports": [], "install_dir": "site", "name": "bitarray-tests", "package_type": "package", "sha256": "bc8a637cb3b2a839be949245ce8ee699d8fded2b5c50baf3a92ce52df776d3cf", "unvendored_tests": false, "version": "2.9.2"}, "bitstring": {"depends": ["bitarray"], "file_name": "bitstring-4.1.4-py3-none-any.whl", "imports": ["bitstring"], "install_dir": "site", "name": "bitstring", "package_type": "package", "sha256": "30a87a2037106772804bc253342df5df13b982145377ec4cd096899ca4303f4c", "unvendored_tests": false, "version": "4.1.4"}, "bleach": {"depends": ["webencodings", "packaging", "six"], "file_name": "bleach-6.1.0-py3-none-any.whl", "imports": ["bleach"], "install_dir": "site", "name": "bleach", "package_type": "package", "sha256": "961d704d008acabfe76acd1d6a1d74698cc8a855b838e507aa464e0b6ec40a42", "unvendored_tests": false, "version": "6.1.0"}, "bokeh": {"depends": ["contourpy", "numpy", "jinja2", "pandas", "pillow", "python-dateutil", "six", "typing-extensions", "pyyaml", "xyzservices"], "file_name": "bokeh-3.6.0-py3-none-any.whl", "imports": ["bokeh"], "install_dir": "site", "name": "bokeh", "package_type": "package", "sha256": "897ad588d4724f83ce0476838fe0f2d32aba7fe28daa0f8347eab06569631a90", "unvendored_tests": false, "version": "3.6.0"}, "boost-histogram": {"depends": ["numpy"], "file_name": "boost_histogram-1.5.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["boost_histogram"], "install_dir": "site", "name": "boost-histogram", "package_type": "package", "sha256": "a685186d8f3656bf031d1ebb3e6cc3903d6158fbb4981705c1feb8d02124fa90", "unvendored_tests": false, "version": "1.5.0"}, "brotli": {"depends": [], "file_name": "brotli-1.1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["brotli"], "install_dir": "site", "name": "brotli", "package_type": "package", "sha256": "182ec62565262bcb26448596586f171c77d2dbaa4d440907dd8b99590222367c", "unvendored_tests": false, "version": "1.1.0"}, "buffer-test": {"depends": [], "file_name": "buffer_test-0.1.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["buffer_test"], "install_dir": "site", "name": "buffer-test", "package_type": "package", "sha256": "10c9ebed5601166dc8fb20daabd58fba388a53f37812ffb0bf7d98dceb17d32e", "unvendored_tests": false, "version": "0.1.1"}, "cachetools": {"depends": [], "file_name": "cachetools-5.3.3-py3-none-any.whl", "imports": ["cachetools"], "install_dir": "site", "name": "cachetools", "package_type": "package", "sha256": "eff8dd237ade14c81f23b404dd2fb0160304b9f96943bdd4e4ec0e24de946542", "unvendored_tests": false, "version": "5.3.3"}, "cartopy": {"depends": ["shapely", "pyshp", "pyproj", "geos", "matplotlib", "scipy"], "file_name": "cartopy-0.24.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cartopy"], "install_dir": "site", "name": "Cartopy", "package_type": "package", "sha256": "9f27c8deb3e9f232272a8595b79b61a66a5cec82886c89ac0413f5a241b1eda6", "unvendored_tests": true, "version": "0.24.1"}, "cartopy-tests": {"depends": ["Cartopy"], "file_name": "cartopy-tests.tar", "imports": [], "install_dir": "site", "name": "Cartopy-tests", "package_type": "package", "sha256": "d291e7ee14a0a3f5e935791c87e9e4a1f93e843e850cd00f144a85eb48de2caa", "unvendored_tests": false, "version": "0.24.1"}, "casadi": {"depends": ["numpy"], "file_name": "casadi-3.6.7-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["casadi"], "install_dir": "site", "name": "casadi", "package_type": "package", "sha256": "c347ca18e190c7ed0f69f28b26d7f12627e865bc219da5041c749f3e647b9d67", "unvendored_tests": false, "version": "3.6.7"}, "cbor-diag": {"depends": [], "file_name": "cbor_diag-1.0.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cbor_diag"], "install_dir": "site", "name": "cbor-diag", "package_type": "package", "sha256": "06f9c6a26c12def09ff8ebf5b31c00ab53091e8ad37770339f87970dfafca949", "unvendored_tests": false, "version": "1.0.1"}, "certifi": {"depends": [], "file_name": "certifi-2024.12.14-py3-none-any.whl", "imports": ["certifi"], "install_dir": "site", "name": "certifi", "package_type": "package", "sha256": "a5f31d8fbcd66632ba9fe6face6471c4d4df2e85cd6c46bd0c5ff58eb903a4ad", "unvendored_tests": false, "version": "2024.12.14"}, "cffi": {"depends": ["pycparser"], "file_name": "cffi-1.17.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cffi"], "install_dir": "site", "name": "cffi", "package_type": "package", "sha256": "3844b091b8da880622d16c428a545d6a2753dfc148240f1328019375e6f70868", "unvendored_tests": false, "version": "1.17.1"}, "cffi-example": {"depends": ["cffi"], "file_name": "cffi_example-0.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cffi_example"], "install_dir": "site", "name": "cffi_example", "package_type": "package", "sha256": "a70ec7a3ad385297c242d6c6f1c05fb0bc2ff3148586514323b5fb128591ef3d", "unvendored_tests": false, "version": "0.1"}, "cftime": {"depends": ["numpy"], "file_name": "cftime-1.6.4.post1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cftime"], "install_dir": "site", "name": "cftime", "package_type": "package", "sha256": "485abc24c9539fa7d4db3ebbac812e2472921dfd1ef1ed6290008856dc2164a1", "unvendored_tests": false, "version": "1.6.4.post1"}, "charset-normalizer": {"depends": [], "file_name": "charset_normalizer-3.3.2-py3-none-any.whl", "imports": ["charset_normalizer"], "install_dir": "site", "name": "charset-normalizer", "package_type": "package", "sha256": "b83440eee4a1398f9a71186169cdc17b84cdb93a63e61f3c6347dd1463a11fca", "unvendored_tests": false, "version": "3.3.2"}, "clarabel": {"depends": ["numpy", "scipy"], "file_name": "clarabel-0.9.0-cp37-abi3-pyodide_2024_0_wasm32.whl", "imports": ["clarabel"], "install_dir": "site", "name": "clarabel", "package_type": "package", "sha256": "ea23a4776d99d9b20e1ddf2494f87fac9ecee00557c9228cdb1571c1e1f787e4", "unvendored_tests": false, "version": "0.9.0"}, "click": {"depends": [], "file_name": "click-8.1.7-py3-none-any.whl", "imports": ["click"], "install_dir": "site", "name": "click", "package_type": "package", "sha256": "b775249c5e122a827749407ad5540e6ac9a4b5a07692080993b8d95f5f82cb3a", "unvendored_tests": false, "version": "8.1.7"}, "cligj": {"depends": ["click"], "file_name": "cligj-0.7.2-py3-none-any.whl", "imports": ["cligj"], "install_dir": "site", "name": "cligj", "package_type": "package", "sha256": "a8b27eb22645f5199f9b706a513933d7c3803da47dceeea047bf3a2d12bcd761", "unvendored_tests": false, "version": "0.7.2"}, "clingo": {"depends": ["cffi"], "file_name": "clingo-5.7.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["clingo"], "install_dir": "site", "name": "clingo", "package_type": "package", "sha256": "4a8b320d1586393d589aae2dbca3c4b2c7711b48578910562e03389f7ed71732", "unvendored_tests": false, "version": "5.7.1"}, "cloudpickle": {"depends": [], "file_name": "cloudpickle-3.0.0-py3-none-any.whl", "imports": ["cloudpickle"], "install_dir": "site", "name": "cloudpickle", "package_type": "package", "sha256": "9625085cc9e9f1a3fbd2b22f7cab1277afdda4b091136d68a98a115659f6d993", "unvendored_tests": false, "version": "3.0.0"}, "cmyt": {"depends": ["colorspacious", "matplotlib", "more-itertools", "numpy"], "file_name": "cmyt-2.0.0-py3-none-any.whl", "imports": ["cmyt"], "install_dir": "site", "name": "cmyt", "package_type": "package", "sha256": "8a84417a5bb77a22b18c497af95397194f9322e2f61f1846e05f3526057095e4", "unvendored_tests": true, "version": "2.0.0"}, "cmyt-tests": {"depends": ["cmyt"], "file_name": "cmyt-tests.tar", "imports": [], "install_dir": "site", "name": "cmyt-tests", "package_type": "package", "sha256": "9918a274a353ec6228a3fe85bcc8c1526fdd9b31a3abac76a56b8a15d06ef6d0", "unvendored_tests": false, "version": "2.0.0"}, "colorspacious": {"depends": ["numpy"], "file_name": "colorspacious-1.1.2-py2.py3-none-any.whl", "imports": ["colorspacious"], "install_dir": "site", "name": "colorspacious", "package_type": "package", "sha256": "d0c49422117b29773267f61eede2f1010753889af797ddc9c14f0f227e7241c7", "unvendored_tests": false, "version": "1.1.2"}, "contourpy": {"depends": ["numpy"], "file_name": "contourpy-1.3.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["contourpy"], "install_dir": "site", "name": "contourpy", "package_type": "package", "sha256": "f6ca0437a039c40691be53ff5bd3c9774868add8d5c2d032167495c6ff1f1c4b", "unvendored_tests": false, "version": "1.3.0"}, "coolprop": {"depends": ["numpy", "matplotlib"], "file_name": "coolprop-6.6.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["CoolProp"], "install_dir": "site", "name": "coolprop", "package_type": "package", "sha256": "e1a3b369385520e9c363f406a572c202fdb279c7378b598f4b24be2ff06d80ee", "unvendored_tests": true, "version": "6.6.0"}, "coolprop-tests": {"depends": ["coolprop"], "file_name": "coolprop-tests.tar", "imports": [], "install_dir": "site", "name": "coolprop-tests", "package_type": "package", "sha256": "24c8b6e386b46c6bf95ef70c6a378cc7bf8333bf10ece309719f39d9b0a4e36a", "unvendored_tests": false, "version": "6.6.0"}, "coverage": {"depends": ["sqlite3"], "file_name": "coverage-7.4.4-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["coverage"], "install_dir": "site", "name": "coverage", "package_type": "package", "sha256": "d26ca50b543df98d77de221462b691ab33f49b997f07abf43957e2f078e06a18", "unvendored_tests": false, "version": "7.4.4"}, "cpp-exceptions-test": {"depends": [], "file_name": "cpp-exceptions-test-0.1.zip", "imports": [], "install_dir": "dynlib", "name": "cpp-exceptions-test", "package_type": "shared_library", "sha256": "a735e762e9aa55e6008086f70cd7c2e9dda8eb01e271277d4b2c8d1ac905133e", "unvendored_tests": false, "version": "0.1"}, "cpp-exceptions-test2": {"depends": [], "file_name": "cpp_exceptions_test2-1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cpp-exceptions-test2"], "install_dir": "site", "name": "cpp-exceptions-test2", "package_type": "package", "sha256": "6290e7e33f2be1f6a4f931c1cc526807ac5b5d291d482e0fc4603b31785e3034", "unvendored_tests": false, "version": "1.0"}, "cramjam": {"depends": [], "file_name": "cramjam-2.8.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cramjam"], "install_dir": "site", "name": "cramjam", "package_type": "package", "sha256": "da6bef32a15029038cd90aa561503462000a046c39fd6061e6ffa8c74e0dca13", "unvendored_tests": false, "version": "2.8.3"}, "crc32c": {"depends": [], "file_name": "crc32c-2.7.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["crc32c"], "install_dir": "site", "name": "crc32c", "package_type": "package", "sha256": "dddd5d0d25a60c0709c82c2351f8693b016ec6b0189a0cb9122e15cf88ca728c", "unvendored_tests": false, "version": "2.7.1"}, "cryptography": {"depends": ["openssl", "six", "cffi"], "file_name": "cryptography-42.0.5-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cryptography"], "install_dir": "site", "name": "cryptography", "package_type": "package", "sha256": "c336f40273d92660cfa8bc2b4180c197ee733d4582e9201be5397072715c6436", "unvendored_tests": false, "version": "42.0.5"}, "css-inline": {"depends": [], "file_name": "css_inline-0.14.6-cp37-abi3-pyodide_2024_0_wasm32.whl", "imports": ["css_inline"], "install_dir": "site", "name": "css-inline", "package_type": "package", "sha256": "863c3e7a93577ef93c76ed6653b68be31f5220dead771e190dce076679fa8daf", "unvendored_tests": false, "version": "0.14.6"}, "cssselect": {"depends": [], "file_name": "cssselect-1.2.0-py2.py3-none-any.whl", "imports": ["cssselect"], "install_dir": "site", "name": "cssselect", "package_type": "package", "sha256": "4514b2ffe110a100b0430737debd989421a75472c47e5e09f09b36f81e81a6e2", "unvendored_tests": false, "version": "1.2.0"}, "cvxpy-base": {"depends": ["numpy", "scipy", "clarabel"], "file_name": "cvxpy_base-1.5.1-py3-none-any.whl", "imports": ["cvxpy"], "install_dir": "site", "name": "cvxpy-base", "package_type": "package", "sha256": "74147367dfe5e688420bc612335681aef26ac0e3770db5c56291b761ed4bcb99", "unvendored_tests": true, "version": "1.5.1"}, "cvxpy-base-tests": {"depends": ["cvxpy-base"], "file_name": "cvxpy-base-tests.tar", "imports": [], "install_dir": "site", "name": "cvxpy-base-tests", "package_type": "package", "sha256": "aeab1ec32f46deca69ed23a4393683a07d13da7f7b97b2a6be2745f5570cdcf9", "unvendored_tests": false, "version": "1.5.1"}, "cycler": {"depends": ["six"], "file_name": "cycler-0.12.1-py3-none-any.whl", "imports": ["cycler"], "install_dir": "site", "name": "cycler", "package_type": "package", "sha256": "e33687b4269fe3eda13c2d38006f9a5daa602c95f5c4f8d0576aff0717d001a6", "unvendored_tests": false, "version": "0.12.1"}, "cysignals": {"depends": [], "file_name": "cysignals-1.12.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cysignals"], "install_dir": "site", "name": "cysignals", "package_type": "package", "sha256": "3506506c50cf26fd1fb09874f6561e9faca98eab37fd0b114258226bc3131067", "unvendored_tests": false, "version": "1.12.2"}, "cytoolz": {"depends": ["toolz"], "file_name": "cytoolz-0.12.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cytoolz"], "install_dir": "site", "name": "cytoolz", "package_type": "package", "sha256": "dc4027bdec5336ece9480c651a72ee35749b0f76c8e5801f67be34125766e0c8", "unvendored_tests": true, "version": "0.12.3"}, "cytoolz-tests": {"depends": ["cytoolz"], "file_name": "cytoolz-tests.tar", "imports": [], "install_dir": "site", "name": "cytoolz-tests", "package_type": "package", "sha256": "820bb9e3afa033a112cf82f57cf11fa5f2877b86464795ca8af2742280e8ea43", "unvendored_tests": false, "version": "0.12.3"}, "decorator": {"depends": [], "file_name": "decorator-5.1.1-py3-none-any.whl", "imports": ["decorator"], "install_dir": "site", "name": "decorator", "package_type": "package", "sha256": "54f90d6b6745fbb89eb7a1d36252862cda4ca111a945930adf6c3c927e17a1e8", "unvendored_tests": false, "version": "5.1.1"}, "demes": {"depends": ["attrs", "ruamel.yaml"], "file_name": "demes-0.2.3-py3-none-any.whl", "imports": ["demes"], "install_dir": "site", "name": "demes", "package_type": "package", "sha256": "aee96e88ff3af0031e0b08fd7178137712f404ee79d018fa22da70ee1eb9afb8", "unvendored_tests": false, "version": "0.2.3"}, "deprecation": {"depends": ["packaging"], "file_name": "deprecation-2.1.0-py2.py3-none-any.whl", "imports": ["deprecation"], "install_dir": "site", "name": "deprecation", "package_type": "package", "sha256": "cbe0ed9f57a41763288d4c186a5724049f705fc41db175407834602015994c63", "unvendored_tests": false, "version": "2.1.0"}, "distlib": {"depends": [], "file_name": "distlib-0.3.8-py2.py3-none-any.whl", "imports": ["distlib"], "install_dir": "site", "name": "distlib", "package_type": "package", "sha256": "ff3261bf3cb0a0101cee422b7ed068c493195452eee65b4a2dba235ba0690084", "unvendored_tests": false, "version": "0.3.8"}, "distro": {"depends": [], "file_name": "distro-1.9.0-py3-none-any.whl", "imports": ["distro"], "install_dir": "site", "name": "distro", "package_type": "package", "sha256": "697c8eca85a124c7448336dcfdcf6862c846a181e1c6430bc35120efffd24878", "unvendored_tests": false, "version": "1.9.0"}, "docutils": {"depends": [], "file_name": "docutils-0.21.1-py3-none-any.whl", "imports": ["docutils"], "install_dir": "site", "name": "docutils", "package_type": "package", "sha256": "87488ae4de9b3078ae4b1312a283999744b8c805ee724a6dfaec1ac629084dca", "unvendored_tests": false, "version": "0.21.1"}, "duckdb": {"depends": [], "file_name": "duckdb-1.1.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["duckdb"], "install_dir": "site", "name": "duckdb", "package_type": "package", "sha256": "eb068fe5ea3d8be969a5f6a6d03fcc835749a5d2c60cd7ca3e3d0fb670d77c2f", "unvendored_tests": false, "version": "1.1.2"}, "ewah-bool-utils": {"depends": [], "file_name": "ewah_bool_utils-1.2.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["ewah_bool_utils"], "install_dir": "site", "name": "ewah_bool_utils", "package_type": "package", "sha256": "e03c418e886c0e1eb7880056c8aae7da0ef42048aadfffe50275ff3fe517cf3f", "unvendored_tests": true, "version": "1.2.2"}, "ewah-bool-utils-tests": {"depends": ["ewah_bool_utils"], "file_name": "ewah-bool-utils-tests.tar", "imports": [], "install_dir": "site", "name": "ewah_bool_utils-tests", "package_type": "package", "sha256": "3dd445a828362da0931cb49cb0e3e89d91a1a98ae88f9350c1874edee8935fc5", "unvendored_tests": false, "version": "1.2.2"}, "exceptiongroup": {"depends": [], "file_name": "exceptiongroup-1.2.1-py3-none-any.whl", "imports": ["exceptiongroup"], "install_dir": "site", "name": "exceptiongroup", "package_type": "package", "sha256": "7137d0f93bb14003e13e0563a5ca817f4227aa7e57547a09afaf38b734ec106d", "unvendored_tests": false, "version": "1.2.1"}, "executing": {"depends": [], "file_name": "executing-2.0.1-py2.py3-none-any.whl", "imports": ["executing"], "install_dir": "site", "name": "executing", "package_type": "package", "sha256": "cfc677eb1eae5a13a502f324450ff9227bf66ad21ed83221e865f280b88dd09b", "unvendored_tests": false, "version": "2.0.1"}, "fastparquet": {"depends": ["cramjam", "numpy", "pandas", "fsspec", "packaging"], "file_name": "fastparquet-2024.5.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["fastparquet"], "install_dir": "site", "name": "fastparquet", "package_type": "package", "sha256": "b3d043c0d82ef617e86883cec008d57cec6ea0fdf2686b467d621ed75c4592b5", "unvendored_tests": false, "version": "2024.5.0"}, "fiona": {"depends": ["attrs", "certifi", "setuptools", "six", "click", "cligj"], "file_name": "fiona-1.9.5-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["fiona"], "install_dir": "site", "name": "fiona", "package_type": "package", "sha256": "2fb8e9f23bad7564e65af26ccfcce829764da5a0480f72f4b59994ed39f69153", "unvendored_tests": false, "version": "1.9.5"}, "fonttools": {"depends": [], "file_name": "fonttools-4.51.0-py3-none-any.whl", "imports": ["fontTools"], "install_dir": "site", "name": "fonttools", "package_type": "package", "sha256": "0c9a46b9246333de02d0fe02c0580840d7136744121f256a870218ed7482b607", "unvendored_tests": false, "version": "4.51.0"}, "fpcast-test": {"depends": [], "file_name": "fpcast_test-0.1.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["fpcast_test"], "install_dir": "site", "name": "fpcast-test", "package_type": "package", "sha256": "091e8dc5617759c6a952612d7d593335f98b0f590fc3146aed10634100801554", "unvendored_tests": false, "version": "0.1.1"}, "freesasa": {"depends": [], "file_name": "freesasa-2.2.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["freesasa"], "install_dir": "site", "name": "freesasa", "package_type": "package", "sha256": "b5145a96fede0cfb3ac87569a7038e86447303c3b51450ee2e889d157401ef8e", "unvendored_tests": false, "version": "2.2.1"}, "frozenlist": {"depends": [], "file_name": "frozenlist-1.4.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["frozenlist"], "install_dir": "site", "name": "frozenlist", "package_type": "package", "sha256": "d53912a6038aef81b1623921908827a839ec4eafa0ed0b6fa8d45e5d17d827df", "unvendored_tests": false, "version": "1.4.1"}, "fsspec": {"depends": [], "file_name": "fsspec-2025.3.2-py3-none-any.whl", "imports": ["fsspec"], "install_dir": "site", "name": "fsspec", "package_type": "package", "sha256": "977bc3c67514d3a4d579cfc993cff0e95cb37f309159b6cfc290f58618498f95", "unvendored_tests": true, "version": "2025.3.2"}, "fsspec-tests": {"depends": ["fsspec"], "file_name": "fsspec-tests.tar", "imports": [], "install_dir": "site", "name": "fsspec-tests", "package_type": "package", "sha256": "8f277582d07e3573ccb6058042cd29d2d07058ad1b82263a4df30321b6b34459", "unvendored_tests": false, "version": "2025.3.2"}, "future": {"depends": [], "file_name": "future-1.0.0-py3-none-any.whl", "imports": ["future"], "install_dir": "site", "name": "future", "package_type": "package", "sha256": "7e2c052f9ef30fba5ef92bfcf7b52d5b755dd778bd312dd0bf9ba3eb9884fbf9", "unvendored_tests": true, "version": "1.0.0"}, "future-tests": {"depends": ["future"], "file_name": "future-tests.tar", "imports": [], "install_dir": "site", "name": "future-tests", "package_type": "package", "sha256": "e2b2b6337da4048844588ae46edb457e3be12fde3711e1c5d273410d3f5c2b25", "unvendored_tests": false, "version": "1.0.0"}, "galpy": {"depends": ["numpy", "scipy", "matplotlib", "astropy", "future", "setuptools"], "file_name": "galpy-1.10.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["galpy"], "install_dir": "site", "name": "galpy", "package_type": "package", "sha256": "dfd8bc97951b7b5f2745231245741e77c4cbebec8caacc386b307db5350d1d2d", "unvendored_tests": false, "version": "1.10.1"}, "gdal": {"depends": ["geos"], "file_name": "gdal-3.8.3.zip", "imports": [], "install_dir": "dynlib", "name": "gdal", "package_type": "shared_library", "sha256": "cada0402f7c2dbe56c88bbf095a2847b07e35d6612836313a451adeb3ab83eac", "unvendored_tests": false, "version": "3.8.3"}, "gensim": {"depends": ["numpy", "scipy", "six", "smart-open", "wrapt"], "file_name": "gensim-4.3.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["gensim"], "install_dir": "site", "name": "gensim", "package_type": "package", "sha256": "63068eafcf08fb80eb6568221fedce54ded2c21d1401b59e00dcd6e7e31cb159", "unvendored_tests": true, "version": "4.3.3"}, "gensim-tests": {"depends": ["gensim"], "file_name": "gensim-tests.tar", "imports": [], "install_dir": "site", "name": "gensim-tests", "package_type": "package", "sha256": "cf4747e0a517fec2a2384c9820b8627d8e587d72f78f9a7524595996740ac31a", "unvendored_tests": false, "version": "4.3.3"}, "geopandas": {"depends": ["shapely", "fiona", "pyproj", "packaging", "pandas"], "file_name": "geopandas-1.0.1-py3-none-any.whl", "imports": ["geopandas"], "install_dir": "site", "name": "geopandas", "package_type": "package", "sha256": "4d60379b3681d1ff6684ddabfa14b959587a577be1b74caa436153614e59671f", "unvendored_tests": true, "version": "1.0.1"}, "geopandas-tests": {"depends": ["geopandas"], "file_name": "geopandas-tests.tar", "imports": [], "install_dir": "site", "name": "geopandas-tests", "package_type": "package", "sha256": "19d11975add31835b37a921de900b8e7e2bb46b20423040bb574dd794692b1fb", "unvendored_tests": false, "version": "1.0.1"}, "geos": {"depends": [], "file_name": "geos-3.12.1.zip", "imports": [], "install_dir": "dynlib", "name": "geos", "package_type": "shared_library", "sha256": "64400007fd90cac91e3d492a989734b09000ce5864403b91e4a6ffcd71900afa", "unvendored_tests": false, "version": "3.12.1"}, "gmpy2": {"depends": [], "file_name": "gmpy2-2.1.5-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["gmpy2"], "install_dir": "site", "name": "gmpy2", "package_type": "package", "sha256": "ebb4d157d170bf7b1e491afd4a38bc7b0c7d65c1bab0ee96d9356cde26543516", "unvendored_tests": false, "version": "2.1.5"}, "gsw": {"depends": ["numpy"], "file_name": "gsw-3.6.19-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["gsw"], "install_dir": "site", "name": "gsw", "package_type": "package", "sha256": "146bf94684e7f06b03d9641f11df2f540f45494e8052df42a584ecc163d2a9e7", "unvendored_tests": true, "version": "3.6.19"}, "gsw-tests": {"depends": ["gsw"], "file_name": "gsw-tests.tar", "imports": [], "install_dir": "site", "name": "gsw-tests", "package_type": "package", "sha256": "f5a93665eeed1120350142cebb8b09ef6dbfbd8387defa9b98ffb0811c0a6c2a", "unvendored_tests": false, "version": "3.6.19"}, "h11": {"depends": [], "file_name": "h11-0.14.0-py3-none-any.whl", "imports": ["h11"], "install_dir": "site", "name": "h11", "package_type": "package", "sha256": "179511e1878e1e4fb6739c944b7c653403cee7334041c6870f790a9f8029991a", "unvendored_tests": true, "version": "0.14.0"}, "h11-tests": {"depends": ["h11"], "file_name": "h11-tests.tar", "imports": [], "install_dir": "site", "name": "h11-tests", "package_type": "package", "sha256": "fd911473c62b2e4cc0bf33ea0a3e055b1c620db93c5745ccb519b5cf803da378", "unvendored_tests": false, "version": "0.14.0"}, "h3": {"depends": [], "file_name": "h3-4.2.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["h3"], "install_dir": "site", "name": "h3", "package_type": "package", "sha256": "d4e7270d91c942ed2f8124c839addad3cc1c7419cf3a661856680a25bb8da99b", "unvendored_tests": false, "version": "4.2.1"}, "h5py": {"depends": ["numpy", "pkgconfig"], "file_name": "h5py-3.12.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["h5py"], "install_dir": "site", "name": "h5py", "package_type": "package", "sha256": "a56b66beb6c8708b128299e414fc9a1d646b1a432e04822059a7c3fcfaaf9e10", "unvendored_tests": true, "version": "3.12.1"}, "h5py-tests": {"depends": ["h5py"], "file_name": "h5py-tests.tar", "imports": [], "install_dir": "site", "name": "h5py-tests", "package_type": "package", "sha256": "3bf38920307fa0f08368d49694bfde6e9f56318080a7a74a553f8a27aa42bcf0", "unvendored_tests": false, "version": "3.12.1"}, "hashlib": {"depends": ["openssl"], "file_name": "hashlib-1.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["_hashlib"], "install_dir": "site", "name": "hashlib", "package_type": "cpython_module", "sha256": "4a6971a70bf547ad93f011e121392803ce1595e62e8b3ca719ffa3ec91384722", "unvendored_tests": false, "version": "1.0.0"}, "html5lib": {"depends": ["webencodings", "six"], "file_name": "html5lib-1.1-py2.py3-none-any.whl", "imports": ["html5lib"], "install_dir": "site", "name": "html5lib", "package_type": "package", "sha256": "8faa3cdcfaf78900c25c50552cae5ddea0898d985d676f4efb163e319975f6e7", "unvendored_tests": false, "version": "1.1"}, "httpcore": {"depends": ["certifi", "h11", "ssl"], "file_name": "httpcore-1.0.7-py3-none-any.whl", "imports": ["httpcore"], "install_dir": "site", "name": "httpcore", "package_type": "package", "sha256": "2409f092fbd9ae88a1e31899e1e2e97c5955fa3fac22a5f1765c2b546b1a581e", "unvendored_tests": false, "version": "1.0.7"}, "httpx": {"depends": [], "file_name": "httpx-0.28.1-py3-none-any.whl", "imports": ["httpx"], "install_dir": "site", "name": "httpx", "package_type": "package", "sha256": "4ca06d11b8dc47f96ec55f5ad601ea95a22d34cde012af826d2ba7640f051a7c", "unvendored_tests": false, "version": "0.28.1"}, "idna": {"depends": [], "file_name": "idna-3.7-py3-none-any.whl", "imports": ["idna"], "install_dir": "site", "name": "idna", "package_type": "package", "sha256": "9d4685891e3e37434e09b1becda7e96a284e660c7aea9222564d88b6c3527c09", "unvendored_tests": false, "version": "3.7"}, "igraph": {"depends": ["texttable"], "file_name": "igraph-0.11.4-cp39-abi3-pyodide_2024_0_wasm32.whl", "imports": ["igraph"], "install_dir": "site", "name": "igraph", "package_type": "package", "sha256": "9f6bd011e677db3f84e573f24590b774f5d1fd8b92af92d94b163d716f582bf3", "unvendored_tests": false, "version": "0.11.4"}, "imageio": {"depends": ["numpy", "pillow"], "file_name": "imageio-2.36.0-py3-none-any.whl", "imports": ["imageio"], "install_dir": "site", "name": "imageio", "package_type": "package", "sha256": "f87ca5f6fc8c965ac35c9d9e716c4691f87923088b1f53a5a09d67f2c6c3d6e6", "unvendored_tests": false, "version": "2.36.0"}, "iminuit": {"depends": ["numpy"], "file_name": "iminuit-2.30.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["iminuit"], "install_dir": "site", "name": "iminuit", "package_type": "package", "sha256": "4a13e54d477ef824d4e94fc2c4acf52a1d795c58596970e4b1cc9e52882759bc", "unvendored_tests": false, "version": "2.30.1"}, "iniconfig": {"depends": [], "file_name": "iniconfig-2.0.0-py3-none-any.whl", "imports": ["iniconfig"], "install_dir": "site", "name": "iniconfig", "package_type": "package", "sha256": "92ecd073d77c7da9cd53c8f4fdd46c1c2562c082ece2c9f23b71d7ad0f2a89af", "unvendored_tests": false, "version": "2.0.0"}, "ipython": {"depends": ["asttokens", "decorator", "executing", "matplotlib-inline", "prompt_toolkit", "pure-eval", "pygments", "six", "stack-data", "traitlets", "sqlite3", "wcwidth"], "file_name": "ipython-8.23.0-py3-none-any.whl", "imports": ["IPython"], "install_dir": "site", "name": "ipython", "package_type": "package", "sha256": "af05617e0f9bb869649a662b33081d0d6f3de017b50f425b3acf5c4da3a28cd2", "unvendored_tests": true, "version": "8.23.0"}, "ipython-tests": {"depends": ["ipython"], "file_name": "ipython-tests.tar", "imports": [], "install_dir": "site", "name": "ipython-tests", "package_type": "package", "sha256": "7fb4c87c339f28ae5335fd5a0c1836f63cfdca379175ea335c61cadff60427fd", "unvendored_tests": false, "version": "8.23.0"}, "jedi": {"depends": ["parso"], "file_name": "jedi-0.19.1-py2.py3-none-any.whl", "imports": ["jedi"], "install_dir": "site", "name": "jedi", "package_type": "package", "sha256": "31edb344d473e145a029392523e637386bfc6a1977b22e2305e034c96eb27b2a", "unvendored_tests": true, "version": "0.19.1"}, "jedi-tests": {"depends": ["jedi"], "file_name": "jedi-tests.tar", "imports": [], "install_dir": "site", "name": "jedi-tests", "package_type": "package", "sha256": "c23da9850f5f5d71e132ed8c28100be3d203ddd7f01feec02b4b6c173f6737e9", "unvendored_tests": false, "version": "0.19.1"}, "jinja2": {"depends": ["markupsafe"], "file_name": "Jinja2-3.1.3-py3-none-any.whl", "imports": ["jinja2"], "install_dir": "site", "name": "Jinja2", "package_type": "package", "sha256": "2c74f33712082b6807f96c6ad4466fe57307d79659887078952f1fa6572580b7", "unvendored_tests": false, "version": "3.1.3"}, "jiter": {"depends": [], "file_name": "jiter-0.8.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["jiter"], "install_dir": "site", "name": "jiter", "package_type": "package", "sha256": "ff0beeb857eedae373da0be5798f86ee34699ce6136afa439d0355f19ebdacd0", "unvendored_tests": false, "version": "0.8.2"}, "joblib": {"depends": [], "file_name": "joblib-1.4.0-py3-none-any.whl", "imports": ["joblib"], "install_dir": "site", "name": "joblib", "package_type": "package", "sha256": "c4a3bb8273356564230296537aae1c175e8fcc6bd998af6b9ab1be74e2d141b6", "unvendored_tests": true, "version": "1.4.0"}, "joblib-tests": {"depends": ["joblib"], "file_name": "joblib-tests.tar", "imports": [], "install_dir": "site", "name": "joblib-tests", "package_type": "package", "sha256": "aa5c52a8673fc23d6f569cfa538ff0e9bff60221ddc09aaf70509ad307bc235f", "unvendored_tests": false, "version": "1.4.0"}, "jsonschema": {"depends": ["attrs", "pyrsistent", "referencing", "jsonschema_specifications"], "file_name": "jsonschema-4.21.1-py3-none-any.whl", "imports": ["jsonschema"], "install_dir": "site", "name": "jsonschema", "package_type": "package", "sha256": "0a9f52c1cf0dab8ee5c0f5b63b08cd3a588c6192f4e22739caaed4f004676409", "unvendored_tests": true, "version": "4.21.1"}, "jsonschema-specifications": {"depends": [], "file_name": "jsonschema_specifications-2023.12.1-py3-none-any.whl", "imports": ["jsonschema_specifications"], "install_dir": "site", "name": "jsonschema_specifications", "package_type": "package", "sha256": "8d3299fdb995a6e68a78b6882e110b20dce641f7c6896bb4da4c7237c476a515", "unvendored_tests": true, "version": "2023.12.1"}, "jsonschema-specifications-tests": {"depends": ["jsonschema_specifications"], "file_name": "jsonschema-specifications-tests.tar", "imports": [], "install_dir": "site", "name": "jsonschema_specifications-tests", "package_type": "package", "sha256": "b253891ed105b4a530508915b8741be209160bb88d4b0d263d94b3424a826543", "unvendored_tests": false, "version": "2023.12.1"}, "jsonschema-tests": {"depends": ["jsonschema"], "file_name": "jsonschema-tests.tar", "imports": [], "install_dir": "site", "name": "jsonschema-tests", "package_type": "package", "sha256": "be754ae8b11e979de484760b6c55c9fbc65af439500133e6f70342368274561c", "unvendored_tests": false, "version": "4.21.1"}, "kiwisolver": {"depends": [], "file_name": "kiwisolver-1.4.5-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["kiwisolver"], "install_dir": "site", "name": "kiwisolver", "package_type": "package", "sha256": "d7652d88b3390d9d1d0175d6c79da675b42bac2cd748cc9b5766a3235da4b762", "unvendored_tests": false, "version": "1.4.5"}, "lakers-python": {"depends": [], "file_name": "lakers_python-0.4.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["lakers"], "install_dir": "site", "name": "lakers-python", "package_type": "package", "sha256": "58f5612fc9fa82debb839ca2fff8625019057eca09872f9a8b9203ba8007febe", "unvendored_tests": false, "version": "0.4.1"}, "lazy-loader": {"depends": [], "file_name": "lazy_loader-0.4-py3-none-any.whl", "imports": ["lazy_loader"], "install_dir": "site", "name": "lazy_loader", "package_type": "package", "sha256": "b2d18752ff3fed4cd3cf7c23a88f84d9b87055c80eae2689ffe809cf766b763a", "unvendored_tests": true, "version": "0.4"}, "lazy-loader-tests": {"depends": ["lazy_loader"], "file_name": "lazy-loader-tests.tar", "imports": [], "install_dir": "site", "name": "lazy_loader-tests", "package_type": "package", "sha256": "d84c83c43ecdb504e58e7df246625117191ec84094e5ccf43867d8e7e7adf8ad", "unvendored_tests": false, "version": "0.4"}, "lazy-object-proxy": {"depends": [], "file_name": "lazy_object_proxy-1.10.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["lazy_object_proxy"], "install_dir": "site", "name": "lazy-object-proxy", "package_type": "package", "sha256": "2d8ca147965162cb0621906b5181b2589adabf2d1deebfb99d97b3bddf1bf118", "unvendored_tests": false, "version": "1.10.0"}, "libcst": {"depends": ["pyyaml"], "file_name": "libcst-1.4.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["libcst"], "install_dir": "site", "name": "libcst", "package_type": "package", "sha256": "5118f345836eb6c09ddf0e20c36fcd6de26d2b2e2f4bee380dab55ec36faa234", "unvendored_tests": true, "version": "1.4.0"}, "libcst-tests": {"depends": ["libcst"], "file_name": "libcst-tests.tar", "imports": [], "install_dir": "site", "name": "libcst-tests", "package_type": "package", "sha256": "f4bad6fc8af8a50e7178d4d2f3927f18abcb52c00546edde62f8c40c3ddd7d8c", "unvendored_tests": false, "version": "1.4.0"}, "libhdf5": {"depends": [], "file_name": "libhdf5-1.12.1.zip", "imports": [], "install_dir": "dynlib", "name": "libhdf5", "package_type": "shared_library", "sha256": "fe57d527663650699e65ee35c98072e13085eccf231bedb489388c1ca45141b4", "unvendored_tests": false, "version": "1.12.1"}, "libheif": {"depends": [], "file_name": "libheif-1.12.0.zip", "imports": [], "install_dir": "dynlib", "name": "libheif", "package_type": "shared_library", "sha256": "a24e7af8a123ecad7d446820486fb382745a522c4b48fcad340e11156e0cc92a", "unvendored_tests": false, "version": "1.12.0"}, "libmagic": {"depends": [], "file_name": "libmagic-5.42.zip", "imports": [], "install_dir": "dynlib", "name": "libmagic", "package_type": "shared_library", "sha256": "604ecf7fc42917b1c0c0c920ae0629427c48359b9afd25d928487bcf4ac44f83", "unvendored_tests": false, "version": "5.42"}, "lightgbm": {"depends": ["numpy", "scipy", "scikit-learn"], "file_name": "lightgbm-4.5.0-py3-none-pyodide_2024_0_wasm32.whl", "imports": ["lightgbm"], "install_dir": "site", "name": "lightgbm", "package_type": "package", "sha256": "2f24d464868ce07ef80061632c011f7f8e2564179cf6b781f403fd67732d456c", "unvendored_tests": false, "version": "4.5.0"}, "logbook": {"depends": ["ssl"], "file_name": "logbook-1.7.0.post0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["logbook"], "install_dir": "site", "name": "logbook", "package_type": "package", "sha256": "bfe651c3fe67842b543c34e3a0b3d42e9df3aa49e50f377bf9aa3362e7a8d80e", "unvendored_tests": false, "version": "1.7.0.post0"}, "lxml": {"depends": [], "file_name": "lxml-5.2.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["lxml"], "install_dir": "site", "name": "lxml", "package_type": "package", "sha256": "7213dd8b1c2bd24e37356d74454e463103b86bb5ff7dfaf1bd1794d8ff7ddc02", "unvendored_tests": false, "version": "5.2.1"}, "lzma": {"depends": [], "file_name": "lzma-1.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["lzma", "_lzma"], "install_dir": "site", "name": "lzma", "package_type": "cpython_module", "sha256": "51b77233960d4353deee46bd23b39ebfd53039835693f7dc2fa8858c88e8eee8", "unvendored_tests": false, "version": "1.0.0"}, "markupsafe": {"depends": [], "file_name": "markupsafe-2.1.5-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["markupsafe"], "install_dir": "site", "name": "MarkupSafe", "package_type": "package", "sha256": "cceab881a7705a8e219f480ed089c4f5b87aad34d704e49360a53173e83f2681", "unvendored_tests": false, "version": "2.1.5"}, "matplotlib": {"depends": ["contourpy", "cycler", "fonttools", "kiwisolver", "numpy", "packaging", "pillow", "pyparsing", "python-dateutil", "pytz", "matplotlib-pyodide"], "file_name": "matplotlib-3.8.4-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pylab", "mpl_toolkits", "matplotlib"], "install_dir": "site", "name": "matplotlib", "package_type": "package", "sha256": "50d4641b32e84ecb0a2c271728d4be73b1e0a0f5f29aa7dd6ea280f888b91340", "unvendored_tests": true, "version": "3.8.4"}, "matplotlib-inline": {"depends": ["traitlets"], "file_name": "matplotlib_inline-0.1.7-py3-none-any.whl", "imports": ["matplotlib-inline"], "install_dir": "site", "name": "matplotlib-inline", "package_type": "package", "sha256": "79a482aa6f83e758b6a60dae955c915682e9706bb8712e11a909a6eb7b0d1f2d", "unvendored_tests": false, "version": "0.1.7"}, "matplotlib-pyodide": {"depends": [], "file_name": "matplotlib_pyodide-0.2.3-py3-none-any.whl", "imports": ["matplotlib_pyodide"], "install_dir": "site", "name": "matplotlib-pyodide", "package_type": "package", "sha256": "070d6244e7ae44f8753d3a78cf5c30f93c8d781e620991af848dcfd44112839f", "unvendored_tests": false, "version": "0.2.3"}, "matplotlib-tests": {"depends": ["matplotlib"], "file_name": "matplotlib-tests.tar", "imports": [], "install_dir": "site", "name": "matplotlib-tests", "package_type": "package", "sha256": "f44d1d465da988ee9abed18c7aee1f6a8a551290e78fa744193125c5ceea9f83", "unvendored_tests": false, "version": "3.8.4"}, "memory-allocator": {"depends": [], "file_name": "memory_allocator-0.1.4-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["memory_allocator"], "install_dir": "site", "name": "memory-allocator", "package_type": "package", "sha256": "ded1d0f51d0c298d5362fcffd033374d97122e6b0a2570a75d15b99dd626ca3d", "unvendored_tests": false, "version": "0.1.4"}, "micropip": {"depends": ["packaging"], "file_name": "micropip-0.9.0-py3-none-any.whl", "imports": ["micropip"], "install_dir": "site", "name": "micropip", "package_type": "package", "sha256": "034f22763607744f982d2911170c50b496a38b8ba0535e5a09618475b1d7b051", "unvendored_tests": false, "version": "0.9.0"}, "mmh3": {"depends": [], "file_name": "mmh3-4.1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["mmh3"], "install_dir": "site", "name": "mmh3", "package_type": "package", "sha256": "7099904077a0dd337a0b0a0ba0316d9bd80fff4046444d9b24171e4ae24cc898", "unvendored_tests": false, "version": "4.1.0"}, "mne": {"depends": ["numpy", "scipy", "setuptools", "decorator", "lazy_loader", "packaging"], "file_name": "mne-1.8.0-py3-none-any.whl", "imports": ["mne"], "install_dir": "site", "name": "mne", "package_type": "package", "sha256": "783b45078798cc4f203aca82acf43353b3f738238c4906b45810b6931c28ac36", "unvendored_tests": true, "version": "1.8.0"}, "mne-tests": {"depends": ["mne"], "file_name": "mne-tests.tar", "imports": [], "install_dir": "site", "name": "mne-tests", "package_type": "package", "sha256": "1c93bd5f37ffb7c7fe3048c3db5694c767d55352c4d0cc91bd522ca52cc6ae03", "unvendored_tests": false, "version": "1.8.0"}, "more-itertools": {"depends": [], "file_name": "more_itertools-10.2.0-py3-none-any.whl", "imports": ["more_itertools"], "install_dir": "site", "name": "more-itertools", "package_type": "package", "sha256": "4dab4e88bb083f1c70bf48adca5098af88c0d59c87f4328bf878005c0949c6d7", "unvendored_tests": false, "version": "10.2.0"}, "mpmath": {"depends": [], "file_name": "mpmath-1.3.0-py3-none-any.whl", "imports": ["mpmath"], "install_dir": "site", "name": "mpmath", "package_type": "package", "sha256": "5c8b3c27ea61c54b90c56a5adf9ddb07d7c3591b80e9f83d4f03009bba6f5ac5", "unvendored_tests": true, "version": "1.3.0"}, "mpmath-tests": {"depends": ["mpmath"], "file_name": "mpmath-tests.tar", "imports": [], "install_dir": "site", "name": "mpmath-tests", "package_type": "package", "sha256": "e674fa6bd8810224d96eaa05197bfff61286f32b45ee2ad38ffda2b06b628a68", "unvendored_tests": false, "version": "1.3.0"}, "msgpack": {"depends": [], "file_name": "msgpack-1.1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["msgpack"], "install_dir": "site", "name": "msgpack", "package_type": "package", "sha256": "5eef122129d4f45f81a766989b0b7e93717188d04c3d8207cc0aa51f40942e7e", "unvendored_tests": false, "version": "1.1.0"}, "msgspec": {"depends": [], "file_name": "msgspec-0.18.6-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["msgspec"], "install_dir": "site", "name": "msgspec", "package_type": "package", "sha256": "897312e6a62138495162a039881bb90cd743777e7ea79e8ad22bb4ea4f1dd319", "unvendored_tests": false, "version": "0.18.6"}, "msprime": {"depends": ["numpy", "newick", "tskit", "demes", "rpds-py"], "file_name": "msprime-1.3.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["msprime"], "install_dir": "site", "name": "msprime", "package_type": "package", "sha256": "0fff280692699e1f7ed9e31352f2571c7efb20183cbee5319fc6438597f66007", "unvendored_tests": false, "version": "1.3.3"}, "multidict": {"depends": [], "file_name": "multidict-6.0.5-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["multidict"], "install_dir": "site", "name": "multidict", "package_type": "package", "sha256": "27bf80a8593b18b154f97b1e3d1874503f03d4e23ba7c97defdeb896aa489286", "unvendored_tests": false, "version": "6.0.5"}, "munch": {"depends": ["setuptools", "six"], "file_name": "munch-4.0.0-py2.py3-none-any.whl", "imports": ["munch"], "install_dir": "site", "name": "munch", "package_type": "package", "sha256": "7117c5b44033ad085870f479a2c019f881570f245223447c9627893f971438e7", "unvendored_tests": false, "version": "4.0.0"}, "mypy": {"depends": [], "file_name": "mypy-1.9.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["mypyc", "mypy"], "install_dir": "site", "name": "mypy", "package_type": "package", "sha256": "7e41f1ee7b77a91477788db77b17dc1cbe1342c3f6732fbcb5cc84d9e6962292", "unvendored_tests": true, "version": "1.9.0"}, "mypy-tests": {"depends": ["mypy"], "file_name": "mypy-tests.tar", "imports": [], "install_dir": "site", "name": "mypy-tests", "package_type": "package", "sha256": "03d347cb7e03befd6bbb44b71759f5177b855204d7632afa774e92f25ce113b2", "unvendored_tests": false, "version": "1.9.0"}, "narwhals": {"depends": [], "file_name": "narwhals-1.41.0-py3-none-any.whl", "imports": ["narwhals"], "install_dir": "site", "name": "narwhals", "package_type": "package", "sha256": "030d0f488d4b5b1f6497e43a12810e304f3bb994075b819338c15fe1cfce9f8a", "unvendored_tests": false, "version": "1.41.0"}, "netcdf4": {"depends": ["numpy", "packaging", "h5py", "cftime", "certifi"], "file_name": "netcdf4-1.7.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["netCDF4"], "install_dir": "site", "name": "netcdf4", "package_type": "package", "sha256": "8f552958adb12626ede6605974a6a9ee3bb225e16ea798eaa33502a04498b661", "unvendored_tests": false, "version": "1.7.2"}, "networkx": {"depends": ["decorator", "setuptools", "matplotlib", "numpy"], "file_name": "networkx-3.4.2-py3-none-any.whl", "imports": ["networkx"], "install_dir": "site", "name": "networkx", "package_type": "package", "sha256": "fc86ae678fdbab25783d543290dfd2fea8f9cc5161cdb4e61ce2687de57665bb", "unvendored_tests": true, "version": "3.4.2"}, "networkx-tests": {"depends": ["networkx"], "file_name": "networkx-tests.tar", "imports": [], "install_dir": "site", "name": "networkx-tests", "package_type": "package", "sha256": "41cd06690fc581bb786b93c2ea701d0fe399f048bb4ba95fb2cc182cef863555", "unvendored_tests": false, "version": "3.4.2"}, "newick": {"depends": [], "file_name": "newick-1.9.0-py2.py3-none-any.whl", "imports": ["newick"], "install_dir": "site", "name": "newick", "package_type": "package", "sha256": "0c36857981135c2fdab3c5014d2c166686f3da63a77d4d7ade1dacc5624f1e3f", "unvendored_tests": false, "version": "1.9.0"}, "nh3": {"depends": [], "file_name": "nh3-0.2.17-cp37-abi3-pyodide_2024_0_wasm32.whl", "imports": ["nh3"], "install_dir": "site", "name": "nh3", "package_type": "package", "sha256": "751f00fd5909f75ffb9d7a0efe5b0cd1eee888bcd767debe5079e5cd5eef2f22", "unvendored_tests": false, "version": "0.2.17"}, "nlopt": {"depends": ["numpy"], "file_name": "nlopt-2.9.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["nlopt"], "install_dir": "site", "name": "nlopt", "package_type": "package", "sha256": "cdfaf6037286471e7759f7f9f0e4c182156f536d55570258ac3ec1774fabad82", "unvendored_tests": false, "version": "2.9.1"}, "nltk": {"depends": ["regex", "sqlite3"], "file_name": "nltk-3.8.1-py3-none-any.whl", "imports": ["nltk"], "install_dir": "site", "name": "nltk", "package_type": "package", "sha256": "73310c9208d65ccc7967d38f1564c478bd9478945c238707d66c6a1797153b77", "unvendored_tests": true, "version": "3.8.1"}, "nltk-tests": {"depends": ["nltk"], "file_name": "nltk-tests.tar", "imports": [], "install_dir": "site", "name": "nltk-tests", "package_type": "package", "sha256": "f027e65392bd6527591ae6ec94f6ad364764c6f77beab2def79318afedd6a050", "unvendored_tests": false, "version": "3.8.1"}, "numcodecs": {"depends": ["numpy", "msgpack"], "file_name": "numcodecs-0.13.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["numcodecs"], "install_dir": "site", "name": "numcodecs", "package_type": "package", "sha256": "63591f47fcf2b76a28b934245d69fff2a050a9aa0df32e1392e9c080dcf4dc9e", "unvendored_tests": true, "version": "0.13.1"}, "numcodecs-tests": {"depends": ["numcodecs"], "file_name": "numcodecs-tests.tar", "imports": [], "install_dir": "site", "name": "numcodecs-tests", "package_type": "package", "sha256": "7afdda6cbdf4bd6e7f46d7f3af0811c63e2955c02de81d8a8a766c6e9efdb3a1", "unvendored_tests": false, "version": "0.13.1"}, "numpy": {"depends": [], "file_name": "numpy-2.0.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["numpy"], "install_dir": "site", "name": "numpy", "package_type": "package", "sha256": "ebb61241d962b98b21597d7ce43b67668a6d5bab3acec4fbe958657320d7cd08", "unvendored_tests": true, "version": "2.0.2"}, "numpy-tests": {"depends": ["numpy"], "file_name": "numpy-tests.tar", "imports": [], "install_dir": "site", "name": "numpy-tests", "package_type": "package", "sha256": "cad7ee071528979cc444c57a20a6996f50d441a904709b41d8a5f70177a9026e", "unvendored_tests": false, "version": "2.0.2"}, "openai": {"depends": ["httpx", "pydantic", "typing-extensions", "distro", "anyio", "jiter"], "file_name": "openai-1.68.2-py3-none-any.whl", "imports": ["openai"], "install_dir": "site", "name": "openai", "package_type": "package", "sha256": "508d5d5ee0a39d1ef108e09888af784c54a639f48ebb354517e3d52d40900f22", "unvendored_tests": false, "version": "1.68.2"}, "openblas": {"depends": [], "file_name": "openblas-0.3.26.zip", "imports": [], "install_dir": "dynlib", "name": "openblas", "package_type": "shared_library", "sha256": "787ea9a8a5cd160204388d03324b3b7ce5c9aea14b5680cec987f837e76c5198", "unvendored_tests": false, "version": "0.3.26"}, "opencv-python": {"depends": ["numpy"], "file_name": "opencv_python-4.10.0.84-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cv2"], "install_dir": "site", "name": "opencv-python", "package_type": "package", "sha256": "fae5731bfaa3590eefd92b70fb78a090882031f31905451230b2804e3d576800", "unvendored_tests": false, "version": "4.10.0.84"}, "openssl": {"depends": [], "file_name": "openssl-1.1.1w.zip", "imports": [], "install_dir": "dynlib", "name": "openssl", "package_type": "shared_library", "sha256": "20b92cd9b9adb1a739af9f93772b60c084203aacf63ae1b2353951bd80c97f08", "unvendored_tests": false, "version": "1.1.1w"}, "optlang": {"depends": ["sympy", "six", "swiglpk"], "file_name": "optlang-1.8.1-py2.py3-none-any.whl", "imports": ["optlang"], "install_dir": "site", "name": "optlang", "package_type": "package", "sha256": "b45dd43fb6383a3769ad63ef05316d9c07cdb1cf82baee03a25c7e0bb42835e4", "unvendored_tests": true, "version": "1.8.1"}, "optlang-tests": {"depends": ["optlang"], "file_name": "optlang-tests.tar", "imports": [], "install_dir": "site", "name": "optlang-tests", "package_type": "package", "sha256": "7ce13eb9c2abf339b588e362767f5b8dfe4d26a5f11635b539661c7877a40dd2", "unvendored_tests": false, "version": "1.8.1"}, "orjson": {"depends": [], "file_name": "orjson-3.10.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["orjson"], "install_dir": "site", "name": "orjson", "package_type": "package", "sha256": "d492fd640b39620ec1ffb89441d74119b35baf77f672226aa9ee05ebdb29ca9b", "unvendored_tests": false, "version": "3.10.1"}, "osqp": {"depends": ["jinja2", "numpy", "scipy"], "file_name": "osqp-1.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["osqp"], "install_dir": "site", "name": "osqp", "package_type": "package", "sha256": "bfed35d7a38f289d7d66ac43de2663db66e8ccaf0e1c1cb9b05af43a0558f0a3", "unvendored_tests": true, "version": "1.0.0"}, "osqp-tests": {"depends": ["osqp"], "file_name": "osqp-tests.tar", "imports": [], "install_dir": "site", "name": "osqp-tests", "package_type": "package", "sha256": "8f0b82951f52473c7c595f17ebf268403a86bc918ee7bba682e9aa6baa7af54d", "unvendored_tests": false, "version": "1.0.0"}, "packaging": {"depends": [], "file_name": "packaging-24.2-py3-none-any.whl", "imports": ["packaging"], "install_dir": "site", "name": "packaging", "package_type": "package", "sha256": "fbf6a5ace596eb8e28fe0089ecfc0bca2eb3930563e9ca06acb98ea5302b99f7", "unvendored_tests": false, "version": "24.2"}, "pandas": {"depends": ["numpy", "python-dateutil", "pytz"], "file_name": "pandas-2.2.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pandas"], "install_dir": "site", "name": "pandas", "package_type": "package", "sha256": "5502f0f94f93a482b851d0b8ca43be692c1b8d20215a168313656847ff74d63a", "unvendored_tests": true, "version": "2.2.3"}, "pandas-tests": {"depends": ["pandas"], "file_name": "pandas-tests.tar", "imports": [], "install_dir": "site", "name": "pandas-tests", "package_type": "package", "sha256": "3d39f671d7b544935b45b72b1af7a8187efb368fcf5910436a3a37baa364d294", "unvendored_tests": false, "version": "2.2.3"}, "parso": {"depends": [], "file_name": "parso-0.8.4-py2.py3-none-any.whl", "imports": ["parso"], "install_dir": "site", "name": "parso", "package_type": "package", "sha256": "c97dfaa7eb01ca1759f92ca0bedacdd9e5e95b29e026aa51f75ca1bf8e144685", "unvendored_tests": false, "version": "0.8.4"}, "patsy": {"depends": ["numpy", "six"], "file_name": "patsy-0.5.6-py2.py3-none-any.whl", "imports": ["patsy"], "install_dir": "site", "name": "patsy", "package_type": "package", "sha256": "e52b38b82b8e67a78d8f7b0e38a3a9a22ee16e029e853434e700e7acb617b67b", "unvendored_tests": true, "version": "0.5.6"}, "patsy-tests": {"depends": ["patsy"], "file_name": "patsy-tests.tar", "imports": [], "install_dir": "site", "name": "patsy-tests", "package_type": "package", "sha256": "2a2478cce831c97a9c83858774ac4915dab53446fb8b0444f344ebfcd042f902", "unvendored_tests": false, "version": "0.5.6"}, "pcodec": {"depends": ["numpy"], "file_name": "pcodec-0.3.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pcodec"], "install_dir": "site", "name": "pcodec", "package_type": "package", "sha256": "96adcbd07aaf76a8e3441545c45e6202293b14a18dadf24af7c2c3fc34991f56", "unvendored_tests": false, "version": "0.3.3"}, "peewee": {"depends": ["sqlite3", "cffi"], "file_name": "peewee-3.17.3-py3-none-any.whl", "imports": ["peewee"], "install_dir": "site", "name": "peewee", "package_type": "package", "sha256": "00e4a6949864d2872c234188c9193b030ab90c4da39d71dcf7320506a19b3536", "unvendored_tests": true, "version": "3.17.3"}, "peewee-tests": {"depends": ["peewee"], "file_name": "peewee-tests.tar", "imports": [], "install_dir": "site", "name": "peewee-tests", "package_type": "package", "sha256": "737c608df70103eb4d5e16482bd324b28f422512eacd3dea2f130d13bc4f47c1", "unvendored_tests": false, "version": "3.17.3"}, "pi-heif": {"depends": ["cffi", "pillow", "libheif"], "file_name": "pi_heif-0.21.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pi_heif"], "install_dir": "site", "name": "pi-heif", "package_type": "package", "sha256": "33372324d0d6c9a37bf67cbddf1ef24f96049ec357c96121063a2cc0295dc25c", "unvendored_tests": false, "version": "0.21.0"}, "pillow": {"depends": [], "file_name": "pillow-10.2.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["PIL"], "install_dir": "site", "name": "Pillow", "package_type": "package", "sha256": "43eab147a9355385a99eeac18fb577d4af2fe4bd0bbd23d3ba3ddb92e72c2815", "unvendored_tests": false, "version": "10.2.0"}, "pillow-heif": {"depends": ["cffi", "pillow", "libheif"], "file_name": "pillow_heif-0.20.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pillow_heif"], "install_dir": "site", "name": "pillow-heif", "package_type": "package", "sha256": "d7e1aba18a35a014915e567b33c5ba45ac4f9ea5f95c6e7b608677052e5e6cee", "unvendored_tests": false, "version": "0.20.0"}, "pkgconfig": {"depends": [], "file_name": "pkgconfig-1.5.5-py3-none-any.whl", "imports": ["pkgconfig"], "install_dir": "site", "name": "pkgconfig", "package_type": "package", "sha256": "6865593962300e910d9d125972b590bf4bac693f54a7ce9c8602625ae42212f8", "unvendored_tests": false, "version": "1.5.5"}, "pluggy": {"depends": [], "file_name": "pluggy-1.5.0-py3-none-any.whl", "imports": ["pluggy"], "install_dir": "site", "name": "pluggy", "package_type": "package", "sha256": "93a74d265d6ee7de8f70cdae64d5ec9d8e0e7d18f791778c1f0cd442ed61d71a", "unvendored_tests": false, "version": "1.5.0"}, "polars": {"depends": [], "file_name": "polars-1.18.0-cp39-abi3-pyodide_2024_0_wasm32.whl", "imports": ["polars"], "install_dir": "site", "name": "polars", "package_type": "package", "sha256": "2e1410d89042e0c05a00832a1e39c9fe0a89d786dd8a3b7a9324cdc1eef5097c", "unvendored_tests": false, "version": "1.18.0"}, "pplpy": {"depends": ["gmpy2", "cysignals"], "file_name": "pplpy-0.8.10-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["ppl"], "install_dir": "site", "name": "pplpy", "package_type": "package", "sha256": "d644230564c6629e9532da4b1e68483f830b8898561e52c998210aae95eb42c3", "unvendored_tests": false, "version": "0.8.10"}, "primecountpy": {"depends": ["cysignals"], "file_name": "primecountpy-0.1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["primecountpy"], "install_dir": "site", "name": "primecountpy", "package_type": "package", "sha256": "33729e94b7e56fecbf70e290053f9c3be6addc9b396ca41917913ced8feb3f45", "unvendored_tests": false, "version": "0.1.0"}, "prompt-toolkit": {"depends": [], "file_name": "prompt_toolkit-3.0.43-py3-none-any.whl", "imports": ["prompt_toolkit"], "install_dir": "site", "name": "prompt_toolkit", "package_type": "package", "sha256": "3237bd2e78447aef7f9a3eddad92ca70410d0aaa1fe9f9797c788bfb3c6994c4", "unvendored_tests": false, "version": "3.0.43"}, "protobuf": {"depends": [], "file_name": "protobuf-5.29.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["google"], "install_dir": "site", "name": "protobuf", "package_type": "package", "sha256": "1c061201f6366b1638af5ec0f5f6a382a73d9773c08749650cdf0b4d656815bc", "unvendored_tests": false, "version": "5.29.2"}, "pure-eval": {"depends": [], "file_name": "pure_eval-0.2.3-py3-none-any.whl", "imports": ["pure_eval"], "install_dir": "site", "name": "pure-eval", "package_type": "package", "sha256": "ea9d0a2c5dc624585d95ea9dbde454d9eb26078ed7a2e6509f97927efdfc9fa8", "unvendored_tests": false, "version": "0.2.3"}, "py": {"depends": [], "file_name": "py-1.11.0-py2.py3-none-any.whl", "imports": ["py"], "install_dir": "site", "name": "py", "package_type": "package", "sha256": "9dfae43125fc30d0ca4d8d102d3fe5ad0062a92781acb16fa354a7b6c0d2f439", "unvendored_tests": false, "version": "1.11.0"}, "pyarrow": {"depends": ["numpy", "pandas", "pyodide-unix-timezones"], "file_name": "pyarrow-18.1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pyarrow"], "install_dir": "site", "name": "pyarrow", "package_type": "package", "sha256": "72c3d9bc1ba0dc807828548c03de885624341efc102846b75f6225bece3f02a6", "unvendored_tests": false, "version": "18.1.0"}, "pyclipper": {"depends": [], "file_name": "pyclipper-1.3.0.post5-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pyclipper"], "install_dir": "site", "name": "pyclipper", "package_type": "package", "sha256": "060d022426c6f8b05f1b36a446868057a63841cab190f010fbbb05d26a207045", "unvendored_tests": false, "version": "1.3.0.post5"}, "pycparser": {"depends": [], "file_name": "pycparser-2.22-py3-none-any.whl", "imports": ["pycparser"], "install_dir": "site", "name": "pycparser", "package_type": "package", "sha256": "9c907f3feea2a7cfdfcf6e2d95cf4de123ac41a9afc1a724fd72377385000385", "unvendored_tests": false, "version": "2.22"}, "pycryptodome": {"depends": [], "file_name": "pycryptodome-3.20.0-cp35-abi3-pyodide_2024_0_wasm32.whl", "imports": ["Crypto"], "install_dir": "site", "name": "pycryptodome", "package_type": "package", "sha256": "a8f3ee4c770ab953b83a1d6f21dbddea08c4b81b80bd5a6c90cd7d0500bbc3bc", "unvendored_tests": true, "version": "3.20.0"}, "pycryptodome-tests": {"depends": ["pycryptodome"], "file_name": "pycryptodome-tests.tar", "imports": [], "install_dir": "site", "name": "pycryptodome-tests", "package_type": "package", "sha256": "c3ff3a8128df4043b238d76ad9ef5177b6c93d0e20532361e5b097f5ccc1517f", "unvendored_tests": false, "version": "3.20.0"}, "pydantic": {"depends": ["typing-extensions", "pydantic_core", "annotated-types"], "file_name": "pydantic-2.10.5-py3-none-any.whl", "imports": ["pydantic"], "install_dir": "site", "name": "pydantic", "package_type": "package", "sha256": "dd344e353e3c3a2d972c1198744a4f4ba1e2ce586e903187cca9fdaafb46c63d", "unvendored_tests": false, "version": "2.10.5"}, "pydantic-core": {"depends": [], "file_name": "pydantic_core-2.27.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pydantic_core"], "install_dir": "site", "name": "pydantic_core", "package_type": "package", "sha256": "eefd735db79e36e3425e4a821fc9df6cb172d2845f0d4a2a1038eb5f4d5c1d0c", "unvendored_tests": false, "version": "2.27.2"}, "pydecimal": {"depends": [], "file_name": "pydecimal-1.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["_pydecimal"], "install_dir": "site", "name": "pydecimal", "package_type": "cpython_module", "sha256": "b580c39e5573e4a22be030aec5ef141fbb725f52a3ef71d0ee903c3d17c01d2b", "unvendored_tests": false, "version": "1.0.0"}, "pydoc-data": {"depends": [], "file_name": "pydoc_data-1.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pydoc_data"], "install_dir": "site", "name": "pydoc_data", "package_type": "cpython_module", "sha256": "7b0b5ff6ecc0dbfbc644516d9b87c4ae78c291c15334ae89aab9e1f24ca0ea9a", "unvendored_tests": false, "version": "1.0.0"}, "pyerfa": {"depends": ["numpy"], "file_name": "pyerfa-2.0.1.4-cp39-abi3-pyodide_2024_0_wasm32.whl", "imports": ["erfa"], "install_dir": "site", "name": "pyerfa", "package_type": "package", "sha256": "3188ea139850f6e7cd8424af15795d14608ec37a60e47bf7387e2ebdd0c34bce", "unvendored_tests": true, "version": "2.0.1.4"}, "pyerfa-tests": {"depends": ["pyerfa"], "file_name": "pyerfa-tests.tar", "imports": [], "install_dir": "site", "name": "pyerfa-tests", "package_type": "package", "sha256": "867d678d47748bda8acbfba72c9d3c2399d2a21cfae83b3dde9a22d109e0e59e", "unvendored_tests": false, "version": "2.0.1.4"}, "pygame-ce": {"depends": [], "file_name": "pygame_ce-2.4.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pygame"], "install_dir": "site", "name": "pygame-ce", "package_type": "package", "sha256": "4ce0d35621b6a67bd66db8d3d4f3531774a8cf80edc0faecf76e33762ff71ef1", "unvendored_tests": true, "version": "2.4.1"}, "pygame-ce-tests": {"depends": ["pygame-ce"], "file_name": "pygame-ce-tests.tar", "imports": [], "install_dir": "site", "name": "pygame-ce-tests", "package_type": "package", "sha256": "6cc0398701cea4986d11ffb75bc488cd6068443d6c1c77ee799de5e0300e5c71", "unvendored_tests": false, "version": "2.4.1"}, "pygments": {"depends": [], "file_name": "pygments-2.17.2-py3-none-any.whl", "imports": ["pygments"], "install_dir": "site", "name": "Pygments", "package_type": "package", "sha256": "f32060883fc37e539491d0f6626aa861f2f484cceb8ae3c1364b482d1dde0e38", "unvendored_tests": false, "version": "2.17.2"}, "pyheif": {"depends": ["cffi"], "file_name": "pyheif-0.8.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pyheif"], "install_dir": "site", "name": "pyheif", "package_type": "package", "sha256": "5bc64d93fbdabd7c2344fda77d8c0280eba4995b417a7a645b30c7770a27aec3", "unvendored_tests": false, "version": "0.8.0"}, "pyiceberg": {"depends": ["click", "fsspec", "mmh3", "pydantic", "pyparsing", "requests", "rich", "sortedcontainers", "sqlalchemy", "strictyaml"], "file_name": "pyiceberg-0.6.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pyiceberg"], "install_dir": "site", "name": "pyiceberg", "package_type": "package", "sha256": "ed67c30c6e534ea38459e7469b08dfb8845c0f73ea45e61aed19c5a08f3c0ae9", "unvendored_tests": false, "version": "0.6.0"}, "pyinstrument": {"depends": [], "file_name": "pyinstrument-4.4.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pyinstrument"], "install_dir": "site", "name": "pyinstrument", "package_type": "package", "sha256": "625e11db231ad89fc896ad4835bdeb6aa3d1959cee9bf64cac7dccc3bf508de3", "unvendored_tests": false, "version": "4.4.0"}, "pynacl": {"depends": ["cffi"], "file_name": "pynacl-1.5.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["nacl"], "install_dir": "site", "name": "pynacl", "package_type": "package", "sha256": "b1404a2af8b8515f11e82b066a1c3dc5b976d990e2ac3c960b0a93cb628e77dd", "unvendored_tests": false, "version": "1.5.0"}, "pyodide-http": {"depends": [], "file_name": "pyodide_http-0.2.1-py3-none-any.whl", "imports": ["pyodide_http"], "install_dir": "site", "name": "pyodide-http", "package_type": "package", "sha256": "eba0df0bfddb0481625725cdf679af16cd6825ba686167a7b52719469a29267b", "unvendored_tests": false, "version": "0.2.1"}, "pyodide-unix-timezones": {"depends": [], "file_name": "pyodide_unix_timezones-1.0.0-py3-none-any.whl", "imports": ["unix_timezones"], "install_dir": "site", "name": "pyodide-unix-timezones", "package_type": "package", "sha256": "3f13dc510527a6496b777593b7e95c4ade6f0c0d7105647f495fe9520b77097c", "unvendored_tests": false, "version": "1.0.0"}, "pyparsing": {"depends": [], "file_name": "pyparsing-3.1.2-py3-none-any.whl", "imports": ["pyparsing"], "install_dir": "site", "name": "pyparsing", "package_type": "package", "sha256": "9070866557845375d8180e9236021fdecb2b93be75a7c8de48841f1465133a60", "unvendored_tests": false, "version": "3.1.2"}, "pyproj": {"depends": ["certifi", "sqlite3"], "file_name": "pyproj-3.6.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pyproj"], "install_dir": "site", "name": "pyproj", "package_type": "package", "sha256": "16489b4aaa6107abe65c4161e3f7c74714bd980305a66f6e517154466192c0a8", "unvendored_tests": false, "version": "3.6.1"}, "pyrsistent": {"depends": [], "file_name": "pyrsistent-0.20.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["_pyrsistent_version", "pyrsistent"], "install_dir": "site", "name": "pyrsistent", "package_type": "package", "sha256": "9b779e5dbee6eb26e493f86b510a199981eb58b3d5777391927143161991eb12", "unvendored_tests": false, "version": "0.20.0"}, "pysam": {"depends": [], "file_name": "pysam-0.22.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pysam"], "install_dir": "site", "name": "pysam", "package_type": "package", "sha256": "0d23f76d51543a216e521161a820b2d245c3b32c34acc29ccae1ed6bb417ee13", "unvendored_tests": false, "version": "0.22.0"}, "pyshp": {"depends": [], "file_name": "pyshp-2.3.1-py2.py3-none-any.whl", "imports": ["shapefile"], "install_dir": "site", "name": "pyshp", "package_type": "package", "sha256": "dfe6e10713df7b685bc8fa0d8c177cf5846ba32d60b84ca35e08adcc53b52503", "unvendored_tests": false, "version": "2.3.1"}, "pytest": {"depends": ["atomicwrites", "attrs", "more-itertools", "pluggy", "py", "setuptools", "six", "iniconfig", "exceptiongroup"], "file_name": "pytest-8.1.1-py3-none-any.whl", "imports": ["_pytest", "pytest"], "install_dir": "site", "name": "pytest", "package_type": "package", "sha256": "6807d755d66c89ea85cbc415eec062f59dbea7ef0de2cc862fdf326042fa0a3f", "unvendored_tests": false, "version": "8.1.1"}, "pytest-asyncio": {"depends": ["pytest"], "file_name": "pytest_asyncio-0.23.7-py3-none-any.whl", "imports": ["pytest_asyncio"], "install_dir": "site", "name": "pytest-asyncio", "package_type": "package", "sha256": "9bb0e70a86393a6a39b6ab0d310ea2c2ccbdc79bbe0ef8264290410952b75ecf", "unvendored_tests": false, "version": "0.23.7"}, "pytest-benchmark": {"depends": [], "file_name": "pytest_benchmark-4.0.0-py3-none-any.whl", "imports": ["pytest_benchmark"], "install_dir": "site", "name": "pytest-benchmark", "package_type": "package", "sha256": "eccc2a3f5f26346be28e84ceeb0c07d2c0de3caa03f856a92cfcc238c39a9ec9", "unvendored_tests": false, "version": "4.0.0"}, "pytest-httpx": {"depends": ["httpx", "pytest", "httpcore"], "file_name": "pytest_httpx-0.30.0-py3-none-any.whl", "imports": ["pytest_httpx"], "install_dir": "site", "name": "pytest_httpx", "package_type": "package", "sha256": "e8bae7ecaf4773c914aeec10e7b4cbf9f6e2fef7835bcb6b960f36dc29348faa", "unvendored_tests": false, "version": "0.30.0"}, "python-dateutil": {"depends": ["six"], "file_name": "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", "imports": ["dateutil"], "install_dir": "site", "name": "python-dateutil", "package_type": "package", "sha256": "02811ea3714f6697d639c07dc5ec63f5774dc7a688e4e1cbbe9beb2f33c3e6c9", "unvendored_tests": false, "version": "2.9.0.post0"}, "python-flint": {"depends": [], "file_name": "python_flint-0.6.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["flint"], "install_dir": "site", "name": "python-flint", "package_type": "package", "sha256": "639412db89782e84e4f323f0c4134f9367e0f110c81a4d3d948bdeedfe87a811", "unvendored_tests": false, "version": "0.6.0"}, "python-magic": {"depends": ["libmagic"], "file_name": "python_magic-0.4.27-py2.py3-none-any.whl", "imports": ["magic"], "install_dir": "site", "name": "python-magic", "package_type": "package", "sha256": "cea35f65052af6d8bf890af06cf2198fa3b2c9a4e2faa5cf2488d43ed7734e5f", "unvendored_tests": false, "version": "0.4.27"}, "python-sat": {"depends": ["six"], "file_name": "python_sat-1.8.dev17-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pysat"], "install_dir": "site", "name": "python-sat", "package_type": "package", "sha256": "32594022aef9c142209a28527351575f091c0d0e573bda3c296461e2699f40c0", "unvendored_tests": false, "version": "1.8.dev17"}, "python-solvespace": {"depends": [], "file_name": "python_solvespace-3.0.8-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["python_solvespace"], "install_dir": "site", "name": "python-solvespace", "package_type": "package", "sha256": "0e3eecbca538c0b9911d8a7e126fd8096feaaec50de242af56e194825698d62a", "unvendored_tests": false, "version": "3.0.8"}, "pytz": {"depends": [], "file_name": "pytz-2024.1-py2.py3-none-any.whl", "imports": ["pytz"], "install_dir": "site", "name": "pytz", "package_type": "package", "sha256": "fcfc168155da8d19057b17bee735fef71dc3a39f1dccd83514e16ecc6abaddc4", "unvendored_tests": false, "version": "2024.1"}, "pywavelets": {"depends": ["numpy"], "file_name": "pywavelets-1.8.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pywt"], "install_dir": "site", "name": "pywavelets", "package_type": "package", "sha256": "722b7a4daa4c1d074cf15f0193bf378c8a894da69df493c186cddc899b0e0e6d", "unvendored_tests": true, "version": "1.8.0"}, "pywavelets-tests": {"depends": ["pywavelets"], "file_name": "pywavelets-tests.tar", "imports": [], "install_dir": "site", "name": "pywavelets-tests", "package_type": "package", "sha256": "8245ff850020e90aa0531b7d339c0b53d9c1cdeb04cb24abe2e3639fcda934a8", "unvendored_tests": false, "version": "1.8.0"}, "pyxel": {"depends": [], "file_name": "pyxel-1.9.10-cp37-abi3-pyodide_2024_0_wasm32.whl", "imports": ["pyxel"], "install_dir": "site", "name": "pyxel", "package_type": "package", "sha256": "f7f2400169ba683e6d80e479aa272a48e3d642d8355c49ed7be2b6085f787c16", "unvendored_tests": false, "version": "1.9.10"}, "pyxirr": {"depends": [], "file_name": "pyxirr-0.10.6-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pyxirr"], "install_dir": "site", "name": "pyxirr", "package_type": "package", "sha256": "1c5653e42432a864f742209a8341ca8184991a104b1fbbb7c8233d9108ff425e", "unvendored_tests": false, "version": "0.10.6"}, "pyyaml": {"depends": [], "file_name": "pyyaml-6.0.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["_yaml", "yaml"], "install_dir": "site", "name": "pyyaml", "package_type": "package", "sha256": "444d034ede13ca0a2961a1215838fb7d4cf6fa98ba7fe5e2a09e5063180af2bf", "unvendored_tests": false, "version": "6.0.2"}, "rasterio": {"depends": ["numpy", "affine", "gdal", "attrs", "certifi", "click", "cligj"], "file_name": "rasterio-1.4.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["rasterio"], "install_dir": "site", "name": "rasterio", "package_type": "package", "sha256": "30252f7e5fce6f9813ea8490e407a2edf941ddcf8b18fff522b836d4f63edbc6", "unvendored_tests": false, "version": "1.4.2"}, "rateslib": {"depends": ["numpy", "pandas", "matplotlib"], "file_name": "rateslib-1.6.0-cp39-abi3-pyodide_2024_0_wasm32.whl", "imports": ["rateslib"], "install_dir": "site", "name": "rateslib", "package_type": "package", "sha256": "2c8af9571e2d9710ea040f171f51bce49d5965274bd54715d15af3a1f6ba5899", "unvendored_tests": false, "version": "1.6.0"}, "rebound": {"depends": ["numpy"], "file_name": "rebound-4.4.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["rebound"], "install_dir": "site", "name": "rebound", "package_type": "package", "sha256": "6694ccb785b604245e4c09cc6528a292c577008b349bc43cdacb72b5a43e2cae", "unvendored_tests": false, "version": "4.4.3"}, "reboundx": {"depends": ["rebound", "numpy"], "file_name": "reboundx-4.3.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["reboundx"], "install_dir": "site", "name": "reboundx", "package_type": "package", "sha256": "1691a8aec70c8fbcd10a14ae60194ce1f6869fff14900001116ea56099161022", "unvendored_tests": false, "version": "4.3.0"}, "referencing": {"depends": ["attrs", "rpds-py"], "file_name": "referencing-0.34.0-py3-none-any.whl", "imports": ["referencing"], "install_dir": "site", "name": "referencing", "package_type": "package", "sha256": "21cba0cad6e1bda83f12d98d7546e3035078d74b2cd8069c7b68131921032726", "unvendored_tests": true, "version": "0.34.0"}, "referencing-tests": {"depends": ["referencing"], "file_name": "referencing-tests.tar", "imports": [], "install_dir": "site", "name": "referencing-tests", "package_type": "package", "sha256": "31b4eaa934a9b7e2591d5051991662f0abed42cc3776332e8871108c7189d1d4", "unvendored_tests": false, "version": "0.34.0"}, "regex": {"depends": [], "file_name": "regex-2024.9.11-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["regex"], "install_dir": "site", "name": "regex", "package_type": "package", "sha256": "96abcf0bbb787d26ba73c2057ae5dd548a650740071860c37582c11037c7bf5d", "unvendored_tests": true, "version": "2024.9.11"}, "regex-tests": {"depends": ["regex"], "file_name": "regex-tests.tar", "imports": [], "install_dir": "site", "name": "regex-tests", "package_type": "package", "sha256": "991e1d190a414427fb4deb9f5e6b95c59149d89d95dec48eef92882ca8b0ff3c", "unvendored_tests": false, "version": "2024.9.11"}, "requests": {"depends": ["charset-normalizer", "idna", "urllib3", "certifi"], "file_name": "requests-2.31.0-py3-none-any.whl", "imports": ["requests"], "install_dir": "site", "name": "requests", "package_type": "package", "sha256": "aa9e565a1522a7b700e0801c429f7139c5e5c56d22c1b20e2987351a5e0cc48b", "unvendored_tests": false, "version": "2.31.0"}, "retrying": {"depends": ["six"], "file_name": "retrying-1.3.4-py3-none-any.whl", "imports": ["retrying"], "install_dir": "site", "name": "retrying", "package_type": "package", "sha256": "e6e09bfbf01b44ff3e8ca3ed57a5dd4a565806b1e417aa4c15483e93f4e9b595", "unvendored_tests": false, "version": "1.3.4"}, "rich": {"depends": [], "file_name": "rich-13.7.1-py3-none-any.whl", "imports": ["rich"], "install_dir": "site", "name": "rich", "package_type": "package", "sha256": "a0b51f5b5b661fbd0a5bfd82b6d09498e62c2e85a3f00ed9878cd58b5b0bf38d", "unvendored_tests": false, "version": "13.7.1"}, "river": {"depends": ["numpy", "pandas", "scipy"], "file_name": "river-0.22.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["river"], "install_dir": "site", "name": "river", "package_type": "package", "sha256": "5195e88e8391cadb6c110a0728c44c53ede82ccb9be384278887db69dec19dba", "unvendored_tests": true, "version": "0.22.0"}, "river-tests": {"depends": ["river"], "file_name": "river-tests.tar", "imports": [], "install_dir": "site", "name": "river-tests", "package_type": "package", "sha256": "46d2fd6e7191b088abd87dd0289ab3cc2162c3dff762dcce583c9e9b977abaeb", "unvendored_tests": false, "version": "0.22.0"}, "robotraconteur": {"depends": ["numpy"], "file_name": "robotraconteur-1.2.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["RobotRaconteur"], "install_dir": "site", "name": "RobotRaconteur", "package_type": "package", "sha256": "85ebc3675e9b9307976be92deb7a3742f09cb4b2d82a2f31c9371fe56f3ba248", "unvendored_tests": false, "version": "1.2.2"}, "rpds-py": {"depends": [], "file_name": "rpds_py-0.18.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["rpds"], "install_dir": "site", "name": "rpds-py", "package_type": "package", "sha256": "4236ab9baaadceecafa95941c0ee78b2fb96e97c1e9e6328a60a7a8a44dd9625", "unvendored_tests": false, "version": "0.18.0"}, "ruamel-yaml": {"depends": [], "file_name": "ruamel.yaml-0.18.6-py3-none-any.whl", "imports": ["ruamel"], "install_dir": "site", "name": "ruamel.yaml", "package_type": "package", "sha256": "164c5ff648a06276340cd108b6f3bbe5be73933d579cf424ab4d195cfd7a0c75", "unvendored_tests": false, "version": "0.18.6"}, "rust-abi-test": {"depends": [], "file_name": "rust_abi_test-1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["rust-abi-test"], "install_dir": "site", "name": "rust-abi-test", "package_type": "package", "sha256": "b4973404a367023dcfac6312c3a0cc375d9b97d2d8e57ddac852e68a770690c6", "unvendored_tests": false, "version": "1.0"}, "rust-panic-test": {"depends": [], "file_name": "rust_panic_test-1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["rust-panic-test"], "install_dir": "site", "name": "rust-panic-test", "package_type": "package", "sha256": "669e81d527fe0d10c371d4c223bc32895b45f6dc1b04adc566d9be0fae16175b", "unvendored_tests": false, "version": "1.0"}, "scikit-image": {"depends": ["packaging", "numpy", "scipy", "networkx", "pillow", "imageio", "pywavelets", "lazy_loader"], "file_name": "scikit_image-0.25.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["skimage"], "install_dir": "site", "name": "scikit-image", "package_type": "package", "sha256": "788beea853f8cf25a3d4847e5fe7de9c80045491e12e49842f1c3b16fbcd6db8", "unvendored_tests": true, "version": "0.25.0"}, "scikit-image-tests": {"depends": ["scikit-image"], "file_name": "scikit-image-tests.tar", "imports": [], "install_dir": "site", "name": "scikit-image-tests", "package_type": "package", "sha256": "801056f0607db2f8b279d90b2df2bf22cf3f05e9e1a785a9be4ee83edf48c98d", "unvendored_tests": false, "version": "0.25.0"}, "scikit-learn": {"depends": ["scipy", "joblib", "threadpoolctl"], "file_name": "scikit_learn-1.6.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["sklearn"], "install_dir": "site", "name": "scikit-learn", "package_type": "package", "sha256": "022fe0061765894279b4ae1035e40da2cb436efa51d408f8e6214aacad0c631b", "unvendored_tests": true, "version": "1.6.1"}, "scikit-learn-tests": {"depends": ["scikit-learn"], "file_name": "scikit-learn-tests.tar", "imports": [], "install_dir": "site", "name": "scikit-learn-tests", "package_type": "package", "sha256": "f05a45caba47a998c0bf7a7adf8ca68e781e784830aa641c65b2794aa5115af1", "unvendored_tests": false, "version": "1.6.1"}, "scipy": {"depends": ["numpy", "openblas"], "file_name": "scipy-1.14.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["scipy"], "install_dir": "site", "name": "scipy", "package_type": "package", "sha256": "997c50a61564a8ce6a56ea98a42e7f4427e5eb98475a73233e83df6a184f415c", "unvendored_tests": true, "version": "1.14.1"}, "scipy-tests": {"depends": ["scipy"], "file_name": "scipy-tests.tar", "imports": [], "install_dir": "site", "name": "scipy-tests", "package_type": "package", "sha256": "cebd7149650a3c52b0fdb466bebf1a613085857785d89574f6d189dc1a78f969", "unvendored_tests": false, "version": "1.14.1"}, "screed": {"depends": [], "file_name": "screed-1.1.3-py2.py3-none-any.whl", "imports": ["bigtests", "screed"], "install_dir": "site", "name": "screed", "package_type": "package", "sha256": "5bcd0e4a52df47e418304762085fd7e5ca514292089baedd420d871b7df01814", "unvendored_tests": true, "version": "1.1.3"}, "screed-tests": {"depends": ["screed"], "file_name": "screed-tests.tar", "imports": [], "install_dir": "site", "name": "screed-tests", "package_type": "package", "sha256": "bfa4d4bb7c62e90093868bcc7546a8b42b7edac56a9c57b03473b871737285dc", "unvendored_tests": false, "version": "1.1.3"}, "setuptools": {"depends": ["pyparsing"], "file_name": "setuptools-69.5.1-py3-none-any.whl", "imports": ["_distutils_hack", "pkg_resources", "setuptools"], "install_dir": "site", "name": "setuptools", "package_type": "package", "sha256": "6a44af4c5bbd6ae019fbe5fe52e6f3bff3b02ee6cbc543ebdf89d113b1c88c87", "unvendored_tests": false, "version": "69.5.1"}, "shapely": {"depends": ["numpy"], "file_name": "shapely-2.0.6-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["shapely"], "install_dir": "site", "name": "shapely", "package_type": "package", "sha256": "5a1354ccee47c150f5fc764e2f1ec7cc6aa2a4e9f028c0e9de5b83c5b5d53026", "unvendored_tests": true, "version": "2.0.6"}, "shapely-tests": {"depends": ["shapely"], "file_name": "shapely-tests.tar", "imports": [], "install_dir": "site", "name": "shapely-tests", "package_type": "package", "sha256": "c21cef6e8c2bacf606b06a47fb2f24f685fdd456e4d7581071cd72b9c89ce14c", "unvendored_tests": false, "version": "2.0.6"}, "sharedlib-test": {"depends": [], "file_name": "sharedlib-test-1.0.zip", "imports": [], "install_dir": "dynlib", "name": "sharedlib-test", "package_type": "shared_library", "sha256": "8a139430acb582c33b14822f8f40c7f827f4d39b685696d7f52819fc6a72e2a8", "unvendored_tests": false, "version": "1.0"}, "sharedlib-test-py": {"depends": ["sharedlib-test"], "file_name": "sharedlib_test_py-1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["sharedlib_test"], "install_dir": "site", "name": "sharedlib-test-py", "package_type": "package", "sha256": "34d2ba1e2da9ad2f605f130e9a22ad686f2ebcaa26a3681f38f00e4d3b20b467", "unvendored_tests": false, "version": "1.0"}, "simplejson": {"depends": [], "file_name": "simplejson-3.19.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["simplejson"], "install_dir": "site", "name": "simplejson", "package_type": "package", "sha256": "924eff7af1fa0496c6edf381093336906ed510eccddbdfa87de5457a9a1be6da", "unvendored_tests": true, "version": "3.19.2"}, "simplejson-tests": {"depends": ["simplejson"], "file_name": "simplejson-tests.tar", "imports": [], "install_dir": "site", "name": "simplejson-tests", "package_type": "package", "sha256": "72c03bc5810643a43371cffe523ef7996a583b8e373580692077a2ccc991abba", "unvendored_tests": false, "version": "3.19.2"}, "sisl": {"depends": ["pyparsing", "numpy", "scipy", "tqdm", "xarray", "pandas", "matplotlib"], "file_name": "sisl-0.15.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["sisl_toolbox", "sisl"], "install_dir": "site", "name": "sisl", "package_type": "package", "sha256": "360da9984c4a45a7e722e4a89701455e6aa9e5eb1ae5e39b78acfb89ad03be04", "unvendored_tests": true, "version": "0.15.1"}, "sisl-tests": {"depends": ["sisl"], "file_name": "sisl-tests.tar", "imports": [], "install_dir": "site", "name": "sisl-tests", "package_type": "package", "sha256": "dcfb63e5681592a006d9cd0c48ac7dfb0c239759c9285fcf12238b9c782f8298", "unvendored_tests": false, "version": "0.15.1"}, "six": {"depends": [], "file_name": "six-1.16.0-py2.py3-none-any.whl", "imports": ["six"], "install_dir": "site", "name": "six", "package_type": "package", "sha256": "f61235bc3a15086f0369585e5071ae9ba0bd244a111d12b37f683862e6850c0a", "unvendored_tests": false, "version": "1.16.0"}, "smart-open": {"depends": ["wrapt"], "file_name": "smart_open-7.0.4-py3-none-any.whl", "imports": ["smart_open"], "install_dir": "site", "name": "smart-open", "package_type": "package", "sha256": "2c4c355114e82c921aed53926553bfd18dea47ba13bb9b42d22d35a3bd212d04", "unvendored_tests": false, "version": "7.0.4"}, "sniffio": {"depends": [], "file_name": "sniffio-1.3.1-py3-none-any.whl", "imports": ["sniffio"], "install_dir": "site", "name": "sniffio", "package_type": "package", "sha256": "9215f9917b34fc73152b134a3fc0a2eb0e4a49b0b956100cad75e84943412bb9", "unvendored_tests": true, "version": "1.3.1"}, "sniffio-tests": {"depends": ["sniffio"], "file_name": "sniffio-tests.tar", "imports": [], "install_dir": "site", "name": "sniffio-tests", "package_type": "package", "sha256": "4359e1a6b2fd3ab2fba68a5c7fe97601cdb11b937922d9a56e5f9c41e32f244e", "unvendored_tests": false, "version": "1.3.1"}, "sortedcontainers": {"depends": [], "file_name": "sortedcontainers-2.4.0-py2.py3-none-any.whl", "imports": ["sortedcontainers"], "install_dir": "site", "name": "sortedcontainers", "package_type": "package", "sha256": "921a3fdbab3f20015bf39eb0f06807891b78080f39baf92376d1e73038562d27", "unvendored_tests": false, "version": "2.4.0"}, "soupsieve": {"depends": [], "file_name": "soupsieve-2.5-py3-none-any.whl", "imports": ["soupsieve"], "install_dir": "site", "name": "soupsieve", "package_type": "package", "sha256": "e18a6ff6869082a37e78db6e688b239e8f638d647a2e8e3e152f7dee81c262eb", "unvendored_tests": false, "version": "2.5"}, "sourmash": {"depends": ["screed", "cffi", "deprecation", "cachetools", "numpy", "matplotlib", "scipy", "sqlite3", "bitstring"], "file_name": "sourmash-4.8.11-py3-none-pyodide_2024_0_wasm32.whl", "imports": ["sourmash"], "install_dir": "site", "name": "sourmash", "package_type": "package", "sha256": "ae9c653de12b5cf4b215e4e6fe4ee5d91ce80e10335805265a8681c019c42ff1", "unvendored_tests": false, "version": "4.8.11"}, "soxr": {"depends": ["numpy"], "file_name": "soxr-0.5.0.post1-cp312-abi3-pyodide_2024_0_wasm32.whl", "imports": ["soxr"], "install_dir": "site", "name": "soxr", "package_type": "package", "sha256": "90f77f06c07dbc1fc09a1901f9a94565f8ae632b4827cf4b5f3ba935ab8c9def", "unvendored_tests": false, "version": "0.5.0.post1"}, "sparseqr": {"depends": ["pycparser", "cffi", "numpy", "scipy", "suitesparse"], "file_name": "sparseqr-1.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["sparseqr"], "install_dir": "site", "name": "sparseqr", "package_type": "package", "sha256": "d0f8222b9e1fda78c125ca526d89649ade8b1da1e8cebd7e031a762284694960", "unvendored_tests": false, "version": "1.2"}, "sqlalchemy": {"depends": ["sqlite3", "typing-extensions"], "file_name": "sqlalchemy-2.0.29-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["sqlalchemy"], "install_dir": "site", "name": "sqlalchemy", "package_type": "package", "sha256": "c6ea5157694bf17915f33311d5064d36c5e73f9b872375571a8927d66c96ef28", "unvendored_tests": true, "version": "2.0.29"}, "sqlalchemy-tests": {"depends": ["sqlalchemy"], "file_name": "sqlalchemy-tests.tar", "imports": [], "install_dir": "site", "name": "sqlalchemy-tests", "package_type": "package", "sha256": "4ebd5b0307df4bc774984d5c782aacffea13dafeb7ce26409b925bb2174290c4", "unvendored_tests": false, "version": "2.0.29"}, "sqlite3": {"depends": [], "file_name": "sqlite3-1.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["sqlite3", "_sqlite3"], "install_dir": "site", "name": "sqlite3", "package_type": "cpython_module", "sha256": "43061928762b03482676a1e11dcef99a003148e59fe914b6a3e41180c382cfc3", "unvendored_tests": false, "version": "1.0.0"}, "ssl": {"depends": ["openssl"], "file_name": "ssl-1.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["ssl", "_ssl"], "install_dir": "site", "name": "ssl", "package_type": "cpython_module", "sha256": "1af0b011a3043331a8a2a358832dcee736deff73a55ad0393222ea533942094a", "unvendored_tests": false, "version": "1.0.0"}, "stack-data": {"depends": ["executing", "asttokens", "pure-eval"], "file_name": "stack_data-0.6.3-py3-none-any.whl", "imports": ["stack_data"], "install_dir": "site", "name": "stack-data", "package_type": "package", "sha256": "650be7bb2e224e51b3f872abc6c503323b0e12c2090121c43cb576b06da7c8c6", "unvendored_tests": false, "version": "0.6.3"}, "statsmodels": {"depends": ["numpy", "scipy", "pandas", "patsy", "packaging"], "file_name": "statsmodels-0.14.4-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["statsmodels"], "install_dir": "site", "name": "statsmodels", "package_type": "package", "sha256": "4c89f4c9146b142216126042af0eb3927d5912485a50bfd333def06c5ad5fd8d", "unvendored_tests": false, "version": "0.14.4"}, "strictyaml": {"depends": ["python-dateutil"], "file_name": "strictyaml-1.7.3-py3-none-any.whl", "imports": ["strictyaml"], "install_dir": "site", "name": "strictyaml", "package_type": "package", "sha256": "9984cb99d952f8f4058af9644ba8c256a66540e280a28a228340d195df6a2b2d", "unvendored_tests": false, "version": "1.7.3"}, "suitesparse": {"depends": ["openblas"], "file_name": "suitesparse-5.11.0.zip", "imports": [], "install_dir": "dynlib", "name": "suitesparse", "package_type": "shared_library", "sha256": "5119c1c844aa457387eb24656c1f5804de6535509d944e9693f9b577ba352b29", "unvendored_tests": false, "version": "5.11.0"}, "svgwrite": {"depends": [], "file_name": "svgwrite-1.4.3-py3-none-any.whl", "imports": ["svgwrite"], "install_dir": "site", "name": "svgwrite", "package_type": "package", "sha256": "4cb6d950e100b7c1a0ee854d3dd0b1e212a9740529b2535e9bcd1cfd84158f35", "unvendored_tests": false, "version": "1.4.3"}, "swiglpk": {"depends": [], "file_name": "swiglpk-5.0.10-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["swiglpk"], "install_dir": "site", "name": "swiglpk", "package_type": "package", "sha256": "c90b0ecc18b1e13302aa4ed8444093fe76eab584b0057fc57503dab800afde7a", "unvendored_tests": false, "version": "5.0.10"}, "sympy": {"depends": ["mpmath"], "file_name": "sympy-1.13.3-py3-none-any.whl", "imports": ["isympy", "sympy"], "install_dir": "site", "name": "sympy", "package_type": "package", "sha256": "f36c07ec53e3992f8d02ea833e4e277c51138791f07b508677dd37ef5c2965dd", "unvendored_tests": true, "version": "1.13.3"}, "sympy-tests": {"depends": ["sympy"], "file_name": "sympy-tests.tar", "imports": [], "install_dir": "site", "name": "sympy-tests", "package_type": "package", "sha256": "aab18f26d950dc211c82b1d070282a06e4f05bb89b8ed6298dfd5f431a7f020c", "unvendored_tests": false, "version": "1.13.3"}, "tblib": {"depends": [], "file_name": "tblib-3.0.0-py3-none-any.whl", "imports": ["tblib"], "install_dir": "site", "name": "tblib", "package_type": "package", "sha256": "ed436e5f8ae0a4199274895bc80d8df84c4fe0f0ed788b731944a12f8608bdba", "unvendored_tests": false, "version": "3.0.0"}, "termcolor": {"depends": [], "file_name": "termcolor-2.4.0-py3-none-any.whl", "imports": ["termcolor"], "install_dir": "site", "name": "termcolor", "package_type": "package", "sha256": "80206bea9d03e428ffa5bcde984cfad8e8460e0a8063aca066ce0a032e438f58", "unvendored_tests": false, "version": "2.4.0"}, "test": {"depends": [], "file_name": "test-1.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["test"], "install_dir": "site", "name": "test", "package_type": "cpython_module", "sha256": "f8ebd5e59c74ec825595874f45b88d061f486bee48b6e721bda5cf3489dc24e3", "unvendored_tests": false, "version": "1.0.0"}, "texttable": {"depends": [], "file_name": "texttable-1.7.0-py2.py3-none-any.whl", "imports": ["texttable"], "install_dir": "site", "name": "texttable", "package_type": "package", "sha256": "6f8af2339378fc488d2510b6b5096b34b57df7124150d6f4efee8c51f2c86dfb", "unvendored_tests": false, "version": "1.7.0"}, "threadpoolctl": {"depends": [], "file_name": "threadpoolctl-3.5.0-py3-none-any.whl", "imports": ["threadpoolctl"], "install_dir": "site", "name": "threadpoolctl", "package_type": "package", "sha256": "c463e5400524d9edd309fc100f362d774207d1e51321b92b258403ee6c3ba49c", "unvendored_tests": false, "version": "3.5.0"}, "tiktoken": {"depends": ["regex", "requests"], "file_name": "tiktoken-0.8.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["tiktoken", "tiktoken_ext"], "install_dir": "site", "name": "tiktoken", "package_type": "package", "sha256": "a8d15e3774b994267a998cc759b82ad6c0013f8200b58c7cd6b69607e1a831c3", "unvendored_tests": false, "version": "0.8.0"}, "tomli": {"depends": [], "file_name": "tomli-2.0.1-py3-none-any.whl", "imports": ["tomli"], "install_dir": "site", "name": "tomli", "package_type": "package", "sha256": "b4a588f7abeb4004dae12fd11792b6d7e7ebaee4cd7a17803764d9223640139d", "unvendored_tests": false, "version": "2.0.1"}, "tomli-w": {"depends": [], "file_name": "tomli_w-1.0.0-py3-none-any.whl", "imports": ["tomli_w"], "install_dir": "site", "name": "tomli-w", "package_type": "package", "sha256": "d2167ae892ab64baf827c89479414c42df7b97156f2b7a3c8af09ef13b27486b", "unvendored_tests": false, "version": "1.0.0"}, "toolz": {"depends": [], "file_name": "toolz-0.12.1-py3-none-any.whl", "imports": ["tlz", "toolz"], "install_dir": "site", "name": "toolz", "package_type": "package", "sha256": "8011c87ab3527478368d34365a5a402eacbd2d525e799f8d99cbf7f3ea2b2a16", "unvendored_tests": true, "version": "0.12.1"}, "toolz-tests": {"depends": ["toolz"], "file_name": "toolz-tests.tar", "imports": [], "install_dir": "site", "name": "toolz-tests", "package_type": "package", "sha256": "b904e1786e5cb8e5c8a45a0a11527350a217ac96d9af2be95b7182a4a5c9e9b6", "unvendored_tests": false, "version": "0.12.1"}, "tqdm": {"depends": [], "file_name": "tqdm-4.66.2-py3-none-any.whl", "imports": ["tqdm"], "install_dir": "site", "name": "tqdm", "package_type": "package", "sha256": "bc00a49b27c4e119f1f79ed363b01d6a7d7c50c6360fb2a4e0760568a0642e6d", "unvendored_tests": false, "version": "4.66.2"}, "traitlets": {"depends": [], "file_name": "traitlets-5.14.3-py3-none-any.whl", "imports": ["traitlets"], "install_dir": "site", "name": "traitlets", "package_type": "package", "sha256": "10548e49e1e17ac87a22080ab40bb818e1123302efa60893ea4ac335a24f86ee", "unvendored_tests": true, "version": "5.14.3"}, "traitlets-tests": {"depends": ["traitlets"], "file_name": "traitlets-tests.tar", "imports": [], "install_dir": "site", "name": "traitlets-tests", "package_type": "package", "sha256": "97c851c135696620e2c46574bcb0070a3a5ae2a505b9e14afe3c2b21339c7f20", "unvendored_tests": false, "version": "5.14.3"}, "traits": {"depends": [], "file_name": "traits-6.4.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["traits"], "install_dir": "site", "name": "traits", "package_type": "package", "sha256": "1cfd691e300a8523ce304a8005dd08834feab48ae49a1e79d34d64d54a74a853", "unvendored_tests": true, "version": "6.4.3"}, "traits-tests": {"depends": ["traits"], "file_name": "traits-tests.tar", "imports": [], "install_dir": "site", "name": "traits-tests", "package_type": "package", "sha256": "81fdf68ee2a9588f211b6471d2c9491e03433d0aedf00b7f77e876a340e5687a", "unvendored_tests": false, "version": "6.4.3"}, "tree-sitter": {"depends": [], "file_name": "tree_sitter-0.23.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["tree_sitter"], "install_dir": "site", "name": "tree-sitter", "package_type": "package", "sha256": "9a68166943480f8691cbc55d3e0749c8cc17554c65ec01326285ebb2cee1f696", "unvendored_tests": false, "version": "0.23.2"}, "tree-sitter-go": {"depends": ["tree-sitter"], "file_name": "tree_sitter_go-0.23.3-cp39-abi3-pyodide_2024_0_wasm32.whl", "imports": ["tree_sitter_go"], "install_dir": "site", "name": "tree-sitter-go", "package_type": "package", "sha256": "c42451ae2de7fbca6d2f4be2a9eff7d30582a2bb8eab3a9642f4025962669e12", "unvendored_tests": false, "version": "0.23.3"}, "tree-sitter-java": {"depends": ["tree-sitter"], "file_name": "tree_sitter_java-0.23.4-cp39-abi3-pyodide_2024_0_wasm32.whl", "imports": ["tree_sitter_java"], "install_dir": "site", "name": "tree-sitter-java", "package_type": "package", "sha256": "a6511fe471f7a022e92ac009ed97d3423226ab7522a7473f93a03f2b3483835d", "unvendored_tests": false, "version": "0.23.4"}, "tree-sitter-python": {"depends": ["tree-sitter"], "file_name": "tree_sitter_python-0.23.4-cp39-abi3-pyodide_2024_0_wasm32.whl", "imports": ["tree_sitter_python"], "install_dir": "site", "name": "tree-sitter-python", "package_type": "package", "sha256": "d948a8f07a3066db2c15b050fae0b5f15283c4466e83ae9017e21d669be3a620", "unvendored_tests": false, "version": "0.23.4"}, "tskit": {"depends": ["numpy", "svgwrite", "jsonschema", "rpds-py"], "file_name": "tskit-0.6.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["tskit"], "install_dir": "site", "name": "tskit", "package_type": "package", "sha256": "fd0fc875732b360ea00463835991d47d708a78b5f6f41b82c55a164c512f3f5c", "unvendored_tests": false, "version": "0.6.0"}, "typing-extensions": {"depends": [], "file_name": "typing_extensions-4.11.0-py3-none-any.whl", "imports": ["typing_extensions"], "install_dir": "site", "name": "typing-extensions", "package_type": "package", "sha256": "c3f00b6653202513b1f7813ad3c466510ceecc599a37d665a31dcfb5ac7049b9", "unvendored_tests": false, "version": "4.11.0"}, "tzdata": {"depends": [], "file_name": "tzdata-2024.1-py2.py3-none-any.whl", "imports": ["tzdata"], "install_dir": "site", "name": "tzdata", "package_type": "package", "sha256": "3f0d487be1b8180e8bfd72709a7727734cd1e02180d6a75e70d4232765215848", "unvendored_tests": false, "version": "2024.1"}, "uncertainties": {"depends": ["future"], "file_name": "uncertainties-3.1.7-py2.py3-none-any.whl", "imports": ["uncertainties"], "install_dir": "site", "name": "uncertainties", "package_type": "package", "sha256": "ca7bb1386e42f33fb78beba09af50eb1bf62c8e8fb2cd18180a42e116a5d4fa2", "unvendored_tests": true, "version": "3.1.7"}, "uncertainties-tests": {"depends": ["uncertainties"], "file_name": "uncertainties-tests.tar", "imports": [], "install_dir": "site", "name": "uncertainties-tests", "package_type": "package", "sha256": "af60023b960585dc4b58abc5680f664d2d71fd2461a2fa3f05884faf3a710b9b", "unvendored_tests": false, "version": "3.1.7"}, "unyt": {"depends": ["numpy", "packaging", "sympy"], "file_name": "unyt-3.0.3-py3-none-any.whl", "imports": ["unyt"], "install_dir": "site", "name": "unyt", "package_type": "package", "sha256": "2c2b2f7eacae8005c2cd4b55466653dd1fac1965683ef57b5a2ffaa7238a1f76", "unvendored_tests": true, "version": "3.0.3"}, "unyt-tests": {"depends": ["unyt"], "file_name": "unyt-tests.tar", "imports": [], "install_dir": "site", "name": "unyt-tests", "package_type": "package", "sha256": "42b1ecb29fc8bbbcacbbd72f87ddb301b72adc4bbe4a7a1c7b4ff2a0bf253d19", "unvendored_tests": false, "version": "3.0.3"}, "urllib3": {"depends": [], "file_name": "urllib3-2.2.3-py3-none-any.whl", "imports": ["urllib3"], "install_dir": "site", "name": "urllib3", "package_type": "package", "sha256": "902ea205c74f46402ea539ac68a7095117d20734c7ee6b7a6de1ca88224604f9", "unvendored_tests": false, "version": "2.2.3"}, "vega-datasets": {"depends": ["pandas"], "file_name": "vega_datasets-0.9.0-py3-none-any.whl", "imports": ["vega_datasets"], "install_dir": "site", "name": "vega-datasets", "package_type": "package", "sha256": "787417007f135977903ef362feb6b316a8e8ed404095ee04f47ffd5db6ba4512", "unvendored_tests": true, "version": "0.9.0"}, "vega-datasets-tests": {"depends": ["vega-datasets"], "file_name": "vega-datasets-tests.tar", "imports": [], "install_dir": "site", "name": "vega-datasets-tests", "package_type": "package", "sha256": "8e75ecd75a50546c5f5d8a1d36fb593a70913e54c2e4e753c3bf30c0d9c90c26", "unvendored_tests": false, "version": "0.9.0"}, "wcwidth": {"depends": [], "file_name": "wcwidth-0.2.13-py2.py3-none-any.whl", "imports": ["wcwidth"], "install_dir": "site", "name": "wcwidth", "package_type": "package", "sha256": "ae8fe34f6b43cadbd0db1a5a02a147cd4570915ae603032322f0a160aa12aaba", "unvendored_tests": false, "version": "0.2.13"}, "webencodings": {"depends": [], "file_name": "webencodings-0.5.1-py2.py3-none-any.whl", "imports": ["webencodings"], "install_dir": "site", "name": "webencodings", "package_type": "package", "sha256": "87f31ffae209d3e24545feb75d17e18c1ac87bb8304cd21a73eca2939d05f08d", "unvendored_tests": false, "version": "0.5.1"}, "wordcloud": {"depends": ["matplotlib"], "file_name": "wordcloud-1.9.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["wordcloud"], "install_dir": "site", "name": "wordcloud", "package_type": "package", "sha256": "f433b5946e3b963feb38818d97335b1f5ad4faad49a209c2c8656fbe374605a6", "unvendored_tests": false, "version": "1.9.3"}, "wrapt": {"depends": [], "file_name": "wrapt-1.16.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["wrapt"], "install_dir": "site", "name": "wrapt", "package_type": "package", "sha256": "4a1dd560aba11b9066f2558996df2c817fdc3894eebb5b031291ca3ced6b6ed5", "unvendored_tests": false, "version": "1.16.0"}, "xarray": {"depends": ["numpy", "packaging", "pandas"], "file_name": "xarray-2024.11.0-py3-none-any.whl", "imports": ["xarray"], "install_dir": "site", "name": "xarray", "package_type": "package", "sha256": "b01d67f12aaa1845655c25fcfd079268b4850f13681e030b7a732cdb7253f2a7", "unvendored_tests": true, "version": "2024.11.0"}, "xarray-tests": {"depends": ["xarray"], "file_name": "xarray-tests.tar", "imports": [], "install_dir": "site", "name": "xarray-tests", "package_type": "package", "sha256": "9d3c2fc81f033b74ca0303a4fc76c560e207aa0b2d6c205749660177147987aa", "unvendored_tests": false, "version": "2024.11.0"}, "xgboost": {"depends": ["numpy", "scipy", "setuptools"], "file_name": "xgboost-2.1.2-py3-none-pyodide_2024_0_wasm32.whl", "imports": ["xgboost"], "install_dir": "site", "name": "xgboost", "package_type": "package", "sha256": "0a283669c0720adb74fe4ccbeeb36bcefc6452adaa266d5c32293e427085f5d4", "unvendored_tests": false, "version": "2.1.2"}, "xlrd": {"depends": [], "file_name": "xlrd-2.0.1-py2.py3-none-any.whl", "imports": ["xlrd"], "install_dir": "site", "name": "xlrd", "package_type": "package", "sha256": "773ba42b16dffbc7475a0922574b61703fc1a59508ea4fefbb61e3e5aca3d7c3", "unvendored_tests": false, "version": "2.0.1"}, "xxhash": {"depends": [], "file_name": "xxhash-3.4.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["xxhash"], "install_dir": "site", "name": "xxhash", "package_type": "package", "sha256": "256f1841d90a000f0b2bee76850a9d68975aed446c4449777710a7398591dfd8", "unvendored_tests": false, "version": "3.4.1"}, "xyzservices": {"depends": [], "file_name": "xyzservices-2024.4.0-py3-none-any.whl", "imports": ["xyzservices"], "install_dir": "site", "name": "xyzservices", "package_type": "package", "sha256": "b157f591ed083cf9caa8554b348f3654133042a9ead9585176cb18b3eb2149d9", "unvendored_tests": true, "version": "2024.4.0"}, "xyzservices-tests": {"depends": ["xyzservices"], "file_name": "xyzservices-tests.tar", "imports": [], "install_dir": "site", "name": "xyzservices-tests", "package_type": "package", "sha256": "08a9053a13a8c68abe90e86cd49d8ad1b5cf8367b2e7badf8271b7f1ee01d4e2", "unvendored_tests": false, "version": "2024.4.0"}, "yarl": {"depends": ["multidict", "idna"], "file_name": "yarl-1.9.4-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["yarl"], "install_dir": "site", "name": "yarl", "package_type": "package", "sha256": "3d66511b55c1f05d65214b602237abacddeac64c658ceb4a438c2af172b5729c", "unvendored_tests": false, "version": "1.9.4"}, "yt": {"depends": ["ewah_bool_utils", "numpy", "matplotlib", "sympy", "setuptools", "packaging", "unyt", "cmyt", "colorspacious", "tqdm", "tomli", "tomli-w"], "file_name": "yt-4.3.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["yt"], "install_dir": "site", "name": "yt", "package_type": "package", "sha256": "ed5a165851b68a7fb585ff57ecdda0e94f5d34ce6121602640ce96fe61eeccf9", "unvendored_tests": false, "version": "4.3.1"}, "zarr": {"depends": ["numpy", "asciitree", "numcodecs"], "file_name": "zarr-2.18.3-py3-none-any.whl", "imports": ["zarr"], "install_dir": "site", "name": "zarr", "package_type": "package", "sha256": "e05fcda26363d310d40440520e79ef84004d9d25227a1fd4a46b81ab89eeba3a", "unvendored_tests": true, "version": "2.18.3"}, "zarr-tests": {"depends": ["zarr"], "file_name": "zarr-tests.tar", "imports": [], "install_dir": "site", "name": "zarr-tests", "package_type": "package", "sha256": "48a7c9e3be63b05c513e3f6d349b432d2179e3bd6a6696845c1a9fb9c258d236", "unvendored_tests": false, "version": "2.18.3"}, "zengl": {"depends": [], "file_name": "zengl-2.7.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["zengl", "_zengl"], "install_dir": "site", "name": "zengl", "package_type": "package", "sha256": "1792f79ca05ebf3afb10b1a06881dd6680bfe52d7c9896e34899fa3e8435cbeb", "unvendored_tests": false, "version": "2.7.1"}, "zfpy": {"depends": ["numpy"], "file_name": "zfpy-1.0.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["zfpy"], "install_dir": "site", "name": "zfpy", "package_type": "package", "sha256": "beab06fc05ed3cdb8cb0fe403369d3f838fec88ebf5a4981e253fa74265ce072", "unvendored_tests": false, "version": "1.0.1"}, "zstandard": {"depends": ["cffi"], "file_name": "zstandard-0.22.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["zstandard"], "install_dir": "site", "name": "zstandard", "package_type": "package", "sha256": "8c83038208fd422dd2f1adaed69afabf7b3d6e72c7669fbb07a98dc3c8b8a049", "unvendored_tests": false, "version": "0.22.0"}}} \ No newline at end of file diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.asm.js b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.asm.js deleted file mode 100644 index 7d7e6f6b24..0000000000 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.asm.js +++ /dev/null @@ -1,17 +0,0 @@ -"use strict"; - -var _createPyodideModule = (() => { - var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined; - if (typeof __filename != 'undefined') _scriptName ||= __filename; - return ( -function(moduleArg = {}) { - var moduleRtn; - -var Module=Object.assign({},moduleArg);var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(ENVIRONMENT_IS_NODE){}var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");if(ENVIRONMENT_IS_WORKER){scriptDirectory=nodePath.dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=(filename,binary)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return fs.readFileSync(filename,binary?undefined:"utf8")};readBinary=filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret};readAsync=(filename,onload,onerror,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);fs.readFile(filename,binary?undefined:"utf8",(err,data)=>{if(err)onerror(err);else onload(binary?data.buffer:data)})};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptName){scriptDirectory=_scriptName}if(scriptDirectory.startsWith("blob:")){scriptDirectory=""}else{scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];if(!Module.wrapException){Module.wrapException=e=>e}var dynamicLibraries=Module["dynamicLibraries"]||[];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];function intArrayFromBase64(s){if(typeof ENVIRONMENT_IS_NODE!="undefined"&&ENVIRONMENT_IS_NODE){var buf=Buffer.from(s,"base64");return new Uint8Array(buf.buffer,buf.byteOffset,buf.length)}var decoded=atob(s);var bytes=new Uint8Array(decoded.length);for(var i=0;ifilename.startsWith(dataURIPrefix);var isFileURI=filename=>filename.startsWith("file://");var wasmBinaryFile;wasmBinaryFile="pyodide.asm.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch=="function"&&!isFileURI(binaryFile)){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{if(!response["ok"]){throw`failed to load wasm binary file at '${binaryFile}'`}return response["arrayBuffer"]()}).catch(()=>getBinarySync(binaryFile))}else if(readAsync){return new Promise((resolve,reject)=>{readAsync(binaryFile,response=>resolve(new Uint8Array(response)),reject)})}}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function getWasmImports(){return{"env":wasmImports,"wasi_snapshot_preview1":wasmImports,"GOT.mem":new Proxy(wasmImports,GOTHandler),"GOT.func":new Proxy(wasmImports,GOTHandler)}}function createWasm(){var info=getWasmImports();if(Module.adjustWasmImports){Module.adjustWasmImports(info)}function receiveInstance(instance,module){wasmExports=instance.exports;wasmExports=relocateExports(wasmExports,1024);var metadata=getDylinkMetadata(module);if(metadata.neededDynlibs){dynamicLibraries=metadata.neededDynlibs.concat(dynamicLibraries)}mergeLibSymbols(wasmExports,"main");LDSO.init();loadDylibs();wasmExports=applySignatureConversions(wasmExports);addOnInit(wasmExports["__wasm_call_ctors"]);__RELOC_FUNCS__.push(wasmExports["__wasm_apply_data_relocs"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"],result["module"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e)}}instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}var ASM_CONSTS={4581890:()=>{throw new Error("intentionally triggered fatal error!")},4581947:()=>{wasmImports["open64"]=wasmImports["open"]},4581996:()=>jspiSupported};function console_error(msg){let jsmsg=UTF8ToString(msg);console.error(jsmsg)}function console_error_obj(obj){console.error(obj)}function new_error(type,msg,err){return new API.PythonError(UTF8ToString(type),msg,err)}new_error.sig="eiei";function fail_test(){API.fail_test=true}fail_test.sig="v";function capture_stderr(){API.capture_stderr()}capture_stderr.sig="v";function restore_stderr(){return API.restore_stderr()}restore_stderr.sig="e";function raw_call_js(func){func()}raw_call_js.sig="ve";function hiwire_invalid_ref_js(type,ref){API.fail_test=!!1;if(type===1&&!ref){if(_PyErr_Occurred()){const e=_wrap_exception();console.error("Pyodide internal error: Argument to hiwire_get is falsy. This was "+"probably because the Python error indicator was set when get_value was "+"called. The Python error that caused this was:",e);throw e}else{const msg="Pyodide internal error: Argument to hiwire_get is falsy (but error "+"indicator is not set).";console.error(msg);throw new Error(msg)}}const typestr={[1]:"get",[2]:"incref",[3]:"decref"}[type];const msg=`hiwire_${typestr} on invalid reference ${ref}. This is most likely due `+"to use after free. It may also be due to memory corruption.";console.error(msg);throw new Error(msg)}hiwire_invalid_ref_js.sig="vii";function set_pyodide_module(mod){API._pyodide=mod}set_pyodide_module.sig="ve";function js2python_immutable_js(value){try{let result=Module.js2python_convertImmutable(value);if(result!==undefined){return result}return 0}catch(e){Module.handle_js_error(e);return 0}errNoRet()}js2python_immutable_js.sig="ie";function js2python_js(value){try{let result=Module.js2python_convertImmutable(value);if(result!==undefined){return result}return _JsProxy_create(value)}catch(e){Module.handle_js_error(e);return 0}errNoRet()}js2python_js.sig="ie";function js2python_convert(v,depth,defaultConverter){try{return Module.js2python_convert(v,{depth:depth,defaultConverter:defaultConverter})}catch(e){Module.handle_js_error(e);return 0}errNoRet()}js2python_convert.sig="ieie";function isReservedWord(word){if(!Module.pythonReservedWords){Module.pythonReservedWords=new Set(["False","await","else","import","pass","None","break","except","in","raise","True","class","finally","is","return","and","continue","for","lambda","try","as","def","from","nonlocal","while","assert","del","global","not","with","async","elif","if","or","yield"])}return Module.pythonReservedWords.has(word)}function normalizeReservedWords(word){const noTrailing_=word.replace(/_*$/,"");if(!isReservedWord(noTrailing_)){return word}if(noTrailing_!==word){return word.slice(0,-1)}return word}function JsProxy_GetAttr_js(jsobj,ptrkey){try{const jskey=normalizeReservedWords(UTF8ToString(ptrkey));const result=jsobj[jskey];if(result===undefined&&!(jskey in jsobj)){return null}return nullToUndefined(result)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsProxy_GetAttr_js.sig="eei";function JsProxy_SetAttr_js(jsobj,ptrkey,jsval){try{let jskey=normalizeReservedWords(UTF8ToString(ptrkey));jsobj[jskey]=jsval}catch(e){Module.handle_js_error(e);return-1}return 0}JsProxy_SetAttr_js.sig="ieie";function JsProxy_DelAttr_js(jsobj,ptrkey){try{let jskey=normalizeReservedWords(UTF8ToString(ptrkey));delete jsobj[jskey]}catch(e){Module.handle_js_error(e);return-1}return 0}JsProxy_DelAttr_js.sig="iei";function JsProxy_GetIter_js(obj){try{return obj[Symbol.iterator]()}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsProxy_GetIter_js.sig="ee";function handle_next_result_js(res,done,msg){try{let errmsg;if(typeof res!=="object"){errmsg=`Result should have type "object" not "${typeof res}"`}else if(typeof res.done==="undefined"){if(typeof res.then==="function"){errmsg=`Result was a promise, use anext() / asend() / athrow() instead.`}else{errmsg=`Result has no "done" field.`}}if(errmsg){HEAPU32[(msg>>2)+0>>>0]=stringToNewUTF8(errmsg);HEAPU32[(done>>2)+0>>>0]=-1}HEAPU32[(done>>2)+0>>>0]=res.done;return res.value}catch(e){Module.handle_js_error(e);return-1}return 0}handle_next_result_js.sig="eeii";function JsException_new_helper(name_ptr,message_ptr,stack_ptr){try{let name=UTF8ToString(name_ptr);let message=UTF8ToString(message_ptr);let stack=UTF8ToString(stack_ptr);return API.deserializeError(name,message,stack)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsException_new_helper.sig="eiii";function JsProxy_GetAsyncIter_js(obj){try{return obj[Symbol.asyncIterator]()}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsProxy_GetAsyncIter_js.sig="ee";function _agen_handle_result_js(p,msg,set_result,set_exception,closing){try{let errmsg;if(typeof p!=="object"){errmsg=`Result of anext() should be object not ${typeof p}`}else if(typeof p.then!=="function"){if(typeof p.done==="boolean"){errmsg=`Result of anext() was not a promise, use next() instead.`}else{errmsg=`Result of anext() was not a promise.`}}if(errmsg){HEAPU32[(msg>>2)+0>>>0]=stringToNewUTF8(errmsg);return-1}_Py_IncRef(set_result);_Py_IncRef(set_exception);p.then(({done:done,value:value})=>{__agen_handle_result_js_c(set_result,set_exception,done,value,closing)},err=>{__agen_handle_result_js_c(set_result,set_exception,-1,err,closing)}).finally(()=>{_Py_DecRef(set_result);_Py_DecRef(set_exception)});return 0}catch(e){Module.handle_js_error(e);return-1}return 0}_agen_handle_result_js.sig="ieiiii";function get_length_helper(val){try{let result;if(typeof val.size==="number"){result=val.size}else if(typeof val.length==="number"){result=val.length}else{return-2}if(result<0){return-3}if(result>2147483647){return-4}return result}catch(e){Module.handle_js_error(e);return-1}return 0}get_length_helper.sig="ie";function get_length_string(val){try{let result;if(typeof val.size==="number"){result=val.size}else if(typeof val.length==="number"){result=val.length}return stringToNewUTF8(" "+result.toString())}catch(e){Module.handle_js_error(e);return 0}errNoRet()}get_length_string.sig="ie";function destroy_jsarray_entries(array){for(let v of array){try{if(typeof v.destroy==="function"){v.destroy()}}catch(e){console.warn("Weird error:",e)}}}destroy_jsarray_entries.sig="ve";function JsArray_repeat_js(o,count){try{return Array.from({length:count},()=>o).flat()}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsArray_repeat_js.sig="eei";function JsArray_inplace_repeat_js(o,count){try{o.splice(0,o.length,...Array.from({length:count},()=>o).flat())}catch(e){Module.handle_js_error(e);return-1}return 0}JsArray_inplace_repeat_js.sig="iei";function JsArray_reversed_iterator(array){return new ReversedIterator(array)}class ReversedIterator{constructor(array){this._array=array;this._i=array.length-1}__length_hint__(){return this._array.length}[Symbol.toStringTag](){return"ReverseIterator"}next(){const i=this._i;const a=this._array;const done=i<0;const value=done?undefined:a[i];this._i--;return{done:done,value:value}}}JsArray_reversed_iterator.sig="ee";function JsArray_index_js(o,v,start,stop){try{for(let i=start;i{let c=s.charCodeAt(0);return c<48||c>57}).map(word=>isReservedWord(word.replace(/_*$/,""))?word+"_":word))}while(jsobj=Object.getPrototypeOf(jsobj));return result}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsProxy_Dir_js.sig="ee";function JsProxy_Bool_js(val){try{if(!val){return!!0}if(val.size===0){if(/HTML[A-Za-z]*Element/.test(getTypeTag(val))){return!!1}return!!0}if(val.length===0&&JsvArray_Check(val)){return!!0}if(val.byteLength===0){return!!0}return!!1}catch(e){return!!0}}JsProxy_Bool_js.sig="ie";function JsObjMap_GetIter_js(obj){try{return Module.iterObject(obj)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsObjMap_GetIter_js.sig="ee";function JsObjMap_length_js(obj){try{let length=0;for(let _ of Module.iterObject(obj)){length++}return length}catch(e){Module.handle_js_error(e);return-1}return 0}JsObjMap_length_js.sig="ie";function JsObjMap_subscript_js(obj,key){try{if(!Object.prototype.hasOwnProperty.call(obj,key)){return null}return obj[key]}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsObjMap_subscript_js.sig="eee";function JsObjMap_ass_subscript_js(obj,key,value){try{if(value===null){if(!Object.prototype.hasOwnProperty.call(obj,key)){return-1}delete obj[key]}else{obj[key]=value}return 0}catch(e){Module.handle_js_error(e);return-1}return 0}JsObjMap_ass_subscript_js.sig="ieee";function JsObjMap_contains_js(obj,key){try{return Object.prototype.hasOwnProperty.call(obj,key)}catch(e){Module.handle_js_error(e);return-1}return 0}JsObjMap_contains_js.sig="iee";function JsModule_GetAll_js(o){try{return Object.getOwnPropertyNames(o)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsModule_GetAll_js.sig="ee";function JsBuffer_DecodeString_js(buffer,encoding){try{let encoding_js;if(encoding){encoding_js=UTF8ToString(encoding)}const decoder=new TextDecoder(encoding_js,{fatal:!!1,ignoreBOM:!!1});let res;try{res=decoder.decode(buffer)}catch(e){if(e instanceof TypeError){return null}throw e}return res}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsBuffer_DecodeString_js.sig="eei";function JsBuffer_get_info(jsobj,byteLength_ptr,format_ptr,size_ptr,checked_ptr){const[format_utf8,size,checked]=Module.get_buffer_datatype(jsobj);HEAPU32[(byteLength_ptr>>2)+0>>>0]=jsobj.byteLength;HEAPU32[(format_ptr>>2)+0>>>0]=format_utf8;HEAPU32[(size_ptr>>2)+0>>>0]=size;HEAPU8[checked_ptr+0>>>0]=checked}JsBuffer_get_info.sig="veiiii";function JsDoubleProxy_unwrap_helper(id){try{return Module.PyProxy_getPtr(id)}catch(e){Module.handle_js_error(e);return 0}errNoRet()}JsDoubleProxy_unwrap_helper.sig="ie";function JsProxy_compute_typeflags(obj,is_py_json){try{let type_flags=0;if(API.isPyProxy(obj)&&!pyproxyIsAlive(obj)){return 0}const typeTag=getTypeTag(obj);function safeBool(cb){try{return cb()}catch(e){return!!0}}const isBufferView=safeBool(()=>ArrayBuffer.isView(obj));const isArray=safeBool(()=>Array.isArray(obj));const constructorName=safeBool(()=>obj.constructor.name)||"";if(typeof obj==="function"){type_flags|=1<<9}if(hasMethod(obj,"then")){type_flags|=1<<7}if(hasMethod(obj,Symbol.iterator)){type_flags|=1<<0}if(hasMethod(obj,Symbol.asyncIterator)){type_flags|=1<<15}if(hasMethod(obj,"next")&&(hasMethod(obj,Symbol.iterator)||!hasMethod(obj,Symbol.asyncIterator))){type_flags|=1<<1}if(hasMethod(obj,"next")&&(!hasMethod(obj,Symbol.iterator)||hasMethod(obj,Symbol.asyncIterator))){type_flags|=1<<18}if(hasProperty(obj,"size")||hasProperty(obj,"length")&&typeof obj!=="function"){type_flags|=1<<2}if(hasMethod(obj,"get")){type_flags|=1<<3}if(hasMethod(obj,"set")){type_flags|=1<<4}if(hasMethod(obj,"has")){type_flags|=1<<5}if(hasMethod(obj,"includes")){type_flags|=1<<6}if((isBufferView||typeTag==="[object ArrayBuffer]")&&!(type_flags&1<<9)){type_flags|=1<<8}if(API.isPyProxy(obj)){type_flags|=1<<13}if(isArray){type_flags|=1<<10}if(typeTag==="[object HTMLCollection]"||typeTag==="[object NodeList]"){type_flags|=1<<11}if(isBufferView&&typeTag!=="[object DataView]"){type_flags|=1<<12}if(typeTag==="[object Generator]"){type_flags|=1<<16}if(typeTag==="[object AsyncGenerator]"){type_flags|=1<<17}if(hasProperty(obj,"name")&&hasProperty(obj,"message")&&(hasProperty(obj,"stack")||constructorName==="DOMException")&&!(type_flags&(1<<9|1<<8))){type_flags|=1<<19}if(is_py_json&&type_flags&(1<<10|1<<11|1<<1)){type_flags|=1<<21}if(is_py_json&&!(type_flags&(1<<10|1<<12|1<<11|1<<8|1<<13|1<<1|1<<9|1<<19))){type_flags|=1<<20}return type_flags}catch(e){Module.handle_js_error(e);return-1}return 0}JsProxy_compute_typeflags.sig="iei";function is_comlink_proxy(obj){try{return!!(API.Comlink&&value[API.Comlink.createEndpoint])}catch(e){return!!0}}is_comlink_proxy.sig="ie";function can_run_sync_js(){return!!validSuspender.value}can_run_sync_js.sig="i";function my_dict_converter(){return Object.fromEntries}my_dict_converter.sig="e";function get_async_js_call_done_callback(proxies){try{return function(result){let msg="This borrowed proxy was automatically destroyed "+"at the end of an asynchronous function call. Try "+"using create_proxy or create_once_callable.";for(let px of proxies){Module.pyproxy_destroy(px,msg,!!0)}if(API.isPyProxy(result)){Module.pyproxy_destroy(result,msg,!!0)}}}catch(e){Module.handle_js_error(e);return null}errNoRet()}get_async_js_call_done_callback.sig="ee";function wrap_generator(gen,proxies){try{proxies=new Set(proxies);const msg="This borrowed proxy was automatically destroyed "+"when a generator completed execution. Try "+"using create_proxy or create_once_callable.";function cleanup(){proxies.forEach(px=>Module.pyproxy_destroy(px,msg))}function wrap(funcname){return function(val){if(API.isPyProxy(val)){val=val.copy();proxies.add(val)}let res;try{res=gen[funcname](val)}catch(e){cleanup();throw e}if(res.done){proxies.delete(res.value);cleanup()}return res}}return{get[Symbol.toStringTag](){return"Generator"},[Symbol.iterator](){return this},next:wrap("next"),throw:wrap("throw"),return:wrap("return")}}catch(e){Module.handle_js_error(e);return null}errNoRet()}wrap_generator.sig="eee";function wrap_async_generator(gen,proxies){try{proxies=new Set(proxies);const msg="This borrowed proxy was automatically destroyed "+"when an asynchronous generator completed execution. Try "+"using create_proxy or create_once_callable.";function cleanup(){proxies.forEach(px=>Module.pyproxy_destroy(px,msg))}function wrap(funcname){return async function(val){if(API.isPyProxy(val)){val=val.copy();proxies.add(val)}let res;try{res=await gen[funcname](val)}catch(e){cleanup();throw e}if(res.done){proxies.delete(res.value);cleanup()}return res}}return{get[Symbol.toStringTag](){return"AsyncGenerator"},[Symbol.asyncIterator](){return this},next:wrap("next"),throw:wrap("throw"),return:wrap("return")}}catch(e){Module.handle_js_error(e);return null}errNoRet()}wrap_async_generator.sig="eee";function throw_no_gil(){throw new API.NoGilError("Attempted to use PyProxy when Python GIL not held")}throw_no_gil.sig="v";function pyproxy_Check(val){return API.isPyProxy(val)}pyproxy_Check.sig="ie";function pyproxy_AsPyObject(val){if(!API.isPyProxy(val)||!pyproxyIsAlive(val)){return 0}return Module.PyProxy_getPtr(val)}pyproxy_AsPyObject.sig="ie";function destroy_proxies(proxies,msg_ptr){let msg=undefined;if(msg_ptr){msg=_JsvString_FromId(msg_ptr)}for(let px of proxies){Module.pyproxy_destroy(px,msg,false)}}destroy_proxies.sig="vei";function gc_register_proxies(proxies){for(let px of proxies){Module.gc_register_proxy(Module.PyProxy_getAttrs(px).shared)}}gc_register_proxies.sig="ve";function destroy_proxy(px,msg_ptr){const{shared:shared,props:props}=Module.PyProxy_getAttrsQuiet(px);if(!shared.ptr){return}if(props.roundtrip){return}let msg=undefined;if(msg_ptr){msg=_JsvString_FromId(msg_ptr)}Module.pyproxy_destroy(px,msg,false)}destroy_proxy.sig="vei";function proxy_cache_get(proxyCache,descr){const proxy=proxyCache.get(descr);if(!proxy){return null}if(pyproxyIsAlive(proxy)){return proxy}else{proxyCache.delete(descr);return null}}proxy_cache_get.sig="eei";function proxy_cache_set(proxyCache,descr,proxy){proxyCache.set(descr,proxy)}proxy_cache_set.sig="veie";function _pyproxyGen_make_result(done,value){return{done:!!done,value:value}}_pyproxyGen_make_result.sig="eie";function array_to_js(array,len){return Array.from(HEAP32.subarray(array/4>>>0,array/4+len>>>0))}array_to_js.sig="eii";function _pyproxy_get_buffer_result(start_ptr,smallest_ptr,largest_ptr,readonly,format,itemsize,shape,strides,view,c_contiguous,f_contiguous,sentinel){format=UTF8ToString(format);return{start_ptr:start_ptr,smallest_ptr:smallest_ptr,largest_ptr:largest_ptr,readonly:readonly,format:format,itemsize:itemsize,shape:shape,strides:strides,view:view,c_contiguous:c_contiguous,f_contiguous:f_contiguous}}_pyproxy_get_buffer_result.sig="eiiiiiieeiiii";function pyproxy_new_ex(ptrobj,capture_this,roundtrip,gcRegister,jsonAdaptor){try{return Module.pyproxy_new(ptrobj,{props:{captureThis:!!capture_this,roundtrip:!!roundtrip},gcRegister:gcRegister,jsonAdaptor:jsonAdaptor})}catch(e){Module.handle_js_error(e);return null}errNoRet()}pyproxy_new_ex.sig="eiiiii";function pyproxy_new(ptrobj){try{return Module.pyproxy_new(ptrobj)}catch(e){Module.handle_js_error(e);return null}errNoRet()}pyproxy_new.sig="ei";function create_once_callable(obj,may_syncify){try{_Py_IncRef(obj);let alreadyCalled=!!0;function wrapper(...args){if(alreadyCalled){throw new Error("OnceProxy can only be called once")}try{if(may_syncify){return Module.callPyObjectMaybePromising(obj,args)}else{return Module.callPyObject(obj,args)}}finally{wrapper.destroy()}}wrapper.destroy=function(){if(alreadyCalled){throw new Error("OnceProxy has already been destroyed")}alreadyCalled=!!1;Module.finalizationRegistry.unregister(wrapper);_Py_DecRef(obj)};Module.finalizationRegistry.register(wrapper,[obj,undefined],wrapper);return wrapper}catch(e){Module.handle_js_error(e);return null}errNoRet()}create_once_callable.sig="eii";function create_promise_handles(handle_result,handle_exception,done_callback,js2py_converter){try{if(handle_result){_Py_IncRef(handle_result)}if(handle_exception){_Py_IncRef(handle_exception)}if(js2py_converter){_Py_IncRef(js2py_converter)}if(!done_callback){done_callback=x=>{}}let used=!!0;function checkUsed(){if(used){throw new Error("One of the promise handles has already been called.")}}function destroy(){checkUsed();used=!!1;if(handle_result){_Py_DecRef(handle_result)}if(handle_exception){_Py_DecRef(handle_exception)}if(js2py_converter){_Py_DecRef(js2py_converter)}}function onFulfilled(res){checkUsed();try{if(handle_result){return _create_promise_handles_result_helper(handle_result,js2py_converter,res)}}finally{done_callback(res);destroy()}}function onRejected(err){checkUsed();try{if(handle_exception){return Module.callPyObjectMaybePromising(handle_exception,[err])}}finally{done_callback(undefined);destroy()}}onFulfilled.destroy=destroy;onRejected.destroy=destroy;return[onFulfilled,onRejected]}catch(e){Module.handle_js_error(e);return null}errNoRet()}create_promise_handles.sig="eiiei";function _python2js_buffer_inner(buf,itemsize,ndim,format,shape,strides,suboffsets){try{let converter=Module.get_converter(format,itemsize);return Module._python2js_buffer_recursive(buf,0,{ndim:ndim,format:format,itemsize:itemsize,shape:shape,strides:strides,suboffsets:suboffsets,converter:converter})}catch(e){Module.handle_js_error(e);return null}errNoRet()}_python2js_buffer_inner.sig="eiiiiiii";function jslib_init_js(){try{HEAP32[_Jsr_undefined/4>>>0]=_hiwire_intern(undefined);HEAP32[_Jsr_true/4>>>0]=_hiwire_intern(true);HEAP32[_Jsr_false/4>>>0]=_hiwire_intern(false);HEAP32[_Jsr_novalue/4>>>0]=_hiwire_intern({noValueMarker:1});Module.novalue=_hiwire_get(HEAP32[_Jsr_novalue/4>>>0]);Hiwire.num_keys=_hiwire_num_refs;return 0}catch(e){Module.handle_js_error(e);return-1}return 0}jslib_init_js.sig="i";function JsvNoValue_Check(v){return v===Module.novalue}JsvNoValue_Check.sig="ie";function JsvNum_fromInt(x){return x}JsvNum_fromInt.sig="ei";function JsvNum_fromDouble(val){return val}JsvNum_fromDouble.sig="ed";function JsvNum_fromDigits(digits,ndigits){let result=BigInt(0);for(let i=0;i>2)+i>>>0])<>2)+ndigits-1>>>0]&2147483648)<=arr.length){return null}return arr.splice(idx,1)[0]}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvArray_Delete.sig="eei";function JsvArray_Push(arr,obj){return arr.push(obj)}JsvArray_Push.sig="iee";function JsvArray_Extend(arr,vals){arr.push(...vals)}JsvArray_Extend.sig="vee";function JsvArray_Insert(arr,idx,value){try{arr.splice(idx,0,value)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvArray_Insert.sig="ieie";function JsvArray_ShallowCopy(arr){try{return"slice"in arr?arr.slice():Array.from(arr)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvArray_ShallowCopy.sig="ee";function JsvArray_slice(obj,length,start,stop,step){try{let result;if(step===1){result=obj.slice(start,stop)}else{result=Array.from({length:length},(_,i)=>obj[start+i*step])}return result}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvArray_slice.sig="eeiiii";function JsvArray_slice_assign(obj,slicelength,start,stop,step,values_length,values){try{let jsvalues=[];for(let i=0;i>2)+i>>>0]);if(ref===null){return-1}jsvalues.push(ref)}if(step===1){obj.splice(start,slicelength,...jsvalues)}else{if(values!==0){for(let i=0;i=0;i--){obj.splice(start+i*step,1)}}}}catch(e){Module.handle_js_error(e);return-1}return 0}JsvArray_slice_assign.sig="ieiiiiii";function JsvObject_New(){return{}}JsvObject_New.sig="e";function JsvObject_SetAttr(obj,attr,value){try{obj[attr]=value}catch(e){Module.handle_js_error(e);return-1}return 0}JsvObject_SetAttr.sig="ieee";function JsvObject_Entries(obj){try{return Object.entries(obj)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvObject_Entries.sig="ee";function JsvObject_Keys(obj){try{return Object.keys(obj)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvObject_Keys.sig="ee";function JsvObject_Values(obj){try{return Object.values(obj)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvObject_Values.sig="ee";function JsvObject_toString(obj){try{if(hasMethod(obj,"toString")){return obj.toString()}return Object.prototype.toString.call(obj)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvObject_toString.sig="ee";function JsvObject_CallMethod(obj,meth,args){try{return nullToUndefined(obj[meth](...args))}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvObject_CallMethod.sig="eeee";function JsvObject_CallMethod_NoArgs(obj,meth){try{return nullToUndefined(obj[meth]())}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvObject_CallMethod_NoArgs.sig="eee";function JsvObject_CallMethod_OneArg(obj,meth,arg){try{return nullToUndefined(obj[meth](arg))}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvObject_CallMethod_OneArg.sig="eeee";function JsvObject_CallMethod_TwoArgs(obj,meth,arg1,arg2){try{return nullToUndefined(obj[meth](arg1,arg2))}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvObject_CallMethod_TwoArgs.sig="eeeee";function JsvFunction_Check(obj){try{return typeof obj==="function"}catch(e){return false}}JsvFunction_Check.sig="ie";function JsvFunction_CallBound(func,this_,args){try{return nullToUndefined(Function.prototype.apply.apply(func,[this_,args]))}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvFunction_CallBound.sig="eeee";function JsvFunction_Call_OneArg(func,arg){try{return nullToUndefined(func(arg))}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvFunction_Call_OneArg.sig="eee";function JsvFunction_Construct(func,args){try{return nullToUndefined(Reflect.construct(func,args))}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvFunction_Construct.sig="eee";function JsvPromise_Check(obj){try{return isPromise(obj)}catch(e){return false}}JsvPromise_Check.sig="ie";function JsvPromise_Resolve(obj){try{return Promise.resolve(obj)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvPromise_Resolve.sig="ee";function jslib_init_buffers_js(){try{const dtypes_str=Array.from("bBhHiIqQfd").join(String.fromCharCode(0));const dtypes_ptr=stringToNewUTF8(dtypes_str);const dtypes_map=Object.fromEntries(Object.entries(dtypes_str).map(([idx,val])=>[val,dtypes_ptr+ +idx]));const buffer_datatype_map=new Map([["Int8Array",[dtypes_map["b"],1,true]],["Uint8Array",[dtypes_map["B"],1,true]],["Uint8ClampedArray",[dtypes_map["B"],1,true]],["Int16Array",[dtypes_map["h"],2,true]],["Uint16Array",[dtypes_map["H"],2,true]],["Int32Array",[dtypes_map["i"],4,true]],["Uint32Array",[dtypes_map["I"],4,true]],["Float32Array",[dtypes_map["f"],4,true]],["Float64Array",[dtypes_map["d"],8,true]],["BigInt64Array",[dtypes_map["q"],8,true]],["BigUint64Array",[dtypes_map["Q"],8,true]],["DataView",[dtypes_map["B"],1,false]],["ArrayBuffer",[dtypes_map["B"],1,false]]]);Module.get_buffer_datatype=function(jsobj){return buffer_datatype_map.get(jsobj.constructor.name)||[0,0,false]}}catch(e){Module.handle_js_error(e);return-1}return 0}jslib_init_buffers_js.sig="i";function JsvBuffer_assignToPtr(buf,ptr){try{Module.HEAPU8.set(bufferAsUint8Array(buf),ptr)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvBuffer_assignToPtr.sig="iei";function JsvBuffer_assignFromPtr(buf,ptr){try{bufferAsUint8Array(buf).set(Module.HEAPU8.subarray(ptr,ptr+buf.byteLength))}catch(e){Module.handle_js_error(e);return-1}return 0}JsvBuffer_assignFromPtr.sig="iei";function JsvBuffer_readFromFile(buf,fd){try{let uint8_buf=bufferAsUint8Array(buf);let stream=Module.FS.streams[fd];Module.FS.read(stream,uint8_buf,0,uint8_buf.byteLength)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvBuffer_readFromFile.sig="iei";function JsvBuffer_writeToFile(buf,fd){try{let uint8_buf=bufferAsUint8Array(buf);let stream=Module.FS.streams[fd];Module.FS.write(stream,uint8_buf,0,uint8_buf.byteLength)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvBuffer_writeToFile.sig="iei";function JsvBuffer_intoFile(buf,fd){try{let uint8_buf=bufferAsUint8Array(buf);let stream=Module.FS.streams[fd];Module.FS.write(stream,uint8_buf,0,uint8_buf.byteLength,undefined,true)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvBuffer_intoFile.sig="iei";function JsvGenerator_Check(obj){try{return getTypeTag(obj)==="[object Generator]"}catch(e){return false}}JsvGenerator_Check.sig="ie";function JsvAsyncGenerator_Check(obj){try{return getTypeTag(obj)==="[object AsyncGenerator]"}catch(e){return false}}JsvAsyncGenerator_Check.sig="ie";function JsvError_Throw(e){throw e}JsvError_Throw.sig="ve";function Jsv_less_than(a,b){try{return!!(ab)}catch(e){return false}}Jsv_greater_than.sig="iee";function Jsv_greater_than_equal(a,b){try{return!!(a>=b)}catch(e){return false}}Jsv_greater_than_equal.sig="iee";function JsvMap_New(){try{return new Map}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvMap_New.sig="e";function JsvLiteralMap_New(){try{return new API.LiteralMap}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvLiteralMap_New.sig="e";function JsvMap_Set(map,key,val){try{map.set(key,val)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvMap_Set.sig="ieee";function JsvSet_New(){try{return new Set}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvSet_New.sig="e";function JsvSet_Add(set,val){try{set.add(val)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvSet_Add.sig="iee";function _python2js_addto_postprocess_list(list,parent,key,value){list.push([parent,key,value])}_python2js_addto_postprocess_list.sig="veeei";function _python2js_handle_postprocess_list(list,cache){for(const[parent,key,ptr]of list){let val=cache.get(ptr);if(parent.constructor.name==="LiteralMap"){parent.set(key,val)}else{parent[key]=val}}}_python2js_handle_postprocess_list.sig="vee";function _python2js_ucs1(ptr,len){try{let jsstr="";for(let i=0;i>>0])}return jsstr}catch(e){Module.handle_js_error(e);return null}errNoRet()}_python2js_ucs1.sig="eii";function _python2js_ucs2(ptr,len){try{let jsstr="";for(let i=0;i>1)+i>>>0])}return jsstr}catch(e){Module.handle_js_error(e);return null}errNoRet()}_python2js_ucs2.sig="eii";function _python2js_ucs4(ptr,len){try{let jsstr="";for(let i=0;i>2)+i>>>0])}return jsstr}catch(e){Module.handle_js_error(e);return null}errNoRet()}_python2js_ucs4.sig="eii";function _python2js_add_to_cache(cache,pyparent,jsparent){try{cache.set(pyparent,jsparent)}catch(e){Module.handle_js_error(e);return-1}return 0}_python2js_add_to_cache.sig="ieie";function _python2js_cache_lookup(cache,pyparent){return cache.get(pyparent)||null}_python2js_cache_lookup.sig="eei";function _JsArray_PushEntry_helper(array,key,value){try{array.push([key,value])}catch(e){Module.handle_js_error(e);return-1}return 0}_JsArray_PushEntry_helper.sig="ieee";function _JsArray_PostProcess_helper(jscontext,array){try{return jscontext.dict_converter(array)}catch(e){Module.handle_js_error(e);return null}errNoRet()}_JsArray_PostProcess_helper.sig="eee";function python2js__default_converter_js(jscontext,object){try{let proxy=Module.pyproxy_new(object);try{return jscontext.default_converter(proxy,jscontext.converter,jscontext.cacheConversion)}finally{proxy.destroy()}}catch(e){Module.handle_js_error(e);return null}errNoRet()}python2js__default_converter_js.sig="eei";function python2js__eager_converter_js(jscontext,object){try{if(jscontext.eager_visited.has(object)){return Module.novalue}jscontext.eager_visited.add(object);const proxy=Module.pyproxy_new(object);try{return jscontext.eager_converter(proxy,jscontext.converter,jscontext.cacheConversion)}finally{proxy.destroy()}}catch(e){Module.handle_js_error(e);return null}errNoRet()}python2js__eager_converter_js.sig="eei";function python2js_custom__create_jscontext(context,cache,dict_converter,default_converter,eager_converter){try{const jscontext={};if(dict_converter){jscontext.dict_converter=dict_converter}if(default_converter){jscontext.default_converter=default_converter;jscontext.cacheConversion=function(input,output){if(!API.isPyProxy(input)){throw new TypeError("The first argument to cacheConversion must be a PyProxy.")}const input_ptr=Module.PyProxy_getPtr(input);cache.set(input_ptr,output)}}if(eager_converter){jscontext.eager_converter=eager_converter;jscontext.eager_visited=new Set}if(default_converter||eager_converter){jscontext.converter=function(x){if(!API.isPyProxy(x)){return x}const ptr=Module.PyProxy_getPtr(x);let res;try{res=__python2js(context,ptr)}catch(e){API.fatal_error(e)}if(res===null){_pythonexc2js()}return res}}return jscontext}catch(e){Module.handle_js_error(e);return null}errNoRet()}python2js_custom__create_jscontext.sig="eieeee";function destroy_proxies_js(proxies_id){try{for(const proxy of proxies_id){proxy.destroy()}}catch(e){Module.handle_js_error(e);return-1}return 0}destroy_proxies_js.sig="ie";function pyodide_js_init(){"use strict";(()=>{var Vr=Object.create;var mt=Object.defineProperty;var qr=Object.getOwnPropertyDescriptor;var Yr=Object.getOwnPropertyNames;var Qr=Object.getPrototypeOf,Xr=Object.prototype.hasOwnProperty;var i=(t,e)=>mt(t,"name",{value:e,configurable:!0}),x=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+t+'" is not supported')});var Zr=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Yr(e))!Xr.call(t,o)&&o!==r&&mt(t,o,{get:()=>e[o],enumerable:!(n=qr(e,o))||n.enumerable});return t};var T=(t,e,r)=>(r=t!=null?Vr(Qr(t)):{},Zr(e||!t||!t.__esModule?mt(r,"default",{value:t,enumerable:!0}):r,t));var Bt=(t,e,r)=>{if(!e.has(t))throw TypeError("Cannot "+r)};var y=(t,e,r)=>(Bt(t,e,"read from private field"),r?r.call(t):e.get(t)),D=(t,e,r)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,r)},M=(t,e,r,n)=>(Bt(t,e,"write to private field"),n?n.call(t,r):e.set(t,r),r);function en(t){return!isNaN(parseFloat(t))&&isFinite(t)}i(en,"_isNumber");function B(t){return t.charAt(0).toUpperCase()+t.substring(1)}i(B,"_capitalize");function _t(t){return function(){return this[t]}}i(_t,"_getter");var W=["isConstructor","isEval","isNative","isToplevel"],G=["columnNumber","lineNumber"],J=["fileName","functionName","source"],tn=["args"],rn=["evalOrigin"],Re=W.concat(G,J,tn,rn);function A(t){if(t)for(var e=0;e-1&&(a=a.replace(/eval code/g,"eval").replace(/(\(eval at [^()]*)|(,.*$)/g,""));var s=a.replace(/^\s+/,"").replace(/\(eval code/g,"(").replace(/^.*?\s+/,""),l=s.match(/ (\(.+\)$)/);s=l?s.replace(l[0],""):s;var c=this.extractLocation(l?l[1]:s),u=l&&s||void 0,d=["eval",""].indexOf(c[0])>-1?void 0:c[0];return new Le({functionName:u,fileName:d,lineNumber:c[1],columnNumber:c[2],source:a})},this)},"ErrorStackParser$$parseV8OrIE"),parseFFOrSafari:i(function(n){var o=n.stack.split(`\n`).filter(function(a){return!a.match(e)},this);return o.map(function(a){if(a.indexOf(" > eval")>-1&&(a=a.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,":$1")),a.indexOf("@")===-1&&a.indexOf(":")===-1)return new Le({functionName:a});var s=/((.*".+"[^@]*)?[^@]*)(?:@)/,l=a.match(s),c=l&&l[1]?l[1]:void 0,u=this.extractLocation(a.replace(s,""));return new Le({functionName:c,fileName:u[0],lineNumber:u[1],columnNumber:u[2],source:a})},this)},"ErrorStackParser$$parseFFOrSafari")}}i(nn,"ErrorStackParser");var on=new nn;var ht=on;function Wt(t){if(typeof t=="string")t=new Error(t);else if(t&&typeof t=="object"&&t.name==="ExitStatus"){let e=t.status;t=new K(t.message),t.status=e}else if(typeof t!="object"||t===null||typeof t.stack!="string"||typeof t.message!="string"){let e=API.getTypeTag(t),r=`A value of type ${typeof t} with tag ${e} was thrown as an error!`;try{r+=`\nString interpolation of the thrown value gives """${t}""".`}catch{r+=`\nString interpolation of the thrown value fails.`}try{r+=`\nThe thrown value's toString method returns """${t.toString()}""".`}catch{r+=`\nThe thrown value's toString method fails.`}t=new Error(r)}return t}i(Wt,"ensureCaughtObjectIsError");var re=class extends Error{constructor(r,n,o){n||(n=`The exception is an object of type ${r} at address ${o} which does not inherit from std::exception`);super(n);this.ty=r}};i(re,"CppException");Object.defineProperty(re.prototype,"name",{get(){return`${this.constructor.name} ${this.ty}`}});var an=WebAssembly.Exception||function(){},Gt=i(t=>t instanceof an,"isWasmException");function Jt(t){if(Gt(t))if(t.is(Module.jsWrapperTag))t=t.getArg(Module.jsWrapperTag,0);else return t;let[e,r]=Module.getExceptionMessage(t);return new re(e,r,t)}i(Jt,"convertCppException");Tests.convertCppException=Jt;var Ht=!1;API.fatal_error=function(t){if(t&&t.pyodide_fatal_error)return;if(Ht){console.error("Recursive call to fatal_error. Inner error was:"),console.error(t);return}if(t instanceof V)throw t;typeof t=="number"||Gt(t)?t=Jt(t):t=Wt(t),t.pyodide_fatal_error=!0,Ht=!0;let e=t instanceof K;e||(console.error("Pyodide has suffered a fatal error. Please report this to the Pyodide maintainers."),console.error("The cause of the fatal error was:"),API.inTestHoist?(console.error(t.toString()),console.error(t.stack)):console.error(t));try{e||_dump_traceback();let n=`Pyodide already ${e?"exited":"fatally failed"} and can no longer be used.`;for(let o of Reflect.ownKeys(API.public_api))typeof o=="string"&&o.startsWith("_")||o==="version"||Object.defineProperty(API.public_api,o,{enumerable:!0,configurable:!0,get:()=>{throw new Error(n)}});API.on_fatal&&API.on_fatal(t)}catch(r){console.error("Another error occurred while handling the fatal error:"),console.error(r)}throw t};API.maybe_fatal_error=function(t){API._skip_unwind_fatal_error&&t==="unwind"||API.fatal_error(t)};var bt=[];API.capture_stderr=function(){bt=[],FS.createDevice("/dev","capture_stderr",null,t=>bt.push(t)),FS.closeStream(2),FS.open("/dev/capture_stderr",1)};API.restore_stderr=function(){return FS.closeStream(2),FS.unlink("/dev/capture_stderr"),FS.open("/dev/stderr",1),(new TextDecoder).decode(new Uint8Array(bt))};API.fatal_loading_error=function(...t){let e=t.join(" ");if(_PyErr_Occurred()){API.capture_stderr(),_PyErr_Print();let r=API.restore_stderr();e+=`\n`+r}throw new ne(e)};function Pt(t){if(!t)return!1;let e=t.fileName||"";if(e.includes("wasm-function"))return!0;if(!e.includes("pyodide.asm.js"))return!1;let r=t.functionName||"";return r.startsWith("Object.")&&(r=r.slice(7)),API.public_api&&r in API.public_api&&r!=="PythonError"?(t.functionName=r,!1):!0}i(Pt,"isPyodideFrame");function zt(t){return Pt(t)&&t.functionName==="new_error"}i(zt,"isErrorStart");Module.handle_js_error=function(t){if(t&&t.pyodide_fatal_error)throw t;if(t instanceof k)return;let e=!1;t instanceof R&&(e=_restore_sys_last_exception(t.__error_address));let r,n;try{r=ht.parse(t)}catch{n=!0}if(n&&(t=Wt(t)),!e){let o=_JsProxy_create(t);_set_error(o),_Py_DecRef(o)}if(!n){if(zt(r[0])||zt(r[1]))for(;Pt(r[0]);)r.shift();for(let o of r){if(Pt(o))break;let a=stringToNewUTF8(o.functionName||"???"),s=stringToNewUTF8(o.fileName||"???.js");__PyTraceback_Add(a,s,o.lineNumber),_free(a),_free(s)}}};var R=class extends Error{constructor(r,n,o){let a=Error.stackTraceLimit;Error.stackTraceLimit=1/0;super(n);Error.stackTraceLimit=a,this.type=r,this.__error_address=o}};i(R,"PythonError");API.PythonError=R;var k=class extends Error{constructor(){super("If you are seeing this message, an internal Pyodide error has occurred. Please report it to the Pyodide maintainers.")}};i(k,"_PropagatePythonError");function sn(t){Object.defineProperty(t.prototype,"name",{value:t.name})}i(sn,"setName");var ne=class extends Error{};i(ne,"FatalPyodideError");var K=class extends Error{};i(K,"Exit");var V=class extends Error{};i(V,"NoGilError");[k,ne,K,R,V].forEach(sn);API.NoGilError=V;API.errorConstructors=new Map([EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError,globalThis.DOMException,globalThis.AssertionError,globalThis.SystemError].filter(t=>t).map(t=>[t.constructor.name,t]));API.deserializeError=function(t,e,r){let n=API.errorConstructors.get(t)||Error,o=new n(e);return API.errorConstructors.has(t)||(o.name=t),o.message=e,o.stack=r,o};function ln(t){let e=0,r=[];for(let s of t){let l=s.codePointAt(0);r.push(l),e=l>e?l:e}let n=r.length,o=_PyUnicode_New(n,e);if(o===0)throw new k;let a=_PyUnicode_Data(o);if(e>65535)for(let s=0;s>2)+s>>>0]=r[s];else if(e>255)for(let s=0;s>1)+s>>>0]=r[s];else for(let s=0;s>>0]=r[s];return o}i(ln,"js2python_string");function cn(t){let e=t,r=0;for(t<0&&(t=-t),t<<=BigInt(1);t;)r++,t>>=BigInt(32);let n=stackSave(),o=stackAlloc(r*4);t=e;for(let s=0;s>2)+s>>>0]=Number(t&BigInt(4294967295)),t>>=BigInt(32);let a=__PyLong_FromByteArray(o,r*4,!0,!0);return stackRestore(n),a}i(cn,"js2python_bigint");function oe(t){let e=un(t);if(e===0)throw new k;return e}i(oe,"js2python_convertImmutable");Module.js2python_convertImmutable=oe;function un(t){let e=typeof t;if(e==="string")return ln(t);if(e==="number")return Number.isSafeInteger(t)?_PyLong_FromDouble(t):_PyFloat_FromDouble(t);if(e==="bigint")return cn(t);if(t==null)return __js2python_none();if(t===!0)return __js2python_true();if(t===!1)return __js2python_false();if(API.isPyProxy(t)){let{props:r,shared:n}=Module.PyProxy_getAttrs(t);return r.roundtrip?_JsProxy_create(t):__js2python_pyproxy(n.ptr)}}i(un,"js2python_convertImmutableInner");function dn(t,e){let r=_PyList_New(t.length);if(r===0)return 0;let n=0;try{e.cache.set(t,r);for(let o=0;oModule.pyproxy_new($e(o,n)),cacheConversion(o,a){if(API.isPyProxy(a))n.cache.set(o,Module.PyProxy_getPtr(a));else throw new Error("Second argument should be a PyProxy!")}};return $e(t,n)}i(fn,"js2python_convert");Module.js2python_convert=fn;Module.processBufferFormatString=function(t,e=""){if(t.length>2)throw new Error(`Expected format string to have length <= 2, got '${t}'.`+e);let r=t.slice(-1),n=t.slice(0,-1),o;switch(n){case"!":case">":o=!0;break;case"<":case"@":case"=":case"":o=!1;break;default:throw new Error(`Unrecognized alignment character ${n}.`+e)}let a;switch(r){case"b":a=Int8Array;break;case"s":case"p":case"c":case"B":case"?":a=Uint8Array;break;case"h":a=Int16Array;break;case"H":a=Uint16Array;break;case"i":case"l":case"n":a=Int32Array;break;case"I":case"L":case"N":case"P":a=Uint32Array;break;case"q":if(globalThis.BigInt64Array===void 0)throw new Error("BigInt64Array is not supported on this browser."+e);a=BigInt64Array;break;case"Q":if(globalThis.BigUint64Array===void 0)throw new Error("BigUint64Array is not supported on this browser."+e);a=BigUint64Array;break;case"f":a=Float32Array;break;case"d":a=Float64Array;break;case"e":throw new Error("Javascript has no Float16 support.");default:throw new Error(`Unrecognized format character '${r}'.`+e)}return[a,o]};Module.python2js_buffer_1d_contiguous=function(t,e,r){let n=e*r;return HEAP8.slice(t,t+n).buffer};Module.python2js_buffer_1d_noncontiguous=function(t,e,r,n,o){let a=o*n,s=new Uint8Array(a);for(let l=0;l=0&&(c=HEAPU32[(c>>2)+0>>>0]+r),s.set(HEAP8.subarray(c>>>0,c+o>>>0),l*o)}return s.buffer};Module._python2js_buffer_recursive=function(t,e,r){let{shape:n,strides:o,ndim:a,converter:s,itemsize:l,suboffsets:c}=r,u=HEAPU32[(n>>2)+e>>>0],d=HEAP32[(o>>2)+e>>>0],p=-1;if(a===0)return s(Module.python2js_buffer_1d_contiguous(t,l,1));if(c!==0&&(p=HEAP32[(c>>2)+e>>>0]),e===a-1){let m;return d===l&&p<0?m=Module.python2js_buffer_1d_contiguous(t,d,u):m=Module.python2js_buffer_1d_noncontiguous(t,d,p,u,l),s(m)}let _=[];for(let m=0;m=0&&(curptr=HEAPU32[(curptr>>2)+0>>>0]+p),_.push(Module._python2js_buffer_recursive(F,e+1,r))}return _};Module.get_converter=function(t,e){let r=UTF8ToString(t),[n,o]=Module.processBufferFormatString(r);switch(r.slice(-1)){case"s":let u=new TextDecoder("utf8",{ignoreBOM:!0});return d=>u.decode(d);case"?":return d=>Array.from(new Uint8Array(d),p=>!!p)}if(!o)return u=>new n(u);let s,l;switch(e){case 2:s="getUint16",l="setUint16";break;case 4:s="getUint32",l="setUint32";break;case 8:s="getFloat64",l="setFloat64";break;default:throw new Error(`Unexpected size ${e}`)}function c(u){let d=new DataView(u),p=d[s].bind(d),_=d[l].bind(d);for(let m=0;mnew n(c(u))};function gn(t){try{return t instanceof g}catch{return!1}}i(gn,"isPyProxy");API.isPyProxy=gn;globalThis.FinalizationRegistry?Module.finalizationRegistry=new FinalizationRegistry(({ptr:t,cache:e})=>{e&&(e.leaked=!0,rr(e));try{_check_gil();let r=validSuspender.value;validSuspender.value=!1,_Py_DecRef(t),validSuspender.value=r}catch(r){API.fatal_error(r)}}):Module.finalizationRegistry={register(){},unregister(){}};var vt=new Map;Module.pyproxy_alloc_map=vt;var wt,St;Module.enable_pyproxy_allocation_tracing=function(){wt=i(function(t){vt.set(t,Error().stack)},"trace_pyproxy_alloc"),St=i(function(t){vt.delete(t)},"trace_pyproxy_dealloc")};Module.disable_pyproxy_allocation_tracing=function(){wt=i(function(t){},"trace_pyproxy_alloc"),St=i(function(t){},"trace_pyproxy_dealloc")};Module.disable_pyproxy_allocation_tracing();var Zt=Symbol("pyproxy.attrs");function mn(t,e){_check_gil();let r=validSuspender.value;validSuspender.value=!1;try{return _pyproxy_getflags(t,e)}finally{validSuspender.value=r}}i(mn,"pyproxy_getflags");function we(t,{flags:e,cache:r,props:n,shared:o,gcRegister:a,jsonAdaptor:s}={}){a===void 0&&(a=!0);let l=e!==void 0?e:mn(t,!!s);l===-1&&_pythonexc2js();let c=l&8192,u=l&32768,d=Module.getPyProxyClass(l),p;l&256?(p=i(function(){},"target"),Object.setPrototypeOf(p,d.prototype),delete p.length,delete p.name,p.prototype=void 0):p=Object.create(d.prototype);let _=!!o;o||(r||(r={map:new Map,json_adaptor_map:new Map,refcnt:0}),r.refcnt++,o={ptr:t,cache:r,flags:l,promise:void 0,destroyed_msg:void 0,gcRegistered:!1},_Py_IncRef(t)),n=Object.assign({isBound:!1,captureThis:!1,boundArgs:[],roundtrip:!1},n);let m;u?m=xt:c?m=kn:m=H;let F=new Proxy(p,m);!_&&a&&er(o),_||wt(F);let N={shared:o,props:n};return p[Zt]=N,F}i(we,"pyproxy_new");Module.pyproxy_new=we;function er(t){let e=Object.assign({},t);t.gcRegistered=!0,Module.finalizationRegistry.register(t,e,t)}i(er,"gc_register_proxy");Module.gc_register_proxy=er;function Ze(t){return t[Zt]}i(Ze,"_getAttrsQuiet");Module.PyProxy_getAttrsQuiet=Ze;function E(t){let e=Ze(t);if(!e.shared.ptr)throw new Error(e.shared.destroyed_msg);return e}i(E,"_getAttrs");Module.PyProxy_getAttrs=E;function f(t){return E(t).shared.ptr}i(f,"_getPtr");function P(t){return Object.getPrototypeOf(t).$$flags}i(P,"_getFlags");function tr(t){return!!(P(t)&98304)}i(tr,"isJsonAdaptor");function qt(t,e,r){let{captureThis:n,boundArgs:o,boundThis:a,isBound:s}=E(t).props;return n?s?[a].concat(o,r):[e].concat(r):s?o.concat(r):r}i(qt,"_adjustArgs");var Yt=new Map;Module.getPyProxyClass=function(t){let e=[[1,je],[2,z],[4,L],[8,q],[16,He],[32,We],[2048,Ge],[512,ze],[1024,Je],[4096,Ke],[64,Ye],[128,Qe],[256,Pe],[8192,Ve],[16384,qe]],r=Yt.get(t);if(r)return r;let n={};for(let[l,c]of e)t&l&&Object.assign(n,Object.getOwnPropertyDescriptors(c.prototype));(t&8192||t&2)&&Object.assign(n,Object.getOwnPropertyDescriptors(Be.prototype)),n.constructor=Object.getOwnPropertyDescriptor(g.prototype,"constructor"),Object.assign(n,Object.getOwnPropertyDescriptors({$$flags:t}));let o=t&256?or:nr,a=Object.create(o,n);function s(){}return i(s,"NewPyProxyClass"),s.prototype=a,Yt.set(t,s),s};Module.PyProxy_getPtr=f;var Qt="This borrowed attribute proxy was automatically destroyed in the process of destroying the proxy it was borrowed from. Try using the 'copy' method.";function rr(t){if(t&&(t.refcnt--,!t.leaked&&t.refcnt===0)){for(let e of t.map.values())Module.pyproxy_destroy(e,Qt,!0);for(let e of t.json_adaptor_map.values())Module.pyproxy_destroy(e,Qt,!0)}}i(rr,"pyproxy_decref_cache");function _n(t,e){if(e=e||"Object has already been destroyed",API.debug_ffi){let r=t.type,n;try{n=t.toString()}catch(o){if(o.pyodide_fatal_error)throw o}e+=`\nThe object was of type "${r}" and `,n?e+=`had repr "${n}"`:e+="an error was raised when trying to generate its repr"}else e+="\nFor more information about the cause of this error, use `pyodide.setDebug(true)`";return e}i(_n,"generateDestroyedMessage");Module.pyproxy_destroy=function(t,e,r){let{shared:n,props:o}=Ze(t);if(!n.ptr||!r&&o.roundtrip)return;n.destroyed_msg=_n(t,e);let a=n.ptr;n.ptr=0,n.gcRegistered&&Module.finalizationRegistry.unregister(n),rr(n.cache);try{_check_gil();let s=validSuspender.value;validSuspender.value=!1,_Py_DecRef(a),St(t),validSuspender.value=s}catch(s){API.fatal_error(s)}};function Xe(t,e,r){let n=e.length,o=Object.keys(r),a=Object.values(r),s=o.length;e.push(...a);let l;try{_check_gil();let c=validSuspender.value;validSuspender.value=!1,l=__pyproxy_apply(t,e,n,o,s),validSuspender.value=c}catch(c){API.maybe_fatal_error(c);return}if(l===null&&_pythonexc2js(),l&&l.type==="coroutine"&&l._ensure_future){_check_gil();let c=validSuspender.value;validSuspender.value=!1;let u=__iscoroutinefunction(t);validSuspender.value=c,u&&l._ensure_future()}return l}i(Xe,"callPyObjectKwargs");async function Ue(t,e,r){if(!Module.jspiSupported)throw new Error("WebAssembly stack switching not supported in this JavaScript runtime");let n=e.length,o=Object.keys(r),a=Object.values(r),s=o.length;e.push(...a);let l=stackSave(),c=stackAlloc(4),u;try{_check_gil();let d=validSuspender.value;validSuspender.value=!1,u=await Module.promisingApply(t,e,n,o,s,c),validSuspender.value=d}catch(d){API.fatal_error(d)}if(u=u[0],u===null){_PyErr_SetRaisedException(HEAPU32[c/4>>>0]);try{_pythonexc2js()}finally{stackRestore(l)}}if(u&&u.type==="coroutine"&&u._ensure_future){_check_gil();let d=validSuspender.value;validSuspender.value=!1;let p=__iscoroutinefunction(t);validSuspender.value=d,p&&u._ensure_future()}return u}i(Ue,"callPyObjectKwargsPromising");Module.callPyObjectMaybePromising=async function(t,e){return Module.jspiSupported?await Ue(t,e,{}):Xe(t,e,{})};Module.callPyObject=function(t,e){return Xe(t,e,{})};var g=class{static[Symbol.hasInstance](e){return[g,ar].some(r=>Function.prototype[Symbol.hasInstance].call(r,e))}constructor(){throw new TypeError("PyProxy is not a constructor")}get[Symbol.toStringTag](){return"PyProxy"}get type(){let e=f(this);return __pyproxy_type(e)}toString(){let e=f(this),r;try{_check_gil();let n=validSuspender.value;validSuspender.value=!1,r=__pyproxy_repr(e),validSuspender.value=n}catch(n){API.fatal_error(n)}return r===null&&_pythonexc2js(),r}destroy(e={}){e=Object.assign({message:"",destroyRoundtrip:!0},e);let{message:r,destroyRoundtrip:n}=e;Module.pyproxy_destroy(this,r,n)}copy(){let e=E(this);return we(e.shared.ptr,{flags:P(this),cache:e.shared.cache,props:e.props})}toJs({depth:e=-1,pyproxies:r=void 0,create_pyproxies:n=!0,dict_converter:o=void 0,default_converter:a=void 0,eager_converter:s=void 0}={}){let l=f(this),c,u;n?r?u=r:u=[]:u=null;try{_check_gil();let d=validSuspender.value;validSuspender.value=!1,c=_python2js_custom(l,e,u,o??null,a??null,s??null),validSuspender.value=d}catch(d){API.fatal_error(d)}return c===null&&_pythonexc2js(),c}};i(g,"PyProxy");var nr=g.prototype;Tests.Function=Function;var or=Object.create(Function.prototype,Object.getOwnPropertyDescriptors(nr));function ar(){}i(ar,"PyProxyFunction");ar.prototype=or;var ae=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&1)}};i(ae,"PyProxyWithLength");var je=class{get length(){let e=f(this),r;try{_check_gil();let n=validSuspender.value;validSuspender.value=!1,r=_PyObject_Size(e),validSuspender.value=n}catch(n){API.fatal_error(n)}return r===-1&&_pythonexc2js(),r}};i(je,"PyLengthMethods");var ie=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&2)}};i(ie,"PyProxyWithGet");var Be=class{asJsJson(){let{shared:e,props:r}=E(this),n=P(this);return n&8192?n|=65536:n|=32768,we(e.ptr,{shared:e,flags:n,props:r})}};i(Be,"PyAsJsonAdaptorMethods");var z=class{get(e){let{shared:r}=E(this),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_getitem(r.ptr,e,r.cache.json_adaptor_map,tr(this)),validSuspender.value=o}catch(o){API.fatal_error(o)}if(n===null)if(_PyErr_Occurred())_pythonexc2js();else return;return n}asJsJson(){throw new Error("Should not happen")}};i(z,"PyGetItemMethods");var se=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&4)}};i(se,"PyProxyWithSet");var L=class{set(e,r){let n=f(this),o;try{_check_gil();let a=validSuspender.value;validSuspender.value=!1,o=__pyproxy_setitem(n,e,r),validSuspender.value=a}catch(a){API.fatal_error(a)}o===-1&&_pythonexc2js()}delete(e){let r=f(this),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_delitem(r,e),validSuspender.value=o}catch(o){API.fatal_error(o)}n===-1&&_pythonexc2js()}};i(L,"PySetItemMethods");var le=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&8)}};i(le,"PyProxyWithHas");var q=class{has(e){let r=f(this),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_contains(r,e),validSuspender.value=o}catch(o){API.fatal_error(o)}return n===-1&&_pythonexc2js(),n===1}};i(q,"PyContainsMethods");function*hn(t,e,r,n){let o=[];try{for(;;){_check_gil();let a=validSuspender.value;validSuspender.value=!1;let s=__pyproxy_iter_next(t,r,n);if(validSuspender.value=a,s===null)break;yield s,!n&&API.isPyProxy(s)&&o.push(s)}}catch(a){API.fatal_error(a)}finally{Module.finalizationRegistry.unregister(e),_Py_DecRef(t)}try{o.forEach(a=>Module.pyproxy_destroy(a,"This borrowed proxy was automatically destroyed when an iterator was exhausted."))}catch{}_PyErr_Occurred()&&_pythonexc2js()}i(hn,"iter_helper");var ce=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&48)}};i(ce,"PyIterable");var He=class{[Symbol.iterator](){let{shared:e}=E(this),r={},n;try{_check_gil();let a=validSuspender.value;validSuspender.value=!1,n=_PyObject_GetIter(e.ptr),validSuspender.value=a}catch(a){API.fatal_error(a)}n===0&&_pythonexc2js();let o=hn(n,r,e.cache.json_adaptor_map,tr(this));return Module.finalizationRegistry.register(o,[n,void 0],r),o}};i(He,"PyIterableMethods");async function*bn(t,e){try{for(;;){let r;try{_check_gil();let n=validSuspender.value;if(validSuspender.value=!1,r=__pyproxy_aiter_next(t),validSuspender.value=n,r===null)break}catch(n){API.fatal_error(n)}try{yield await r}catch(n){if(n&&typeof n=="object"&&n.type==="StopAsyncIteration")return;throw n}finally{r.destroy()}}}finally{Module.finalizationRegistry.unregister(e),_Py_DecRef(t)}_PyErr_Occurred()&&_pythonexc2js()}i(bn,"aiter_helper");var ue=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&1536)}};i(ue,"PyAsyncIterable");var ze=class{[Symbol.asyncIterator](){let e=f(this),r={},n;try{_check_gil();let a=validSuspender.value;validSuspender.value=!1,n=_PyObject_GetAIter(e),validSuspender.value=a}catch(a){API.fatal_error(a)}n===0&&_pythonexc2js();let o=bn(n,r);return Module.finalizationRegistry.register(o,[n,void 0],r),o}};i(ze,"PyAsyncIterableMethods");var de=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&32)}};i(de,"PyIterator");var We=class{[Symbol.iterator](){return this}next(e=void 0){let r,n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_Send(f(this),e),validSuspender.value=o}catch(o){API.fatal_error(o)}return r===null&&_pythonexc2js(),r}};i(We,"PyIteratorMethods");var ye=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&2048)}};i(ye,"PyGenerator");var Ge=class{throw(e){let r;try{_check_gil();let n=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_throw(f(this),e),validSuspender.value=n}catch(n){API.fatal_error(n)}return r===null&&_pythonexc2js(),r}return(e){let r;try{_check_gil();let n=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_return(f(this),e),validSuspender.value=n}catch(n){API.fatal_error(n)}return r===null&&_pythonexc2js(),r}};i(Ge,"PyGeneratorMethods");var pe=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&1024)}};i(pe,"PyAsyncIterator");var Je=class{[Symbol.asyncIterator](){return this}async next(e=void 0){let r;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_asend(f(this),e),validSuspender.value=o}catch(o){API.fatal_error(o)}r===null&&_pythonexc2js();let n;try{n=await r}catch(o){if(o&&typeof o=="object"&&o.type==="StopAsyncIteration")return{done:!0,value:n};throw o}finally{r.destroy()}return{done:!1,value:n}}};i(Je,"PyAsyncIteratorMethods");var fe=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&4096)}};i(fe,"PyAsyncGenerator");var Ke=class{async throw(e){let r;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_athrow(f(this),e),validSuspender.value=o}catch(o){API.fatal_error(o)}r===null&&_pythonexc2js();let n;try{n=await r}catch(o){if(o&&typeof o=="object"){if(o.type==="StopAsyncIteration")return{done:!0,value:n};if(o.type==="GeneratorExit")return{done:!0,value:n}}throw o}finally{r.destroy()}return{done:!1,value:n}}async return(e){let r;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_areturn(f(this)),validSuspender.value=o}catch(o){API.fatal_error(o)}r===null&&_pythonexc2js();let n;try{n=await r}catch(o){if(o&&typeof o=="object"){if(o.type==="StopAsyncIteration")return{done:!0,value:n};if(o.type==="GeneratorExit")return{done:!0,value:e}}throw o}finally{r.destroy()}return{done:!1,value:n}}};i(Ke,"PyAsyncGeneratorMethods");var ge=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&8192)}};i(ge,"PySequence");function Pn(t,e){let r=t.toString(),n=e.toString();return r===n?0:r{this.insert(n,r)}),this.length}copyWithin(...e){return Array.prototype.copyWithin.apply(this,e),this}fill(...e){return Array.prototype.fill.apply(this,e),this}};i(qe,"PyMutableSequenceMethods");function vn(t,e){let r=f(t),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_hasattr(r,e),validSuspender.value=o}catch(o){API.fatal_error(o)}return n===-1&&_pythonexc2js(),n!==0}i(vn,"python_hasattr");function xn(t,e){let{shared:r}=E(t),n=r.cache.map,o;try{_check_gil();let a=validSuspender.value;validSuspender.value=!1,o=__pyproxy_getattr(r.ptr,e,n),validSuspender.value=a}catch(a){API.fatal_error(a)}if(o===null){_PyErr_Occurred()&&_pythonexc2js();return}return o}i(xn,"python_getattr");function wn(t,e,r){let n=f(t),o;try{_check_gil();let a=validSuspender.value;validSuspender.value=!1,o=__pyproxy_setattr(n,e,r),validSuspender.value=a}catch(a){API.fatal_error(a)}o===-1&&_pythonexc2js()}i(wn,"python_setattr");function Sn(t,e){let r=f(t),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_delattr(r,e),validSuspender.value=o}catch(o){API.fatal_error(o)}n===-1&&_pythonexc2js()}i(Sn,"python_delattr");function An(t,e,r,n){let o=f(t),a;try{_check_gil();let s=validSuspender.value;validSuspender.value=!1,a=__pyproxy_slice_assign(o,e,r,n),validSuspender.value=s}catch(s){API.fatal_error(s)}return a===null&&_pythonexc2js(),a}i(An,"python_slice_assign");function Xt(t,e){let r=f(t),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_pop(r,e),validSuspender.value=o}catch(o){API.fatal_error(o)}return n===null&&_pythonexc2js(),n}i(Xt,"python_pop");var In=new Set(["name","length","caller","arguments"]);function Ce(t,e,r){return t instanceof Function?e in t&&!(In.has(e)||r&&e==="prototype"):e in t}i(Ce,"filteredHasKey");var H={isExtensible(){return!0},has(t,e){return Ce(t,e,!1)?!0:typeof e=="symbol"?!1:(e.startsWith("$")&&(e=e.slice(1)),vn(t,e))},get(t,e){return typeof e=="symbol"||Ce(t,e,!0)?Reflect.get(t,e):(e.startsWith("$")&&(e=e.slice(1)),xn(t,e))},set(t,e,r){let n=Object.getOwnPropertyDescriptor(t,e);return n&&!n.writable&&!n.set?!1:typeof e=="symbol"||Ce(t,e,!0)?Reflect.set(t,e,r):(e.startsWith("$")&&(e=e.slice(1)),wn(t,e,r),!0)},deleteProperty(t,e){let r=Object.getOwnPropertyDescriptor(t,e);return r&&!r.configurable?!1:typeof e=="symbol"||Ce(t,e,!0)?Reflect.deleteProperty(t,e):(e.startsWith("$")&&(e=e.slice(1)),Sn(t,e),!0)},ownKeys(t){let e=f(t),r;try{_check_gil();let n=validSuspender.value;validSuspender.value=!1,r=__pyproxy_ownKeys(e),validSuspender.value=n}catch(n){API.fatal_error(n)}return r===null&&_pythonexc2js(),r.push(...Reflect.ownKeys(t)),r},apply(t,e,r){return t.apply(e,r)}};function _e(t){return t&&typeof t=="object"&&t.constructor&&t.constructor.name==="PythonError"}i(_e,"isPythonError");var kn={isExtensible(){return!0},has(t,e){return typeof e=="string"&&/^[0-9]+$/.test(e)?Number(e)n.toString())),e.push("length"),e}},En=new Set(["copy","constructor","$$flags","toString","destroy"]),xt={isExtensible(){return!0},has(t,e){return!!(q.prototype.has.call(t,e)||(typeof e=="string"&&/^[0-9]+$/.test(e)&&(e=Number(e)),q.prototype.has.call(t,e)))},get(t,e){let r;return En.has(e)||typeof e=="symbol"?Reflect.get(...arguments):(typeof e=="string"&&(r=z.prototype.get.call(t,e)),r||(typeof e=="string"&&/^[0-9]+$/.test(e)&&(e=Number(e),r=z.prototype.get.call(t,e)),r)?r:Reflect.get(...arguments))},set(t,e,r){if(typeof e=="string"){/^[0-9]+$/.test(e)&&(e=Number(e));try{return L.prototype.set.call(t,e,r),!0}catch(n){if(_e(n))return!1;throw n}}return!1},deleteProperty(t,e){if(typeof e=="string"&&/^[0-9]+$/.test(e))try{return L.prototype.delete.call(t,Number(e)),!0}catch(r){if(_e(r))return!1;throw r}return!1},getOwnPropertyDescriptor(t,e){return xt.has(t,e)?{configurable:!0,enumerable:!0,value:xt.get(t,e),writable:!0}:void 0},ownKeys(t){let e;e=H.get(t,"keys")();let r=Array.from(e);return e.destroy(),r}},he=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&64)}};i(he,"PyAwaitable");var Ye=class{_ensure_future(){let{shared:e}=Ze(this);if(e.promise)return e.promise;let r=e.ptr;r||E(this);let n,o,a=new Promise((l,c)=>{n=l,o=c}),s;try{_check_gil();let l=validSuspender.value;validSuspender.value=!1,s=__pyproxy_ensure_future(r,n,o),validSuspender.value=l}catch(l){API.fatal_error(l)}return s===-1&&_pythonexc2js(),e.promise=a,this.destroy(),a}then(e,r){return this._ensure_future().then(e,r)}catch(e){return this._ensure_future().catch(e)}finally(e){return this._ensure_future().finally(e)}};i(Ye,"PyAwaitableMethods");var be=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&256)}};i(be,"PyCallable");var Pe=class{apply(e,r){return r=function(...n){return n}.apply(void 0,r),r=qt(this,e,r),Module.callPyObject(f(this),r)}call(e,...r){return r=qt(this,e,r),Module.callPyObject(f(this),r)}callWithOptions({relaxed:e,kwargs:r,promising:n},...o){let a={};if(r){if(o.length===0)throw new TypeError("callWithOptions with 'kwargs: true' requires at least one argument (the key word argument object)");if(a=o.pop(),a.constructor!==void 0&&a.constructor.name!=="Object")throw new TypeError("kwargs argument is not an object")}let s=e?API.pyodide_code.relaxed_call:this;return e&&o.unshift(this),(n?Ue:Xe)(f(s),o,a)}callKwargs(...e){if(e.length===0)throw new TypeError("callKwargs requires at least one argument (the key word argument object)");let r=e.pop();if(r.constructor!==void 0&&r.constructor.name!=="Object")throw new TypeError("kwargs argument is not an object");return Xe(f(this),e,r)}callRelaxed(...e){return API.pyodide_code.relaxed_call(this,...e)}callKwargsRelaxed(...e){return API.pyodide_code.relaxed_call.callKwargs(this,...e)}callPromising(...e){return Ue(f(this),e,{})}callPromisingKwargs(...e){if(e.length===0)throw new TypeError("callKwargs requires at least one argument (the key word argument object)");let r=e.pop();if(r.constructor!==void 0&&r.constructor.name!=="Object")throw new TypeError("kwargs argument is not an object");return Ue(f(this),e,r)}bind(e,...r){let{shared:n,props:o}=E(this),{boundArgs:a,boundThis:s,isBound:l}=o,c=e;l&&(c=s);let u=a.concat(r);return o=Object.assign({},o,{boundArgs:u,isBound:!0,boundThis:c}),we(n.ptr,{shared:n,flags:P(this),props:o})}captureThis(){let{props:e,shared:r}=E(this);return e=Object.assign({},e,{captureThis:!0}),we(r.ptr,{shared:r,flags:P(this),props:e})}};i(Pe,"PyCallableMethods");Pe.prototype.prototype=Function.prototype;var Fn=new Map([["i8",Int8Array],["u8",Uint8Array],["u8clamped",Uint8ClampedArray],["i16",Int16Array],["u16",Uint16Array],["i32",Int32Array],["u32",Uint32Array],["i32",Int32Array],["u32",Uint32Array],["i64",globalThis.BigInt64Array],["u64",globalThis.BigUint64Array],["f32",Float32Array],["f64",Float64Array],["dataview",DataView]]),ve=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&128)}};i(ve,"PyBuffer");var Qe=class{getBuffer(e){let r;if(e&&(r=Fn.get(e),r===void 0))throw new Error(`Unknown type ${e}`);let n=f(this),o;try{_check_gil();let O=validSuspender.value;validSuspender.value=!1,o=__pyproxy_get_buffer(n),validSuspender.value=O}catch(O){API.fatal_error(O)}o===null&&_pythonexc2js();let{start_ptr:a,smallest_ptr:s,largest_ptr:l,readonly:c,format:u,itemsize:d,shape:p,strides:_,view:m,c_contiguous:F,f_contiguous:N}=o,jt=!1;try{let O=!1;r===void 0&&([r,O]=Module.processBufferFormatString(u," In this case, you can pass an explicit type argument."));let $=parseInt(r.name.replace(/[^0-9]/g,""))/8||1;if(O&&$>1)throw new Error("JavaScript has no native support for big endian buffers. In this case, you can pass an explicit type argument. For instance, `getBuffer('dataview')` will return a `DataView`which has native support for reading big endian data. Alternatively, toJs will automatically convert the buffer to little endian.");let Te=l-s;if(Te!==0&&(a%$!==0||s%$!==0||l%$!==0))throw new Error(`Buffer does not have valid alignment for a ${r.name}`);let Gr=Te/$,Jr=(a-s)/$,gt;Te===0?gt=new r:gt=new r(HEAPU32.buffer,s,Gr);for(let Kr of _.keys())_[Kr]/=$;return jt=!0,Object.create(Y.prototype,Object.getOwnPropertyDescriptors({offset:Jr,readonly:c,format:u,itemsize:d,ndim:p.length,nbytes:Te,shape:p,strides:_,data:gt,c_contiguous:F,f_contiguous:N,_view_ptr:m,_released:!1}))}finally{if(!jt)try{_check_gil();let O=validSuspender.value;validSuspender.value=!1,_PyBuffer_Release(m),_PyMem_Free(m),validSuspender.value=O}catch(O){API.fatal_error(O)}}}};i(Qe,"PyBufferMethods");var xe=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&e.type==="dict"}};i(xe,"PyDict");var Y=class{constructor(){throw new TypeError("PyBufferView is not a constructor")}release(){if(!this._released){try{_check_gil();let e=validSuspender.value;validSuspender.value=!1,_PyBuffer_Release(this._view_ptr),_PyMem_Free(this._view_ptr),validSuspender.value=e}catch(e){API.fatal_error(e)}this._released=!0,this.data=null}}};i(Y,"PyBufferView");var ir={PyProxy:g,PyProxyWithLength:ae,PyProxyWithGet:ie,PyProxyWithSet:se,PyProxyWithHas:le,PyDict:xe,PyIterable:ce,PyAsyncIterable:ue,PyIterator:de,PyAsyncIterator:pe,PyGenerator:ye,PyAsyncGenerator:fe,PyAwaitable:he,PyCallable:be,PyBuffer:ve,PyBufferView:Y,PythonError:R,PySequence:ge,PyMutableSequence:me};function sr(t){t.id!=="canvas"&&console.warn("If you are using canvas element for SDL library, it should have id 'canvas' to work properly."),Module.canvas=t}i(sr,"setCanvas2D");function lr(){return Module.canvas}i(lr,"getCanvas2D");function On(t){sr(t)}i(On,"setCanvas3D");function Dn(){return lr()}i(Dn,"getCanvas3D");var cr={setCanvas2D:sr,getCanvas2D:lr,setCanvas3D:On,getCanvas3D:Dn};var h=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string"&&!process.browser,At=h&&typeof module<"u"&&typeof module.exports<"u"&&typeof x<"u"&&typeof __dirname<"u",ur=h&&!At,Mn=typeof globalThis.Bun<"u",dr=typeof Deno<"u",It=!h&&!dr,Q=It&&typeof window=="object"&&typeof document=="object"&&typeof document.createElement=="function"&&"sessionStorage"in window&&typeof importScripts!="function",Se=It&&typeof importScripts=="function"&&typeof self=="object",kt=typeof navigator=="object"&&typeof navigator.userAgent=="string"&&navigator.userAgent.indexOf("Chrome")==-1&&navigator.userAgent.indexOf("Safari")>-1;function yr(){return{IN_NODE:h,IN_NODE_COMMONJS:At,IN_NODE_ESM:ur,IN_BUN:Mn,IN_DENO:dr,IN_BROWSER:It,IN_BROWSER_MAIN_THREAD:Q,IN_BROWSER_WEB_WORKER:Se,IN_SAFARI:kt}}i(yr,"detectEnvironment");function Et(){let t=i(()=>{},"_resolve"),e=i(()=>{},"_reject"),r=new Promise((n,o)=>{t=n,e=o});return r.resolve=t,r.reject=e,r}i(Et,"createResolvable");function et(){let t=Promise.resolve();async function e(){let r=t,n;return t=new Promise(o=>n=o),await r,n}return i(e,"acquireLock"),e}i(et,"createLock");var Nn=/[-_.]+/g;function pr(t){return t.replace(Nn,"-").toLowerCase()}i(pr,"canonicalizePackageName");var Tn=/^.*?([^\/]*)\.whl$/;function fr(t){let e=Tn.exec(t);if(e){let r=e[1].toLowerCase().split("-");return{name:r[0],version:r[1],fileName:r.join("-")+".whl"}}}i(fr,"uriToPackageData");function gr(t){return btoa(t.match(/\w{2}/g).map(function(e){return String.fromCharCode(parseInt(e,16))}).join(""))}i(gr,"base16ToBase64");var mr,Ot,_r,tt,X;async function hr(){if(!h||(mr=(await import("node:url")).default,tt=await import("node:fs"),X=await import("node:fs/promises"),_r=(await import("node:vm")).default,Ot=await import("node:path"),br=Ot.sep,typeof x<"u"))return;let t=tt,e=await import("node:crypto"),r=await import("ws"),n=await import("node:child_process"),o={fs:t,crypto:e,ws:r,child_process:n};globalThis.require=function(a){return o[a]}}i(hr,"initNodeModules");function Rn(t,e){return Ot.resolve(e||".",t)}i(Rn,"node_resolvePath");function Ln(t,e){return e===void 0&&(e=location),new URL(t,e).toString()}i(Ln,"browser_resolvePath");var rt;h?rt=Rn:rt=Ln;var br;h||(br="/");function $n(t,e){return t.startsWith("file://")&&(t=t.slice(7)),t.includes("://")?{response:fetch(t)}:{binary:X.readFile(t).then(r=>new Uint8Array(r.buffer,r.byteOffset,r.byteLength))}}i($n,"node_getBinaryResponse");function Cn(t,e){let r=new URL(t,location);return{response:fetch(r,e?{integrity:e}:{})}}i(Cn,"browser_getBinaryResponse");var Dt;h?Dt=$n:Dt=Cn;async function Ae(t,e){let{response:r,binary:n}=Dt(t,e);if(n)return n;let o=await r;if(!o.ok)throw new Error(`Failed to load '${t}': request failed.`);return new Uint8Array(await o.arrayBuffer())}i(Ae,"loadBinaryFile");var Ft;if(Q)Ft=i(async t=>await import(t),"loadScript");else if(Se)Ft=i(async t=>{try{globalThis.importScripts(t)}catch(e){if(e instanceof TypeError)await import(t);else throw e}},"loadScript");else if(h)Ft=Un;else throw new Error("Cannot determine runtime environment");async function Un(t){t.startsWith("file://")&&(t=t.slice(7)),t.includes("://")?_r.runInThisContext(await(await fetch(t)).text()):await import(mr.pathToFileURL(t).href)}i(Un,"nodeLoadScript");async function Pr(t){if(h)try{await X.stat(t)}catch{await X.mkdir(t,{recursive:!0})}}i(Pr,"ensureDirNode");var ee,b,Z=class{constructor(e,r){D(this,ee,void 0);D(this,b,void 0);this._lock=et();M(this,ee,e),M(this,b,r)}*getSubDirs(e){let r=y(this,b).FS.readdir(e);for(let n of r){if(n==="."||n==="..")continue;let o=y(this,b).PATH.join2(e,n),a=y(this,b).FS.lookupPath(o);if(a.node===null)continue;let s=a.node.mode;y(this,b).FS.isDir(s)&&(yield o,yield*this.getSubDirs(o))}}createDynlibFS(e,r){let n=e.substring(0,e.lastIndexOf("/")),o=r||[];o=o.concat(y(this,ee).defaultLdLibraryPath,[n]);let a=i(c=>{if(y(this,b).PATH.isAbs(c))return c;for(let u of o){let d=y(this,b).PATH.join2(u,c);if(y(this,b).FS.findObject(d)!==null)return d}for(let u of this.getSubDirs(n)){let d=y(this,b).PATH.join2(u,c);if(y(this,b).FS.findObject(d)!==null)return d}return c},"resolvePath");return{findObject:(c,u)=>y(this,b).FS.findObject(a(c),u),readFile:i(c=>y(this,b).FS.readFile(a(c)),"readFile")}}async loadDynlib(e,r,n){let o=await this._lock(),a=this.createDynlibFS(e,n),s=r?null:{};try{if(await y(this,b).loadDynamicLibrary(e,{loadAsync:!0,nodelete:!0,allowUndefined:!0,global:r,fs:a},s),y(this,b).PATH.isAbs(e)){let l=y(this,b).PATH.basename(e);y(this,b).LDSO.loadedLibsByName[l]||(y(this,b).LDSO.loadedLibsByName[l]=y(this,b).LDSO.loadedLibsByName[e])}}catch(l){if(l&&l.message&&l.message.includes("need to see wasm magic number")){console.warn(`Failed to load dynlib ${e}. We probably just tried to load a linux .so file or something.`);return}throw l}finally{o()}}async loadDynlibsFromPackage(e,r){let n=`${y(this,ee).sitepackages}/${e.file_name.split("-")[0]}.libs`;for(let o of r)await this.loadDynlib(o,!1,[n])}};i(Z,"DynlibLoader"),ee=new WeakMap,b=new WeakMap;if(typeof API<"u"&&typeof Module<"u"){let t=new Z(API,Module);API.loadDynlib=t.loadDynlib.bind(t),API.loadDynlibsFromPackage=t.loadDynlibsFromPackage.bind(t)}var Ie,ke,te=class{constructor(e,r){D(this,Ie,void 0);D(this,ke,void 0);M(this,Ie,e),M(this,ke,new Z(e,r))}async install(e,r,n,o,a){let s=y(this,Ie).package_loader.unpack_buffer.callKwargs({buffer:e,filename:r,extract_dir:n,installer:o,source:a,calculate_dynlibs:!0});await y(this,ke).loadDynlibsFromPackage({file_name:r},s)}};i(te,"Installer"),Ie=new WeakMap,ke=new WeakMap;var vr;if(typeof API<"u"&&typeof Module<"u"){let t=new te(API,Module);vr=t.install.bind(t),API.install=vr}async function jn(t){await hr();let e=await t;if(!e.packages)throw new Error("Loaded pyodide lock file does not contain the expected key 'packages'.");if(e.info.version!==API.version)throw new Error(`Lock file version doesn't match Pyodide version.\n lockfile version: ${e.info.version}\n pyodide version: ${API.version}`);API.lockfile_info=e.info,API.lockfile_packages=e.packages,API.lockfile_unvendored_stdlibs_and_test=[],API.repodata_info=e.info,API.repodata_packages=e.packages,API._import_name_to_package_name=new Map;for(let o of Object.keys(API.lockfile_packages)){let a=API.lockfile_packages[o];for(let s of a.imports)API._import_name_to_package_name.set(s,o);a.package_type==="cpython_module"&&API.lockfile_unvendored_stdlibs_and_test.push(o)}API.lockfile_unvendored_stdlibs=API.lockfile_unvendored_stdlibs_and_test.filter(o=>o!=="test");let r=API.config.packages;API.config.fullStdLib&&(r=[...r,...API.lockfile_unvendored_stdlibs]),await Oe(r,{messageCallback(){}}),await API.bootstrapFinalizedPromise,API._pyodide._importhook.register_module_not_found_hook(API._import_name_to_package_name,API.lockfile_unvendored_stdlibs_and_test),API.package_loader.init_loaded_packages()}i(jn,"initializePackageIndex");var Bn="default channel",Hn="pyodide.loadPackage",w,S,Fe,nt=class{constructor(e,r){D(this,w,void 0);D(this,S,void 0);D(this,Fe,void 0);this.cdnURL="";this.loadedPackages={};this._lock=et();this.defaultChannel=Bn;M(this,w,e),M(this,S,r),M(this,Fe,new te(e,r)),this.stdout=n=>{let o=y(this,S).stackSave();try{let a=y(this,S).stringToUTF8OnStack(n);y(this,S)._print_stdout(a)}finally{y(this,S).stackRestore(o)}},this.stderr=n=>{let o=y(this,S).stackSave();try{let a=y(this,S).stringToUTF8OnStack(n);y(this,S)._print_stderr(a)}finally{y(this,S).stackRestore(o)}}}async loadPackage(e,r={checkIntegrity:!0}){let n=new Set,{messageCallback:o,errorCallback:a}=r,s=Wn(e),l=this.recursiveDependencies(s,a);for(let[p,{name:_,normalizedName:m,channel:F}]of l){let N=this.getLoadedPackageChannel(_);N&&(l.delete(m),N===F||F===this.defaultChannel?this.logStdout(`${_} already loaded from ${N}`,o):this.logStderr(`URI mismatch, attempting to load package ${_} from ${F} while it is already loaded from ${N}. To override a dependency, load the custom package first.`,a))}if(l.size===0)return this.logStdout("No new packages to load",o),[];let c=Array.from(l.values(),({name:p})=>p).sort().join(", "),u=new Map,d=await this._lock();try{this.logStdout(`Loading ${c}`,o);for(let[p,_]of l){if(this.getLoadedPackageChannel(_.name)){l.delete(_.normalizedName);continue}_.installPromise=this.downloadAndInstall(_,l,n,u,r.checkIntegrity)}if(await Promise.all(Array.from(l.values()).map(({installPromise:p})=>p)),y(this,S).reportUndefinedSymbols(),n.size>0){let p=Array.from(n,_=>_.name).sort().join(", ");this.logStdout(`Loaded ${p}`,o)}if(u.size>0){let p=Array.from(u.keys()).sort().join(", ");this.logStdout(`Failed to load ${p}`,o);for(let[_,m]of u)this.logStderr(`The following error occurred while loading ${_}:`,a),this.logStderr(m.message,a)}return y(this,w).importlib.invalidate_caches(),Array.from(n,zn)}finally{d()}}addPackageToLoad(e,r){let n=pr(e);if(r.has(n))return;let o=y(this,w).lockfile_packages[n];if(!o)throw new Error(`No known package with name '${e}'`);if(r.set(n,{name:o.name,normalizedName:n,channel:this.defaultChannel,depends:o.depends,installPromise:void 0,done:Et(),packageData:o}),!this.getLoadedPackageChannel(o.name))for(let a of o.depends)this.addPackageToLoad(a,r)}recursiveDependencies(e,r){let n=new Map;for(let o of e){let a=fr(o);if(a===void 0){this.addPackageToLoad(o,n);continue}let{name:s,version:l,fileName:c}=a,u=o;if(n.has(s)&&n.get(s).channel!==u){this.logStderr(`Loading same package ${s} from ${u} and ${n.get(s).channel}`,r);continue}n.set(s,{name:s,normalizedName:s,channel:u,depends:[],installPromise:void 0,done:Et(),packageData:{name:s,version:l,file_name:c,install_dir:"site",sha256:"",package_type:"package",imports:[],depends:[]}})}return n}async downloadPackage(e,r=!0){let n=h?y(this,w).config.packageCacheDir:y(this,w).config.indexURL;await Pr(n);let o,a,s;if(e.channel===this.defaultChannel){if(!(e.normalizedName in y(this,w).lockfile_packages))throw new Error(`Internal error: no entry for package named ${name}`);let c=y(this,w).lockfile_packages[e.normalizedName];o=c.file_name,a=rt(o,n),s="sha256-"+gr(c.sha256)}else a=e.channel,s=void 0;r||(s=void 0);try{return await Ae(a,s)}catch(c){if(!h||e.channel!==this.defaultChannel)throw c}this.logStdout(`Didn't find package ${o} locally, attempting to load from ${this.cdnURL}`);let l=await Ae(this.cdnURL+o);return this.logStdout(`Package ${o} loaded from ${this.cdnURL}, caching the wheel in node_modules for future use.`),await X.writeFile(a,l),l}async installPackage(e,r){let n=y(this,w).lockfile_packages[e.normalizedName];n||(n=e.packageData);let o=n.file_name,a=y(this,w).package_loader.get_install_dir(n.install_dir);await y(this,Fe).install(r,o,a,Hn,e.channel===this.defaultChannel?"pyodide":e.channel)}async downloadAndInstall(e,r,n,o,a=!0){if(Ee[e.name]===void 0)try{let s=await this.downloadPackage(e,a),l=e.depends.map(c=>r.has(c)?r.get(c).done:Promise.resolve());await y(this,w).bootstrapFinalizedPromise,await Promise.all(l),await this.installPackage(e,s),n.add(e.packageData),Ee[e.name]=e.channel}catch(s){o.set(e.name,s)}finally{e.done.resolve()}}setCdnUrl(e){this.cdnURL=e}getLoadedPackageChannel(e){let r=this.loadedPackages[e];return r===void 0?null:r}logStdout(e,r){r?r(e):this.stdout(e)}logStderr(e,r){r?r(e):this.stderr(e)}};i(nt,"PackageManager"),w=new WeakMap,S=new WeakMap,Fe=new WeakMap;function zn({name:t,version:e,file_name:r,package_type:n}){return{name:t,version:e,fileName:r,packageType:n}}i(zn,"filterPackageData");function Wn(t){return typeof t.toJs=="function"&&(t=t.toJs()),Array.isArray(t)||(t=[t]),t}i(Wn,"toStringArray");var Oe,Ee;if(typeof API<"u"&&typeof Module<"u"){let t=new nt(API,Module);Oe=t.loadPackage.bind(t),Ee=t.loadedPackages,API.recursiveDependencies=t.recursiveDependencies.bind(t),API.setCdnUrl=t.setCdnUrl.bind(t),API.lockFilePromise&&(API.packageIndexReady=jn(API.lockFilePromise))}var xr="0.27.7";var Tt=h?x("node:fs"):void 0,Ir=h?x("node:tty"):void 0;function kr(t){try{Tt.fsyncSync(t)}catch(e){if(e?.code==="EINVAL"||e?.code==="ENOTSUP"&&(t===1||t===2))return;throw e}}i(kr,"nodeFsync");var Er=!1,ct={},I={};function Nt(t){ct[I.stdin]=t}i(Nt,"_setStdinOps");function Gn(t){ct[I.stdout]=t}i(Gn,"_setStdoutOps");function Jn(t){ct[I.stderr]=t}i(Jn,"_setStderrOps");function Kn(t){return t&&typeof t=="object"&&"errno"in t}i(Kn,"isErrnoError");var Vn=new Int32Array(new WebAssembly.Memory({shared:!0,initial:1,maximum:1}).buffer);function qn(t){try{return Atomics.wait(Vn,0,0,t),!0}catch{return!1}}i(qn,"syncSleep");function Yn(t){for(;;)try{return t()}catch(e){if(e&&e.code==="EAGAIN"&&qn(100))continue;throw e}}i(Yn,"handleEAGAIN");function wr(t,e,r){let n;try{n=Yn(e)}catch(o){throw o&&o.code&&Module.ERRNO_CODES[o.code]?new FS.ErrnoError(Module.ERRNO_CODES[o.code]):Kn(o)?o:(console.error("Error thrown in read:"),console.error(o),new FS.ErrnoError(29))}if(n===void 0)throw console.warn(`${r} returned undefined; a correct implementation must return a number`),new FS.ErrnoError(29);return n!==0&&(t.node.timestamp=Date.now()),n}i(wr,"readWriteHelper");var Sr=i((t,e,r)=>API.typedArrayAsUint8Array(t).subarray(e,e+r),"prepareBuffer"),Mt={open:function(t){let e=ct[t.node.rdev];if(!e)throw new FS.ErrnoError(43);t.devops=e,t.tty=t.devops.isatty?{ops:{}}:void 0,t.seekable=!1},close:function(t){t.stream_ops.fsync(t)},fsync:function(t){let e=t.devops;e.fsync&&e.fsync()},read:function(t,e,r,n,o){return e=Sr(e,r,n),wr(t,()=>t.devops.read(e),"read")},write:function(t,e,r,n,o){return e=Sr(e,r,n),wr(t,()=>t.devops.write(e),"write")}};function ut(){Er&&(FS.closeStream(0),FS.closeStream(1),FS.closeStream(2),FS.open("/dev/stdin",0),FS.open("/dev/stdout",1),FS.open("/dev/stderr",1))}i(ut,"refreshStreams");API.initializeStreams=function(t,e,r){let n=FS.createDevice.major++;I.stdin=FS.makedev(n,0),I.stdout=FS.makedev(n,1),I.stderr=FS.makedev(n,2),FS.registerDevice(I.stdin,Mt),FS.registerDevice(I.stdout,Mt),FS.registerDevice(I.stderr,Mt),FS.unlink("/dev/stdin"),FS.unlink("/dev/stdout"),FS.unlink("/dev/stderr"),FS.mkdev("/dev/stdin",I.stdin),FS.mkdev("/dev/stdout",I.stdout),FS.mkdev("/dev/stderr",I.stderr),Me({stdin:t}),Rt({batched:e}),Lt({batched:r}),Er=!0,ut()};function Qn(){Me(h?new at(process.stdin.fd):{stdin:()=>prompt()})}i(Qn,"setDefaultStdin");function Xn(){Nt(new ot),ut()}i(Xn,"setStdinError");function Me(t={}){let{stdin:e,error:r,isatty:n,autoEOF:o,read:a}=t,s=+!!e+ +!!r+ +!!a;if(s>1)throw new TypeError("At most one of stdin, read, and error must be provided.");if(!e&&o!==void 0)throw new TypeError("The 'autoEOF' option can only be used with the 'stdin' option");if(s===0){Qn();return}r&&Xn(),e&&(o=o===void 0?!0:o,Nt(new it(e.bind(t),!!n,o))),a&&Nt(t),ut()}i(Me,"setStdin");function Fr(t,e,r){let{raw:n,isatty:o,batched:a,write:s}=t,l=+!!n+ +!!a+ +!!s;if(l===0&&(t=r(),({raw:n,isatty:o,batched:a,write:s}=t)),l>1)throw new TypeError("At most one of 'raw', 'batched', and 'write' must be passed");if(!n&&!s&&o)throw new TypeError("Cannot set 'isatty' to true unless 'raw' or 'write' is provided");n&&e(new st(n.bind(t),!!o)),a&&e(new lt(a.bind(t))),s&&e(t),ut()}i(Fr,"_setStdwrite");function Zn(){return h?new De(process.stdout.fd):{batched:t=>console.log(t)}}i(Zn,"_getStdoutDefaults");function eo(){return h?new De(process.stderr.fd):{batched:t=>console.warn(t)}}i(eo,"_getStderrDefaults");function Rt(t={}){Fr(t,Gn,Zn)}i(Rt,"setStdout");function Lt(t={}){Fr(t,Jn,eo)}i(Lt,"setStderr");var to=new TextEncoder,Ar=new TextDecoder,ot=class{read(e){throw new FS.ErrnoError(29)}};i(ot,"ErrorReader");var at=class{constructor(e){this.fd=e,this.isatty=Ir.isatty(e)}read(e){try{return Tt.readSync(this.fd,e)}catch(r){if(r.toString().includes("EOF"))return 0;throw r}}fsync(){kr(this.fd)}};i(at,"NodeReader");var it=class{constructor(e,r,n){this.infunc=e,this.isatty=r,this.autoEOF=n,this.index=0,this.saved=void 0,this.insertEOF=!1}_getInput(){if(this.saved)return this.saved;let e=this.infunc();if(typeof e=="number")return e;if(e!=null){if(ArrayBuffer.isView(e)){if(e.BYTES_PER_ELEMENT!==1)throw console.warn(`Expected BYTES_PER_ELEMENT to be 1, infunc gave ${e.constructor}`),new FS.ErrnoError(29);return e}if(typeof e=="string")return e.endsWith(`\n`)||(e+=`\n`),e;if(Object.prototype.toString.call(e)==="[object ArrayBuffer]")return new Uint8Array(e);throw console.warn("Expected result to be undefined, null, string, array buffer, or array buffer view"),new FS.ErrnoError(29)}}read(e){if(this.insertEOF)return this.insertEOF=!1,0;let r=0;for(;;){let n=this._getInput();if(typeof n=="number"){e[0]=n,e=e.subarray(1),r++;continue}let o;if(n&&n.length>0)if(typeof n=="string"){let{read:a,written:s}=to.encodeInto(n,e);this.saved=n.slice(a),r+=s,o=e[s-1],e=e.subarray(s)}else{let a;n.length>e.length?(e.set(n.subarray(0,e.length)),this.saved=n.subarray(e.length),a=e.length):(e.set(n),this.saved=void 0,a=n.length),r+=a,o=e[a-1],e=e.subarray(a)}if(!(n&&n.length>0)||this.autoEOF||e.length===0)return this.insertEOF=r>0&&this.autoEOF&&o!==10,r}}fsync(){}};i(it,"LegacyReader");var st=class{constructor(e,r){this.out=e,this.isatty=r}write(e){for(let r of e)this.out(r);return e.length}};i(st,"CharacterCodeWriter");var lt=class{constructor(e){this.isatty=!1;this.out=e,this.output=[]}write(e){for(let r of e)r===10?(this.out(Ar.decode(new Uint8Array(this.output))),this.output=[]):r!==0&&this.output.push(r);return e.length}fsync(){this.output&&this.output.length>0&&(this.out(Ar.decode(new Uint8Array(this.output))),this.output=[])}};i(lt,"StringWriter");var De=class{constructor(e){this.fd=e,this.isatty=Ir.isatty(e)}write(e){return Tt.writeSync(this.fd,e)}fsync(){kr(this.fd)}};i(De,"NodeWriter");var Ct="sched$"+Math.random().toString(36).slice(2)+"$",Ut={},$t=0;function ro(){if(!Q)return;let t=i(e=>{if(typeof e.data=="string"&&e.data.indexOf(Ct)===0){let r=+e.data.slice(Ct.length),n=Ut[r];if(!n)return;try{n()}finally{delete Ut[r]}}},"onGlobalMessage");globalThis.addEventListener("message",t,!1)}i(ro,"installPostMessageHandler");ro();function no(t){if(h)setImmediate(t);else if(Q&&typeof globalThis.postMessage=="function")Ut[$t]=t,globalThis.postMessage(Ct+$t,"*"),$t++;else if(Se&&!kt&&typeof MessageChannel=="function"){let e=new MessageChannel;e.port1.onmessage=()=>{e.port1.onmessage=null,e.port1.close(),e.port2.close(),t()},e.port2.postMessage("")}else setTimeout(t,0)}i(no,"scheduleCallbackImmediate");function dt(t,e=0){e<=2?no(t):setTimeout(t,e)}i(dt,"scheduleCallback");var{get:oo,getOwnPropertyDescriptor:ao,ownKeys:io}=Reflect,so=i(t=>({value:t,enumerable:!0,writable:!0,configurable:!0}),"getPropertyDescriptor"),Dr=Symbol(),Or="prototype",lo={deleteProperty:(t,e)=>t.has(e)?t.delete(e):delete t[e],get(t,e,r){if(e===Dr)return t;let n=t[e];return typeof n=="function"&&e!=="constructor"&&(n=n.bind(t)),n||(n=t.get(e)),n},getOwnPropertyDescriptor(t,e){if(t.has(e))return so(t.get(e));if(e in t)return ao(t,e)},has:(t,e)=>t.has(e)||e in t,ownKeys:t=>[...t.keys(),...io(t)].filter(e=>["string","symbol"].includes(typeof e)),set:(t,e,r)=>(t.set(e,r),!0)},co=new Proxy(i(class extends Map{constructor(...e){return new Proxy(super(...e),lo)}},"LiteralMap"),{get(t,e,...r){return e!==Or&&e in t[Or]?(n,...o)=>{let a=n[Dr],s=a[e];return typeof s=="function"&&(s=s.apply(a,o)),s===a?n:s}:oo(t,e,...r)}}),Mr=co;var yt=new FinalizationRegistry(t=>void t());function uo(t){let e=new AbortController;for(let l of t)if(l.aborted)return e.abort(l.reason),e.signal;let r=new WeakRef(e),n=[],o=t.length;t.forEach(l=>{let c=new WeakRef(l);function u(){r.deref()?.abort(c.deref()?.reason)}i(u,"abort"),l.addEventListener("abort",u),n.push([c,u]),yt.register(l,()=>!--o&&a(),l)});function a(){n.forEach(([l,c])=>{let u=l.deref();u&&(u.removeEventListener("abort",c),yt.unregister(u));let d=r.deref();d&&(yt.unregister(d.signal),delete d.signal.__controller)})}i(a,"clear");let{signal:s}=e;return yt.register(s,a,s),s.addEventListener("abort",a),s.__controller=e,s}i(uo,"abortSignalAny");var Nr=uo;API.getExpectedKeys=function(){return[null,API.config.jsglobals,API.public_api,API,dt,API,{}]};var Lr=Symbol("getAccessorList");function pt(t,e=[]){return new Proxy(t,{get(r,n,o){if(n===Lr)return e;let a=Reflect.get(...arguments),s=Reflect.getOwnPropertyDescriptor(r,n);return s&&s.writable===!1&&!s.configurable||s&&s.set&&!s.get||!["object","function"].includes(typeof a)?a:pt(a,[...e,n])},getPrototypeOf(){return pt(Reflect.getPrototypeOf(...arguments),[...e,"[getProtoTypeOf]"])}})}i(pt,"makeGlobalsProxy");var $r=1886286592,ft=4+4+4+4+32;function yo(t,e){if(e.length!==8)throw new Error("Expected 256 bit buffer");for(let r=0;r<32;r++)e[r]=parseInt(t.slice(r*8,(r+1)*8),16)}i(yo,"encodeBuildId");function po(t){if(t.length!==8)throw new Error("Expected 256 bit buffer");return Array.from(t,e=>e.toString(16).padStart(8,"0")).join("")}i(po,"decodeBuildId");function Tr(t,e,r){if(e===r)return;if(typeof r=="function"&&typeof e!="function")throw console.warn(r,e),new Error(`Expected function at index ${t}`);let n=!1;try{n=JSON.stringify(e)===JSON.stringify(r)}catch(o){console.warn(o)}if(!n)throw console.warn(r,e),new Error(`Unexpected hiwire entry at index ${t}`)}i(Tr,"checkEntry");var Ne=5;API.serializeHiwireState=function(t,e){e||(e=Tr);let r=[],n=API.getExpectedKeys();for(let s=0;sRr(a,o)),e.hiwireKeys.forEach((o,a)=>{let s;if(!o)s=o;else if("path"in o)s=o.path.reduce((l,c)=>l[c],t)||null;else{if(!r)throw new Error("You must pass an appropriate deserializer as _snapshotDeserializer");s=r(o.serialized)}Rr(n.length+a,s)}),e.immortalKeys.forEach(o=>Module.__hiwire_immortal_add(o))}i(Ur,"syncUpSnapshotLoad2");async function jr(t,e){return new Promise((r,n)=>{t.FS.syncfs(e,o=>{o?n(o):r()})})}i(jr,"syncfs");async function Br(t){return await jr(t,!1)}i(Br,"syncLocalToRemote");async function Hr(t){return await jr(t,!0)}i(Hr,"syncRemoteToLocal");API.loadBinaryFile=Ae;API.rawRun=i(function(e){let r=Module.stringToNewUTF8(e);Module.API.capture_stderr();let n=_PyRun_SimpleString(r);_free(r);let o=Module.API.restore_stderr().trim();return[n,o]},"rawRun");API.runPythonInternal=function(t){return API._pyodide._base.eval_code(t,API.runPythonInternal_dict)};API.setPyProxyToStringMethod=function(t){Module.HEAP8[Module._compat_to_string_repr]=+t};API.saveState=()=>API.pyodide_py._state.save_state();API.restoreState=t=>API.pyodide_py._state.restore_state(t);API.scheduleCallback=dt;API.detectEnvironment=yr;AbortSignal.any?API.abortSignalAny=AbortSignal.any:API.abortSignalAny=Nr;API.LiteralMap=Mr;function zr(t){Module.FS.mkdirTree(t);let{node:e}=Module.FS.lookupPath(t,{follow_mount:!1});if(FS.isMountpoint(e))throw new Error(`path '${t}' is already a file system mount point`);if(!FS.isDir(e.mode))throw new Error(`path '${t}' points to a file not a directory`);for(let r in e.contents)throw new Error(`directory '${t}' is not empty`)}i(zr,"ensureMountPathExists");var v=class{static async loadPackagesFromImports(e,r={checkIntegrity:!0}){let n=API.pyodide_code.find_imports(e),o;try{o=n.toJs()}finally{n.destroy()}if(o.length===0)return[];let a=API._import_name_to_package_name,s=new Set;for(let l of o)a.has(l)&&s.add(a.get(l));return s.size?await Oe(Array.from(s),r):[]}static runPython(e,r={}){return r.globals||(r.globals=API.globals),API.pyodide_code.eval_code.callKwargs(e,r)}static async runPythonAsync(e,r={}){return r.globals||(r.globals=API.globals),await API.pyodide_code.eval_code_async.callKwargs(e,r)}static registerJsModule(e,r){API.pyodide_ffi.register_js_module(e,r)}static unregisterJsModule(e){API.pyodide_ffi.unregister_js_module(e)}static toPy(e,{depth:r,defaultConverter:n}={depth:-1}){switch(typeof e){case"string":case"number":case"boolean":case"bigint":case"undefined":return e}if(!e||API.isPyProxy(e))return e;let o=0,a=0;try{o=Module.js2python_convert(e,{depth:r,defaultConverter:n})}catch(s){throw s instanceof Module._PropagatePythonError&&_pythonexc2js(),s}try{if(_JsProxy_Check(o))return e;a=_python2js(o),a===null&&_pythonexc2js()}finally{_Py_DecRef(o)}return a}static pyimport(e){return API.pyodide_base.pyimport_impl(e)}static unpackArchive(e,r,n={}){if(!ArrayBuffer.isView(e)&&API.getTypeTag(e)!=="[object ArrayBuffer]")throw new TypeError("Expected argument 'buffer' to be an ArrayBuffer or an ArrayBuffer view");API.typedArrayAsUint8Array(e);let o=n.extractDir;API.package_loader.unpack_buffer.callKwargs({buffer:e,format:r,extract_dir:o,installer:"pyodide.unpackArchive"})}static async mountNativeFS(e,r){if(r.constructor.name!=="FileSystemDirectoryHandle")throw new TypeError("Expected argument 'fileSystemHandle' to be a FileSystemDirectoryHandle");return zr(e),Module.FS.mount(Module.FS.filesystems.NATIVEFS_ASYNC,{fileSystemHandle:r},e),await Hr(Module),{syncfs:async()=>await Br(Module)}}static mountNodeFS(e,r){if(!h)throw new Error("mountNodeFS only works in Node");zr(e);let n;try{n=tt.lstatSync(r)}catch{throw new Error(`hostPath '${r}' does not exist`)}if(!n.isDirectory())throw new Error(`hostPath '${r}' is not a directory`);Module.FS.mount(Module.FS.filesystems.NODEFS,{root:r},e)}static registerComlink(e){API._Comlink=e}static setInterruptBuffer(e){Module.HEAP8[Module._Py_EMSCRIPTEN_SIGNAL_HANDLING]=+!!e,Module.Py_EmscriptenSignalBuffer=e}static checkInterrupt(){if(_PyGILState_Check()){__PyErr_CheckSignals()&&_pythonexc2js();return}else{let e=Module.Py_EmscriptenSignalBuffer;if(e&&e[0]===2)throw new Module.FS.ErrnoError(27)}}static setDebug(e){let r=!!API.debug_ffi;return API.debug_ffi=e,r}static makeMemorySnapshot({serializer:e}={}){if(!API.config._makeSnapshot)throw new Error("Can only use pyodide.makeMemorySnapshot if the _makeSnapshot option is passed to loadPyodide");return API.makeSnapshot(e)}};i(v,"PyodideAPI"),v.version=xr,v.loadPackage=Oe,v.loadedPackages=Ee,v.ffi=ir,v.setStdin=Me,v.setStdout=Rt,v.setStderr=Lt,v.globals={},v.FS={},v.PATH={},v.canvas=cr,v.ERRNO_CODES={},v.pyodide_py={};function fo(){let t=Object.getOwnPropertyDescriptors(v);delete t.prototype;let e=Object.create({},t);return API.public_api=e,e.FS=Module.FS,e.PATH=Module.PATH,e.ERRNO_CODES=Module.ERRNO_CODES,e._module=Module,e._api=API,e}i(fo,"makePublicAPI");function go(t,e){return new Proxy(t,{get(r,n){return n==="get"?o=>{let a=r.get(o);return a===void 0&&(a=e.get(o)),a}:n==="has"?o=>r.has(o)||e.has(o):Reflect.get(r,n)}})}i(go,"wrapPythonGlobals");var Wr;API.bootstrapFinalizedPromise=new Promise(t=>Wr=t);API.finalizeBootstrap=function(t,e){t&&Cr();let[r,n]=API.rawRun("import _pyodide_core");r&&API.fatal_loading_error(`Failed to import _pyodide_core\n`,n),API.runPythonInternal_dict=API._pyodide._base.eval_code("{}"),API.importlib=API.runPythonInternal("import importlib; importlib");let o=API.importlib.import_module;API.sys=o("sys"),API.os=o("os");let a=API.runPythonInternal("import __main__; __main__.__dict__"),s=API.runPythonInternal("import builtins; builtins.__dict__");API.globals=go(a,s);let l=API._pyodide._importhook,c=fo();API.config._makeSnapshot&&(API.config.jsglobals=pt(API.config.jsglobals));let u=API.config.jsglobals;return t?Ur(u,t,e):(l.register_js_finder(),l.register_js_module("js",u),l.register_js_module("pyodide_js",c)),API.pyodide_py=o("pyodide"),API.pyodide_code=o("pyodide.code"),API.pyodide_ffi=o("pyodide.ffi"),API.package_loader=o("pyodide._package_loader"),API.pyodide_base=o("_pyodide._base"),API.sitepackages=API.package_loader.SITE_PACKAGES.__str__(),API.dsodir=API.package_loader.DSO_DIR.__str__(),API.defaultLdLibraryPath=[API.dsodir,API.sitepackages],API.os.environ.__setitem__("LD_LIBRARY_PATH",API.defaultLdLibraryPath.join(":")),c.pyodide_py=API.pyodide_py,c.globals=API.globals,Wr(),c}})()}var StackSwitching=(()=>{var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var stack_switching_exports={};__export(stack_switching_exports,{StackState:()=>StackState,createPromising:()=>createPromising,jsWrapperTag:()=>jsWrapperTag,jspiSupported:()=>jspiSupported,newJspiSupported:()=>newJspiSupported,oldJspiSupported:()=>oldJspiSupported,promisingApply:()=>promisingApply,promisingRunMain:()=>promisingRunMain,suspenderGlobal:()=>suspenderGlobal,validSuspender:()=>validSuspender});var WASM_PRELUDE=[0,97,115,109,1,0,0,0];function insertSectionPrefix(sectionCode,sectionBody){var section=[sectionCode];uleb128Encode(sectionBody.length,section);section.push(...sectionBody);return section}var typeCodes={i32:127,i64:126,f32:125,f64:124,externref:111,void:64};var constCodes={i32:65,i64:66,f32:67,f64:68};function emscriptenSigToWasm(sig){const lookup={i:"i32",j:"i64",f:"f32",d:"f64",e:"externref",v:""};const parameters=sig.split("").map(x=>lookup[x]);const result=parameters.shift();const results=result?[result]:[];return{parameters:parameters,results:results}}var TypeSection=class{constructor(){this._numTypes=0;this._section=[0]}addEmscripten(sig){return this.addWasm(emscriptenSigToWasm(sig))}addWasm({parameters:parameters,results:results}){this._section.push(96);uleb128Encode(parameters.length,this._section);for(let p of parameters){this._section.push(typeCodes[p])}uleb128Encode(results.length,this._section);for(let p of results){this._section.push(typeCodes[p])}return this._numTypes++}generate(){this._section[0]=this._numTypes;return insertSectionPrefix(1,this._section)}};function encodeStr(s){const buf=(new TextEncoder).encode(s);return[buf.length,...buf]}var ImportSection=class{constructor(){this._numImports=0;this.numGlobals=0;this.numFuncs=0;this._section=[0]}_addName(name){this._section.push(...ImportSection._module);this._section.push(...encodeStr(name))}addFunction(name,sig){this._addName(name);this._section.push(ImportSection.descr.func,sig);this._numImports++;return this.numFuncs++}addTable(name){this._addName(name);this._section.push(ImportSection.descr.table,112,0,0);this._numImports++}addGlobal(name,type){this._addName(name);this._section.push(ImportSection.descr.global,typeCodes[type],1);this._numImports++;return this.numGlobals++}addTag(name,sig){this._addName(name);this._section.push(ImportSection.descr.tag,0,sig);this._numImports++}generate(){this._section[0]=this._numImports;return insertSectionPrefix(2,this._section)}};ImportSection._module=encodeStr("e");ImportSection.descr={func:0,table:1,mem:2,global:3,tag:4};var CodeSection=class{constructor(...locals){this._section=[];this.add(locals.length);for(let l of locals){this.add(1,typeCodes[l])}}add(...args){this._section.push(...args)}local_get(idx){this.add(32,idx)}local_set(idx){this.add(33,idx)}local_tee(idx){this.add(34,idx)}global_get(idx){this.add(35,idx)}global_set(idx){this.add(36,idx)}call(func){this.add(16,func)}call_indirect(func){this.add(17,func,0)}const(type,...val){this.add(constCodes[type],...val)}end(){this.add(11)}generate(){this.end();return insertSectionPrefix(10,insertSectionPrefix(1,this._section))}};var WasmModule=class{constructor(){this._sections=[WASM_PRELUDE]}addSection(section){this._sections.push(section.generate())}addSectionBody(sectionCode,sectionBody){this._sections.push(insertSectionPrefix(sectionCode,sectionBody))}addImportSection(imports){this.addSection(imports);this._numImportFuncs=imports.numFuncs}setExportType(type){const functionSection=[1,type];this.addSectionBody(3,functionSection);const exportSection=[1,...encodeStr("o"),0,this._numImportFuncs];this.addSectionBody(7,exportSection)}generate(){const bytes=new Uint8Array(this._sections.flat());return new WebAssembly.Module(bytes)}};function createInvokeModule(sig){const mod=new WasmModule;const types=new TypeSection;const invoke_sig=emscriptenSigToWasm(sig);const export_sig=structuredClone(invoke_sig);export_sig.parameters.unshift("i32");const invoke_tidx=types.addWasm(invoke_sig);const export_tidx=types.addWasm(export_sig);const try_tidx=typeCodes[invoke_sig.results[0]||"void"];const tag_tidx=types.addEmscripten("ve");const save_tidx=types.addEmscripten("i");const restore_tidx=types.addEmscripten("vi");const setThrew_tidx=types.addEmscripten("vii");mod.addSection(types);const imports=new ImportSection;imports.addTable("t");imports.addTag("tag",tag_tidx);const save_stack_func=imports.addFunction("s",save_tidx);const restore_stack_func=imports.addFunction("r",restore_tidx);const set_threw_func=imports.addFunction("q",setThrew_tidx);mod.addImportSection(imports);mod.setExportType(export_tidx);const code=new CodeSection(["i32"]);const stackLocal=export_sig.parameters.length;code.call(save_stack_func);code.local_set(stackLocal);code.add(6,try_tidx);for(let i=1;inew WebAssembly.Exception(jsWrapperTag,[e]);function createInvoke(sig){if(!jsWrapperTag){return createInvokeFunction(sig)}const module=createInvokeModule(sig);const instance=new WebAssembly.Instance(module,{e:{t:wasmTable,s:()=>stackSave(),r:x=>stackRestore(x),q:(x,y)=>_setThrew(x,y),tag:jsWrapperTag}});return instance.exports["o"]}function adjustWasmImports(wasmImports){const i="invoke_";for(let name of Object.keys(wasmImports.env)){if(!name.startsWith(i)){continue}wasmImports.env[name]=createInvoke(name.slice(i.length))}}var suspenderGlobal={value:null};var validSuspender={value:false};var promisingApplyHandler;function promisingApply(...args){validSuspender.value=true;Module.stackStop=stackSave();Module.origCframe=_get_cframe();return promisingApplyHandler(...args)}var promisingRunMainHandler;function promisingRunMain(...args){validSuspender.value=true;Module.stackStop=stackSave();return promisingRunMainHandler(...args)}function createPromising(wasm_func){if(Module.newJspiSupported){const promisingFunc=WebAssembly.promising(wasm_func);async function wrapper(...args){const orig=validSuspender.value;validSuspender.value=true;try{return await promisingFunc(null,...args)}finally{validSuspender.value=orig}}return wrapper}const{parameters:parameters}=wasmFunctionType(wasm_func);parameters.shift();return new WebAssembly.Function({parameters:parameters,results:["externref"]},wasm_func,{promising:"first"})}function initSuspenders(){promisingApplyHandler=createPromising(wasmExports._pyproxy_apply_promising);if(wasmExports.run_main_promising){promisingRunMainHandler=createPromising(wasmExports.run_main_promising)}}var stackStates=[];var StackState=class{constructor(){this.start=stackSave();this.stop=Module.stackStop;this._copy=new Uint8Array(0);if(this.start!==this.stop){stackStates.push(this)}}restore(){let total=0;while(stackStates.length>0&&stackStates[stackStates.length-1].stop>>0,this.start+sz2>>>0);const c=new Uint8Array(sz2);c.set(this._copy);c.set(new_segment,sz1);this._copy=c;return sz2}_save(){return this._save_up_to(this.stop)}};var canConstructWasm=true;try{new WebAssembly.Module(new Uint8Array([0,97,115,109,1,0,0,0]))}catch(e){canConstructWasm=false}var newJspiSupported=canConstructWasm&&"Suspending"in WebAssembly;var oldJspiSupported=canConstructWasm&&"Suspender"in WebAssembly;var jspiSupported=newJspiSupported||oldJspiSupported;Module.newJspiSupported=newJspiSupported;Module.oldJspiSupported=oldJspiSupported;Module.jspiSupported=jspiSupported;if(jspiSupported){Module.preRun.push(initSuspenders);Module.adjustWasmImports=adjustWasmImports;Module.wrapException=wrapException;Module.createInvoke=createInvoke}return __toCommonJS(stack_switching_exports)})();const{StackState:StackState,createPromising:createPromising,jsWrapperTag:jsWrapperTag,jspiSupported:jspiSupported,newJspiSupported:newJspiSupported,oldJspiSupported:oldJspiSupported,promisingApply:promisingApply,promisingRunMain:promisingRunMain,suspenderGlobal:suspenderGlobal,validSuspender:validSuspender}=StackSwitching;Object.assign(Module,StackSwitching);const API=Module.API;const Hiwire={};const Tests={};API.tests=Tests;API.version="0.27.7";Module.hiwire=Hiwire;function getTypeTag(x){try{return Object.prototype.toString.call(x)}catch(e){return""}}API.getTypeTag=getTypeTag;function hasProperty(obj,prop){try{while(obj){if(Object.hasOwn(obj,prop)){return true}obj=Object.getPrototypeOf(obj)}}catch(e){}return false}function hasMethod(obj,prop){try{return typeof obj[prop]==="function"}catch(e){return false}}const pyproxyIsAlive=px=>!!Module.PyProxy_getAttrsQuiet(px).shared.ptr;API.pyproxyIsAlive=pyproxyIsAlive;const errNoRet=()=>{throw new Error("Assertion error: control reached end of function without return")};Module.reportUndefinedSymbols=()=>{};const nullToUndefined=x=>x===null?undefined:x;function isPromise(obj){try{return typeof obj?.then==="function"}catch(e){return false}}API.isPromise=isPromise;function bufferAsUint8Array(arg){if(ArrayBuffer.isView(arg)){return new Uint8Array(arg.buffer,arg.byteOffset,arg.byteLength)}else{return new Uint8Array(arg)}}API.typedArrayAsUint8Array=bufferAsUint8Array;Module.iterObject=function*(object){for(let k in object){if(Object.hasOwn(object,k)){yield k}}};function wasmFunctionType(wasm_func){if(!WebAssembly.Function){throw new Error("No type reflection")}if(WebAssembly.Function.type){return WebAssembly.Function.type(wasm_func)}return wasm_func.type()}pyodide_js_init();pyodide_js_init.sig="v";function set_suspender(suspender){suspenderGlobal.value=suspender}set_suspender.sig="ve";function get_suspender(){return suspenderGlobal.value}get_suspender.sig="e";function syncifyHandler(x,y){return null}async function inner(x,y){try{return nullToUndefined(await(x??y))}catch(e){if(e&&e.pyodide_fatal_error){throw e}Module.syncify_error=e;return null}}if(newJspiSupported){syncifyHandler=new WebAssembly.Suspending(inner)}else if(oldJspiSupported){syncifyHandler=new WebAssembly.Function({parameters:["externref","externref"],results:["externref"]},inner,{suspending:"first"})}syncifyHandler.sig="eee";function JsvPromise_Syncify_handleError(){if(!Module.syncify_error){return}Module.handle_js_error(Module.syncify_error);delete Module.syncify_error}JsvPromise_Syncify_handleError.sig="v";function saveState(){if(!validSuspender.value){return null}const stackState=new StackState;const threadState=_captureThreadState();const origCframe=Module.origCframe;_restore_cframe(origCframe);return{threadState:threadState,stackState:stackState,suspender:suspenderGlobal.value,origCframe:origCframe}}saveState.sig="e";function restoreState(state){state.stackState.restore();Module.origCframe=state.origCframe;_restoreThreadState(state.threadState);suspenderGlobal.value=state.suspender;validSuspender.value=true}restoreState.sig="ve";function _PyImport_InitFunc_TrampolineCall(func){return wasmTable.get(func)()}_PyImport_InitFunc_TrampolineCall.sig="ii";function _Py_emscripten_runtime(){var info;if(typeof navigator=="object"){info=navigator.userAgent}else if(typeof process=="object"){info="Node.js ".concat(process.version)}else{info="UNKNOWN"}var len=lengthBytesUTF8(info)+1;var res=_malloc(len);if(res)stringToUTF8(info,res,len);return res}_Py_emscripten_runtime.sig="i";function _Py_CheckEmscriptenSignals_Helper(){if(!Module.Py_EmscriptenSignalBuffer){return 0}try{let result=Module.Py_EmscriptenSignalBuffer[0];Module.Py_EmscriptenSignalBuffer[0]=0;return result}catch(e){return 0}}_Py_CheckEmscriptenSignals_Helper.sig="i";function _PyEM_GetCountArgsPtr(){return Module._PyEM_CountArgsPtr}function getPyEMCountArgsPtr(){let isIOS=globalThis.navigator&&/iPad|iPhone|iPod/.test(navigator.platform);if(isIOS){return 0}const code=new Uint8Array([0,97,115,109,1,0,0,0,1,27,5,96,0,1,127,96,1,127,1,127,96,2,127,127,1,127,96,3,127,127,127,1,127,96,1,127,0,2,9,1,1,101,1,116,1,112,0,0,3,2,1,1,7,5,1,1,102,0,0,10,68,1,66,1,1,112,32,0,37,0,34,1,251,20,3,2,4,69,13,0,65,3,15,11,32,1,251,20,2,2,4,69,13,0,65,2,15,11,32,1,251,20,1,2,4,69,13,0,65,1,15,11,32,1,251,20,0,2,4,69,13,0,65,0,15,11,65,127,11]);try{const mod=new WebAssembly.Module(code);const inst=new WebAssembly.Instance(mod,{e:{t:wasmTable}});return addFunction(inst.exports.f)}catch(e){return 0}}addOnPreRun(()=>{const ptr=getPyEMCountArgsPtr();Module._PyEM_CountArgsPtr=ptr;const offset=HEAP32[__PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET/4>>>0];HEAP32[(__PyRuntime+offset)/4>>>0]=ptr});_PyEM_GetCountArgsPtr.sig="i";function _PyEM_TrampolineCall_JS(func,arg1,arg2,arg3){return wasmTable.get(func)(arg1,arg2,arg3)}_PyEM_TrampolineCall_JS.sig="iiiii";function unbox_small_structs(type_ptr){var type_id=HEAPU16[(type_ptr+6>>1)+0>>>0];while(type_id===13){var elements=HEAPU32[(type_ptr+8>>2)+0>>>0];var first_element=HEAPU32[(elements>>2)+0>>>0];if(first_element===0){type_id=0;break}else if(HEAPU32[(elements>>2)+1>>>0]===0){type_ptr=first_element;type_id=HEAPU16[(first_element+6>>1)+0>>>0]}else{break}}return[type_ptr,type_id]}function ffi_call_js(cif,fn,rvalue,avalue){var abi=HEAPU32[(cif>>2)+0>>>0];var nargs=HEAPU32[(cif>>2)+1>>>0];var nfixedargs=HEAPU32[(cif>>2)+6>>>0];var arg_types_ptr=HEAPU32[(cif>>2)+2>>>0];var rtype_unboxed=unbox_small_structs(HEAPU32[(cif>>2)+3>>>0]);var rtype_ptr=rtype_unboxed[0];var rtype_id=rtype_unboxed[1];var orig_stack_ptr=stackSave();var cur_stack_ptr=orig_stack_ptr;var args=[];var ret_by_arg=false;if(rtype_id===15){throw new Error("complex ret marshalling nyi")}if(rtype_id<0||rtype_id>15){throw new Error("Unexpected rtype "+rtype_id)}if(rtype_id===4||rtype_id===13){args.push(rvalue);ret_by_arg=true}for(var i=0;i>2)+i>>>0];var arg_unboxed=unbox_small_structs(HEAPU32[(arg_types_ptr>>2)+i>>>0]);var arg_type_ptr=arg_unboxed[0];var arg_type_id=arg_unboxed[1];switch(arg_type_id){case 1:case 10:case 9:case 14:args.push(HEAPU32[(arg_ptr>>2)+0>>>0]);break;case 2:args.push(HEAPF32[(arg_ptr>>2)+0>>>0]);break;case 3:args.push(HEAPF64[(arg_ptr>>3)+0>>>0]);break;case 5:args.push(HEAPU8[arg_ptr+0>>>0]);break;case 6:args.push(HEAP8[arg_ptr+0>>>0]);break;case 7:args.push(HEAPU16[(arg_ptr>>1)+0>>>0]);break;case 8:args.push(HEAP16[(arg_ptr>>1)+0>>>0]);break;case 11:case 12:args.push(HEAPU64[(arg_ptr>>3)+0]);break;case 4:args.push(HEAPU64[(arg_ptr>>3)+0]);args.push(HEAPU64[(arg_ptr>>3)+1]);break;case 13:var size=HEAPU32[(arg_type_ptr>>2)+0>>>0];var align=HEAPU16[(arg_type_ptr+4>>1)+0>>>0];cur_stack_ptr-=size,cur_stack_ptr&=~(align-1);HEAP8.subarray(cur_stack_ptr>>>0,cur_stack_ptr+size>>>0).set(HEAP8.subarray(arg_ptr>>>0,arg_ptr+size>>>0));args.push(cur_stack_ptr);break;case 15:throw new Error("complex marshalling nyi");default:throw new Error("Unexpected type "+arg_type_id)}}if(nfixedargs!=nargs){var struct_arg_info=[];for(var i=nargs-1;i>=nfixedargs;i--){var arg_ptr=HEAPU32[(avalue>>2)+i>>>0];var arg_unboxed=unbox_small_structs(HEAPU32[(arg_types_ptr>>2)+i>>>0]);var arg_type_ptr=arg_unboxed[0];var arg_type_id=arg_unboxed[1];switch(arg_type_id){case 5:case 6:cur_stack_ptr-=1,cur_stack_ptr&=~(1-1);HEAPU8[cur_stack_ptr+0>>>0]=HEAPU8[arg_ptr+0>>>0];break;case 7:case 8:cur_stack_ptr-=2,cur_stack_ptr&=~(2-1);HEAPU16[(cur_stack_ptr>>1)+0>>>0]=HEAPU16[(arg_ptr>>1)+0>>>0];break;case 1:case 9:case 10:case 14:case 2:cur_stack_ptr-=4,cur_stack_ptr&=~(4-1);HEAPU32[(cur_stack_ptr>>2)+0>>>0]=HEAPU32[(arg_ptr>>2)+0>>>0];break;case 3:case 11:case 12:cur_stack_ptr-=8,cur_stack_ptr&=~(8-1);HEAPU32[(cur_stack_ptr>>2)+0>>>0]=HEAPU32[(arg_ptr>>2)+0>>>0];HEAPU32[(cur_stack_ptr>>2)+1>>>0]=HEAPU32[(arg_ptr>>2)+1>>>0];break;case 4:cur_stack_ptr-=16,cur_stack_ptr&=~(8-1);HEAPU32[(cur_stack_ptr>>2)+0>>>0]=HEAPU32[(arg_ptr>>2)+0>>>0];HEAPU32[(cur_stack_ptr>>2)+1>>>0]=HEAPU32[(arg_ptr>>2)+1>>>0];HEAPU32[(cur_stack_ptr>>2)+2>>>0]=HEAPU32[(arg_ptr>>2)+2>>>0];HEAPU32[(cur_stack_ptr>>2)+3>>>0]=HEAPU32[(arg_ptr>>2)+3>>>0];break;case 13:cur_stack_ptr-=4,cur_stack_ptr&=~(4-1);struct_arg_info.push([cur_stack_ptr,arg_ptr,HEAPU32[(arg_type_ptr>>2)+0>>>0],HEAPU16[(arg_type_ptr+4>>1)+0>>>0]]);break;case 15:throw new Error("complex arg marshalling nyi");default:throw new Error("Unexpected argtype "+arg_type_id)}}args.push(cur_stack_ptr);for(var i=0;i>>0,cur_stack_ptr+size>>>0).set(HEAP8.subarray(arg_ptr>>>0,arg_ptr+size>>>0));HEAPU32[(arg_target>>2)+0>>>0]=cur_stack_ptr}}stackRestore(cur_stack_ptr);stackAlloc(0);var result=(0,getWasmTableEntry(fn).apply(null,args));stackRestore(orig_stack_ptr);if(ret_by_arg){return}switch(rtype_id){case 0:break;case 1:case 9:case 10:case 14:HEAPU32[(rvalue>>2)+0>>>0]=result;break;case 2:HEAPF32[(rvalue>>2)+0>>>0]=result;break;case 3:HEAPF64[(rvalue>>3)+0>>>0]=result;break;case 5:case 6:HEAPU8[rvalue+0>>>0]=result;break;case 7:case 8:HEAPU16[(rvalue>>1)+0>>>0]=result;break;case 11:case 12:HEAPU64[(rvalue>>3)+0]=result;break;case 15:throw new Error("complex ret marshalling nyi");default:throw new Error("Unexpected rtype "+rtype_id)}}ffi_call_js.sig="viiii";function ffi_closure_alloc_js(size,code){var closure=_malloc(size);var index=getEmptyTableSlot();HEAPU32[(code>>2)+0>>>0]=index;HEAPU32[(closure>>2)+0>>>0]=index;return closure}ffi_closure_alloc_js.sig="iii";function ffi_closure_free_js(closure){var index=HEAPU32[(closure>>2)+0>>>0];freeTableIndexes.push(index);_free(closure)}ffi_closure_free_js.sig="vi";function ffi_prep_closure_loc_js(closure,cif,fun,user_data,codeloc){var abi=HEAPU32[(cif>>2)+0>>>0];var nargs=HEAPU32[(cif>>2)+1>>>0];var nfixedargs=HEAPU32[(cif>>2)+6>>>0];var arg_types_ptr=HEAPU32[(cif>>2)+2>>>0];var rtype_unboxed=unbox_small_structs(HEAPU32[(cif>>2)+3>>>0]);var rtype_ptr=rtype_unboxed[0];var rtype_id=rtype_unboxed[1];var sig;var ret_by_arg=false;switch(rtype_id){case 0:sig="v";break;case 13:case 4:sig="vi";ret_by_arg=true;break;case 1:case 5:case 6:case 7:case 8:case 9:case 10:case 14:sig="i";break;case 2:sig="f";break;case 3:sig="d";break;case 11:case 12:sig="j";break;case 15:throw new Error("complex ret marshalling nyi");default:throw new Error("Unexpected rtype "+rtype_id)}var unboxed_arg_type_id_list=[];var unboxed_arg_type_info_list=[];for(var i=0;i>2)+i>>>0]);var arg_type_ptr=arg_unboxed[0];var arg_type_id=arg_unboxed[1];unboxed_arg_type_id_list.push(arg_type_id);unboxed_arg_type_info_list.push([HEAPU32[(arg_type_ptr>>2)+0>>>0],HEAPU16[(arg_type_ptr+4>>1)+0>>>0]])}for(var i=0;i>2)+carg_idx>>>0]=cur_ptr;HEAPU8[cur_ptr+0>>>0]=cur_arg;break;case 7:case 8:cur_ptr-=2,cur_ptr&=~(4-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPU16[(cur_ptr>>1)+0>>>0]=cur_arg;break;case 1:case 9:case 10:case 14:cur_ptr-=4,cur_ptr&=~(4-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPU32[(cur_ptr>>2)+0>>>0]=cur_arg;break;case 13:cur_ptr-=arg_size,cur_ptr&=~(arg_align-1);HEAP8.subarray(cur_ptr>>>0,cur_ptr+arg_size>>>0).set(HEAP8.subarray(cur_arg>>>0,cur_arg+arg_size>>>0));HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;break;case 2:cur_ptr-=4,cur_ptr&=~(4-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPF32[(cur_ptr>>2)+0>>>0]=cur_arg;break;case 3:cur_ptr-=8,cur_ptr&=~(8-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPF64[(cur_ptr>>3)+0>>>0]=cur_arg;break;case 11:case 12:cur_ptr-=8,cur_ptr&=~(8-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPU64[(cur_ptr>>3)+0]=cur_arg;break;case 4:cur_ptr-=16,cur_ptr&=~(8-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPU64[(cur_ptr>>3)+0]=cur_arg;cur_arg=args[jsarg_idx++];HEAPU64[(cur_ptr>>3)+1]=cur_arg;break}}var varargs=args[args.length-1];for(;carg_idx>2)+0>>>0];cur_ptr-=arg_size,cur_ptr&=~(arg_align-1);HEAP8.subarray(cur_ptr>>>0,cur_ptr+arg_size>>>0).set(HEAP8.subarray(struct_ptr>>>0,struct_ptr+arg_size>>>0));HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr}else{HEAPU32[(args_ptr>>2)+carg_idx>>>0]=varargs}varargs+=4}stackRestore(cur_ptr);stackAlloc(0);0;getWasmTableEntry(HEAPU32[(closure>>2)+2>>>0])(HEAPU32[(closure>>2)+1>>>0],ret_ptr,args_ptr,HEAPU32[(closure>>2)+3>>>0]);stackRestore(orig_stack_ptr);if(!ret_by_arg){switch(sig[0]){case"i":return HEAPU32[(ret_ptr>>2)+0>>>0];case"j":return HEAPU64[(ret_ptr>>3)+0];case"d":return HEAPF64[(ret_ptr>>3)+0>>>0];case"f":return HEAPF32[(ret_ptr>>2)+0>>>0]}}}try{var wasm_trampoline=convertJsFunctionToWasm(trampoline,sig)}catch(e){return 1}setWasmTableEntry(codeloc,wasm_trampoline);HEAPU32[(closure>>2)+1>>>0]=cif;HEAPU32[(closure>>2)+2>>>0]=fun;HEAPU32[(closure>>2)+3>>>0]=user_data;return 0}ffi_prep_closure_loc_js.sig="iiiiii";function __hiwire_deduplicate_new(){return new Map}__hiwire_deduplicate_new.sig="e";function __hiwire_deduplicate_get(map,value){return map.get(value)}__hiwire_deduplicate_get.sig="iee";function __hiwire_deduplicate_set(map,value,ref){map.set(value,ref)}__hiwire_deduplicate_set.sig="veei";function __hiwire_deduplicate_delete(map,value){map.delete(value)}__hiwire_deduplicate_delete.sig="vee";function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status}Module["ExitStatus"]=ExitStatus;var GOT={};Module["GOT"]=GOT;var currentModuleWeakSymbols=new Set([]);Module["currentModuleWeakSymbols"]=currentModuleWeakSymbols;var GOTHandler={get(obj,symName){var rtn=GOT[symName];if(!rtn){rtn=GOT[symName]=new WebAssembly.Global({"value":"i32","mutable":true})}if(!currentModuleWeakSymbols.has(symName)){rtn.required=true}return rtn}};Module["GOTHandler"]=GOTHandler;var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};Module["callRuntimeCallbacks"]=callRuntimeCallbacks;var decrementExceptionRefcount=ptr=>___cxa_decrement_exception_refcount(ptr);Module["decrementExceptionRefcount"]=decrementExceptionRefcount;var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf8"):undefined;Module["UTF8Decoder"]=UTF8Decoder;var UTF8ArrayToString=(heapOrArray,idx,maxBytesToRead)=>{idx>>>=0;var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};Module["UTF8ArrayToString"]=UTF8ArrayToString;var getDylinkMetadata=binary=>{var offset=0;var end=0;function getU8(){return binary[offset++]}function getLEB(){var ret=0;var mul=1;while(1){var byte=binary[offset++];ret+=(byte&127)*mul;mul*=128;if(!(byte&128))break}return ret}function getString(){var len=getLEB();offset+=len;return UTF8ArrayToString(binary,offset-len,len)}function failIf(condition,message){if(condition)throw new Error(message)}var name="dylink.0";if(binary instanceof WebAssembly.Module){var dylinkSection=WebAssembly.Module.customSections(binary,name);if(dylinkSection.length===0){name="dylink";dylinkSection=WebAssembly.Module.customSections(binary,name)}failIf(dylinkSection.length===0,"need dylink section");binary=new Uint8Array(dylinkSection[0]);end=binary.length}else{var int32View=new Uint32Array(new Uint8Array(binary.subarray(0,24)).buffer);var magicNumberFound=int32View[0]==1836278016;failIf(!magicNumberFound,"need to see wasm magic number");failIf(binary[8]!==0,"need the dylink section to be first");offset=9;var section_size=getLEB();end=offset+section_size;name=getString()}var customSection={neededDynlibs:[],tlsExports:new Set,weakImports:new Set};if(name=="dylink"){customSection.memorySize=getLEB();customSection.memoryAlign=getLEB();customSection.tableSize=getLEB();customSection.tableAlign=getLEB();var neededDynlibsCount=getLEB();for(var i=0;i_emscripten_stack_get_current();Module["stackSave"]=stackSave;var stackRestore=val=>__emscripten_stack_restore(val);Module["stackRestore"]=stackRestore;var stackAlloc=sz=>__emscripten_stack_alloc(sz);Module["stackAlloc"]=stackAlloc;var UTF8ToString=(ptr,maxBytesToRead)=>{ptr>>>=0;return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""};Module["UTF8ToString"]=UTF8ToString;var getExceptionMessageCommon=ptr=>{var sp=stackSave();var type_addr_addr=stackAlloc(4);var message_addr_addr=stackAlloc(4);___get_exception_message(ptr,type_addr_addr,message_addr_addr);var type_addr=HEAPU32[type_addr_addr>>>2>>>0];var message_addr=HEAPU32[message_addr_addr>>>2>>>0];var type=UTF8ToString(type_addr);_free(type_addr);var message;if(message_addr){message=UTF8ToString(message_addr);_free(message_addr)}stackRestore(sp);return[type,message]};Module["getExceptionMessageCommon"]=getExceptionMessageCommon;var getExceptionMessage=ptr=>getExceptionMessageCommon(ptr);Module["getExceptionMessage"]=getExceptionMessage;function getValue(ptr,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":return HEAP8[ptr>>>0];case"i8":return HEAP8[ptr>>>0];case"i16":return HEAP16[ptr>>>1>>>0];case"i32":return HEAP32[ptr>>>2>>>0];case"i64":return HEAP64[ptr>>>3];case"float":return HEAPF32[ptr>>>2>>>0];case"double":return HEAPF64[ptr>>>3>>>0];case"*":return HEAPU32[ptr>>>2>>>0];default:abort(`invalid type for getValue: ${type}`)}}Module["getValue"]=getValue;var incrementExceptionRefcount=ptr=>___cxa_increment_exception_refcount(ptr);Module["incrementExceptionRefcount"]=incrementExceptionRefcount;var newDSO=(name,handle,syms)=>{var dso={refcount:Infinity,name:name,exports:syms,global:true};LDSO.loadedLibsByName[name]=dso;if(handle!=undefined){LDSO.loadedLibsByHandle[handle]=dso}return dso};Module["newDSO"]=newDSO;var LDSO={loadedLibsByName:{},loadedLibsByHandle:{},init(){newDSO("__main__",0,wasmImports)}};Module["LDSO"]=LDSO;var ___heap_base=9883824;Module["___heap_base"]=___heap_base;var zeroMemory=(address,size)=>{HEAPU8.fill(0,address,address+size);return address};Module["zeroMemory"]=zeroMemory;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;Module["alignMemory"]=alignMemory;var getMemory=size=>{if(runtimeInitialized){return zeroMemory(_malloc(size),size)}var ret=___heap_base;var end=ret+alignMemory(size,16);___heap_base=end;GOT["__heap_base"].value=end;return ret};Module["getMemory"]=getMemory;var isInternalSym=symName=>["__cpp_exception","__c_longjmp","__wasm_apply_data_relocs","__dso_handle","__tls_size","__tls_align","__set_stack_limits","_emscripten_tls_init","__wasm_init_tls","__wasm_call_ctors","__start_em_asm","__stop_em_asm","__start_em_js","__stop_em_js"].includes(symName)||symName.startsWith("__em_js__");Module["isInternalSym"]=isInternalSym;var uleb128Encode=(n,target)=>{if(n<128){target.push(n)}else{target.push(n%128|128,n>>7)}};Module["uleb128Encode"]=uleb128Encode;var sigToWasmTypes=sig=>{var typeNames={"i":"i32","j":"i64","f":"f32","d":"f64","e":"externref","p":"i32"};var type={parameters:[],results:sig[0]=="v"?[]:[typeNames[sig[0]]]};for(var i=1;i{var sigRet=sig.slice(0,1);var sigParam=sig.slice(1);var typeCodes={"i":127,"p":127,"j":126,"f":125,"d":124,"e":111};target.push(96);uleb128Encode(sigParam.length,target);for(var i=0;i{if(typeof WebAssembly.Function=="function"){return new WebAssembly.Function(sigToWasmTypes(sig),func)}var typeSectionBody=[1];generateFuncType(sig,typeSectionBody);var bytes=[0,97,115,109,1,0,0,0,1];uleb128Encode(typeSectionBody.length,bytes);bytes.push(...typeSectionBody);bytes.push(2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0);var module=new WebAssembly.Module(new Uint8Array(bytes));var instance=new WebAssembly.Instance(module,{"e":{"f":func}});var wrappedFunc=instance.exports["f"];return wrappedFunc};Module["convertJsFunctionToWasm"]=convertJsFunctionToWasm;var wasmTableMirror=[];Module["wasmTableMirror"]=wasmTableMirror;var wasmTable=new WebAssembly.Table({"initial":6649,"element":"anyfunc"});Module["wasmTable"]=wasmTable;var getWasmTableEntry=funcPtr=>{var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func};Module["getWasmTableEntry"]=getWasmTableEntry;var updateTableMap=(offset,count)=>{if(functionsInTableMap){for(var i=offset;i{if(!functionsInTableMap){functionsInTableMap=new WeakMap;updateTableMap(0,wasmTable.length)}return functionsInTableMap.get(func)||0};Module["getFunctionAddress"]=getFunctionAddress;var freeTableIndexes=[];Module["freeTableIndexes"]=freeTableIndexes;var getEmptyTableSlot=()=>{if(freeTableIndexes.length){return freeTableIndexes.pop()}try{wasmTable.grow(1)}catch(err){if(!(err instanceof RangeError)){throw err}throw"Unable to grow wasm table. Set ALLOW_TABLE_GROWTH."}return wasmTable.length-1};Module["getEmptyTableSlot"]=getEmptyTableSlot;var setWasmTableEntry=(idx,func)=>{wasmTable.set(idx,func);wasmTableMirror[idx]=wasmTable.get(idx)};Module["setWasmTableEntry"]=setWasmTableEntry;var addFunction=(func,sig)=>{var rtn=getFunctionAddress(func);if(rtn){return rtn}var ret=getEmptyTableSlot();try{setWasmTableEntry(ret,func)}catch(err){if(!(err instanceof TypeError)){throw err}var wrapped=convertJsFunctionToWasm(func,sig);setWasmTableEntry(ret,wrapped)}functionsInTableMap.set(func,ret);return ret};Module["addFunction"]=addFunction;var updateGOT=(exports,replace)=>{for(var symName in exports){if(isInternalSym(symName)){continue}var value=exports[symName];GOT[symName]||=new WebAssembly.Global({"value":"i32","mutable":true});if(replace||GOT[symName].value==0){if(typeof value=="function"){GOT[symName].value=addFunction(value)}else if(typeof value=="number"){GOT[symName].value=value}else{err(`unhandled export type for '${symName}': ${typeof value}`)}}}};Module["updateGOT"]=updateGOT;var relocateExports=(exports,memoryBase,replace)=>{var relocated={};for(var e in exports){var value=exports[e];if(typeof value=="object"){value=value.value}if(typeof value=="number"){value+=memoryBase}relocated[e]=value}updateGOT(relocated,replace);return relocated};Module["relocateExports"]=relocateExports;var isSymbolDefined=symName=>{var existing=wasmImports[symName];if(!existing||existing.stub){return false}return true};Module["isSymbolDefined"]=isSymbolDefined;var dynCall=(sig,ptr,args=[])=>{var rtn=getWasmTableEntry(ptr)(...args);return sig[0]=="p"?rtn>>>0:rtn};Module["dynCall"]=dynCall;var createInvokeFunction=sig=>function(){var sp=stackSave();try{return dynCall(sig,arguments[0],Array.prototype.slice.call(arguments,1))}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);if(sig[0]=="j")return 0n}};Module["createInvokeFunction"]=createInvokeFunction;var resolveGlobalSymbol=(symName,direct=false)=>{var sym;if(isSymbolDefined(symName)){sym=wasmImports[symName]}else if(symName.startsWith("invoke_")){sym=wasmImports[symName]=Module.createInvoke(symName.split("_")[1])}else if(symName.startsWith("__cxa_find_matching_catch_")){sym=wasmImports[symName]=function(){var args=Array.from(arguments);var rtn=findMatchingCatch(args);return rtn}}return{sym:sym,name:symName}};Module["resolveGlobalSymbol"]=resolveGlobalSymbol;var loadWebAssemblyModule=(binary,flags,libName,localScope,handle)=>{var metadata=getDylinkMetadata(binary);currentModuleWeakSymbols=metadata.weakImports;function loadModule(){var firstLoad=!handle||!HEAP8[handle+8>>>0];if(firstLoad){var memAlign=Math.pow(2,metadata.memoryAlign);var memoryBase=metadata.memorySize?alignMemory(getMemory(metadata.memorySize+memAlign),memAlign):0;var tableBase=metadata.tableSize?wasmTable.length:0;if(handle){HEAP8[handle+8>>>0]=1;HEAPU32[handle+12>>>2>>>0]=memoryBase;HEAP32[handle+16>>>2>>>0]=metadata.memorySize;HEAPU32[handle+20>>>2>>>0]=tableBase;HEAP32[handle+24>>>2>>>0]=metadata.tableSize}}else{memoryBase=HEAPU32[handle+12>>>2>>>0];tableBase=HEAPU32[handle+20>>>2>>>0]}var tableGrowthNeeded=tableBase+metadata.tableSize-wasmTable.length;if(tableGrowthNeeded>0){wasmTable.grow(tableGrowthNeeded)}var moduleExports;function resolveSymbol(sym){var resolved=resolveGlobalSymbol(sym).sym;if(!resolved&&localScope){resolved=localScope[sym]}if(!resolved){resolved=moduleExports[sym]}return resolved}var proxyHandler={get(stubs,prop){switch(prop){case"__memory_base":return memoryBase;case"__table_base":return tableBase}if(prop in wasmImports&&!wasmImports[prop].stub){return wasmImports[prop]}if(!(prop in stubs)){var resolved;stubs[prop]=(...args)=>{resolved||=resolveSymbol(prop);if(!resolved){throw new Error(`Dynamic linking error: cannot resolve symbol ${prop}`)}return resolved(...args)}}return stubs[prop]}};var proxy=new Proxy({},proxyHandler);var info={"GOT.mem":new Proxy({},GOTHandler),"GOT.func":new Proxy({},GOTHandler),"env":proxy,"wasi_snapshot_preview1":proxy};function postInstantiation(module,instance){updateTableMap(tableBase,metadata.tableSize);moduleExports=relocateExports(instance.exports,memoryBase);if(!flags.allowUndefined){reportUndefinedSymbols()}function addEmAsm(addr,body){var args=[];var arity=0;for(;arity<16;arity++){if(body.indexOf("$"+arity)!=-1){args.push("$"+arity)}else{break}}args=args.join(",");var func=`(${args}) => { ${body} };`;ASM_CONSTS[start]=eval(func)}if("__start_em_asm"in moduleExports){var start=moduleExports["__start_em_asm"];var stop=moduleExports["__stop_em_asm"];while(start ${body};`;moduleExports[name]=eval(func)}for(var name in moduleExports){if(name.startsWith("__em_js__")){var start=moduleExports[name];var jsString=UTF8ToString(start);var parts=jsString.split("<::>");addEmJs(name.replace("__em_js__",""),parts[0],parts[1]);delete moduleExports[name]}}var applyRelocs=moduleExports["__wasm_apply_data_relocs"];if(applyRelocs){if(runtimeInitialized){applyRelocs()}else{__RELOC_FUNCS__.push(applyRelocs)}}var init=moduleExports["__wasm_call_ctors"];if(init){if(runtimeInitialized){init()}else{__ATINIT__.push(init)}}return moduleExports}if(flags.loadAsync){if(binary instanceof WebAssembly.Module){var instance=new WebAssembly.Instance(binary,info);return Promise.resolve(postInstantiation(binary,instance))}return WebAssembly.instantiate(binary,info).then(result=>postInstantiation(result.module,result.instance))}var module=binary instanceof WebAssembly.Module?binary:new WebAssembly.Module(binary);var instance=new WebAssembly.Instance(module,info);return postInstantiation(module,instance)}if(flags.loadAsync){return metadata.neededDynlibs.reduce((chain,dynNeeded)=>chain.then(()=>loadDynamicLibrary(dynNeeded,flags,localScope)),Promise.resolve()).then(loadModule)}metadata.neededDynlibs.forEach(needed=>loadDynamicLibrary(needed,flags,localScope));return loadModule()};Module["loadWebAssemblyModule"]=loadWebAssemblyModule;var mergeLibSymbols=(exports,libName)=>{for(var[sym,exp]of Object.entries(exports)){const setImport=target=>{if(!isSymbolDefined(target)){wasmImports[target]=exp}};setImport(sym);const main_alias="__main_argc_argv";if(sym=="main"){setImport(main_alias)}if(sym==main_alias){setImport("main")}if(sym.startsWith("dynCall_")&&!Module.hasOwnProperty(sym)){Module[sym]=exp}}};Module["mergeLibSymbols"]=mergeLibSymbols;var asyncLoad=(url,onload,onerror,noRunDep)=>{var dep=!noRunDep?getUniqueRunDependency(`al ${url}`):"";readAsync(url,arrayBuffer=>{onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},event=>{if(onerror){onerror()}else{throw`Loading data file "${url}" failed.`}});if(dep)addRunDependency(dep)};Module["asyncLoad"]=asyncLoad;var preloadPlugins=Module["preloadPlugins"]||[];Module["preloadPlugins"]=preloadPlugins;var registerWasmPlugin=()=>{var wasmPlugin={"promiseChainEnd":Promise.resolve(),"canHandle":name=>!Module.noWasmDecoding&&name.endsWith(".so"),"handle":(byteArray,name,onload,onerror)=>{wasmPlugin["promiseChainEnd"]=wasmPlugin["promiseChainEnd"].then(()=>loadWebAssemblyModule(byteArray,{loadAsync:true,nodelete:true},name,{})).then(exports=>{preloadedWasm[name]=exports;onload(byteArray)},error=>{err(`failed to instantiate wasm: ${name}: ${error}`);onerror()})}};preloadPlugins.push(wasmPlugin)};Module["registerWasmPlugin"]=registerWasmPlugin;var preloadedWasm={};Module["preloadedWasm"]=preloadedWasm;function loadDynamicLibrary(libName,flags={global:true,nodelete:true},localScope,handle){var dso=LDSO.loadedLibsByName[libName];if(dso){if(!flags.global){if(localScope){Object.assign(localScope,dso.exports)}}else if(!dso.global){dso.global=true;mergeLibSymbols(dso.exports,libName)}if(flags.nodelete&&dso.refcount!==Infinity){dso.refcount=Infinity}dso.refcount++;if(handle){LDSO.loadedLibsByHandle[handle]=dso}return flags.loadAsync?Promise.resolve(true):true}dso=newDSO(libName,handle,"loading");dso.refcount=flags.nodelete?Infinity:1;dso.global=flags.global;function loadLibData(){var libData;if(handle){var data=HEAPU32[handle+28>>>2>>>0];var dataSize=HEAPU32[handle+32>>>2>>>0];if(data&&dataSize){libData=HEAP8.slice(data,data+dataSize)}}if(!libData&&flags.fs&&flags.fs.findObject(libName)){libData=flags.fs.readFile(libName,{encoding:"binary"});if(!(libData instanceof Uint8Array)){libData=new Uint8Array(libData)}}if(libData){return flags.loadAsync?Promise.resolve(libData):libData}var libFile=locateFile(libName);if(flags.loadAsync){return new Promise(function(resolve,reject){asyncLoad(libFile,resolve,reject)})}if(!readBinary){throw new Error(`${libFile}: file not found, and synchronous loading of external files is not available`)}return readBinary(libFile)}function getExports(){var preloaded=preloadedWasm[libName];if(preloaded){return flags.loadAsync?Promise.resolve(preloaded):preloaded}if(flags.loadAsync){return loadLibData().then(libData=>loadWebAssemblyModule(libData,flags,libName,localScope,handle))}return loadWebAssemblyModule(loadLibData(),flags,libName,localScope,handle)}function moduleLoaded(exports){if(dso.global){mergeLibSymbols(exports,libName)}else if(localScope){Object.assign(localScope,exports)}dso.exports=exports}if(flags.loadAsync){return getExports().then(exports=>{moduleLoaded(exports);return true})}moduleLoaded(getExports());return true}Module["loadDynamicLibrary"]=loadDynamicLibrary;var reportUndefinedSymbols=()=>{for(var[symName,entry]of Object.entries(GOT)){if(entry.value==0){var value=resolveGlobalSymbol(symName,true).sym;if(!value&&!entry.required){continue}if(typeof value=="function"){entry.value=addFunction(value,value.sig)}else if(typeof value=="number"){entry.value=value}else{throw new Error(`bad export type for '${symName}': ${typeof value}`)}}}};Module["reportUndefinedSymbols"]=reportUndefinedSymbols;var loadDylibs=()=>{if(!dynamicLibraries.length){reportUndefinedSymbols();return}addRunDependency("loadDylibs");dynamicLibraries.reduce((chain,lib)=>chain.then(()=>loadDynamicLibrary(lib,{loadAsync:true,global:true,nodelete:true,allowUndefined:true})),Promise.resolve()).then(()=>{reportUndefinedSymbols();removeRunDependency("loadDylibs")})};Module["loadDylibs"]=loadDylibs;var noExitRuntime=Module["noExitRuntime"]||true;Module["noExitRuntime"]=noExitRuntime;function setValue(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":HEAP8[ptr>>>0]=value;break;case"i8":HEAP8[ptr>>>0]=value;break;case"i16":HEAP16[ptr>>>1>>>0]=value;break;case"i32":HEAP32[ptr>>>2>>>0]=value;break;case"i64":HEAP64[ptr>>>3]=BigInt(value);break;case"float":HEAPF32[ptr>>>2>>>0]=value;break;case"double":HEAPF64[ptr>>>3>>>0]=value;break;case"*":HEAPU32[ptr>>>2>>>0]=value;break;default:abort(`invalid type for setValue: ${type}`)}}Module["setValue"]=setValue;var MAX_INT53=9007199254740992;Module["MAX_INT53"]=MAX_INT53;var MIN_INT53=-9007199254740992;Module["MIN_INT53"]=MIN_INT53;var bigintToI53Checked=num=>numMAX_INT53?NaN:Number(num);Module["bigintToI53Checked"]=bigintToI53Checked;function ___assert_fail(condition,filename,line,func){condition>>>=0;filename>>>=0;func>>>=0;abort(`Assertion failed: ${UTF8ToString(condition)}, at: `+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])}Module["___assert_fail"]=___assert_fail;___assert_fail.sig="vppip";function ___call_sighandler(fp,sig){fp>>>=0;return getWasmTableEntry(fp)(sig)}Module["___call_sighandler"]=___call_sighandler;___call_sighandler.sig="vpi";var exceptionCaught=[];Module["exceptionCaught"]=exceptionCaught;var uncaughtExceptionCount=0;Module["uncaughtExceptionCount"]=uncaughtExceptionCount;function ___cxa_begin_catch(ptr){ptr>>>=0;var info=new ExceptionInfo(ptr);if(!info.get_caught()){info.set_caught(true);uncaughtExceptionCount--}info.set_rethrown(false);exceptionCaught.push(info);___cxa_increment_exception_refcount(info.excPtr);return info.get_exception_ptr()}Module["___cxa_begin_catch"]=___cxa_begin_catch;___cxa_begin_catch.sig="pp";function ___cxa_current_primary_exception(){if(!exceptionCaught.length){return 0}var info=exceptionCaught[exceptionCaught.length-1];___cxa_increment_exception_refcount(info.excPtr);return info.excPtr}Module["___cxa_current_primary_exception"]=___cxa_current_primary_exception;___cxa_current_primary_exception.sig="p";var exceptionLast=0;Module["exceptionLast"]=exceptionLast;var ___cxa_end_catch=()=>{_setThrew(0,0);var info=exceptionCaught.pop();___cxa_decrement_exception_refcount(info.excPtr);exceptionLast=0};Module["___cxa_end_catch"]=___cxa_end_catch;___cxa_end_catch.sig="v";class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){HEAPU32[this.ptr+4>>>2>>>0]=type}get_type(){return HEAPU32[this.ptr+4>>>2>>>0]}set_destructor(destructor){HEAPU32[this.ptr+8>>>2>>>0]=destructor}get_destructor(){return HEAPU32[this.ptr+8>>>2>>>0]}set_caught(caught){caught=caught?1:0;HEAP8[this.ptr+12>>>0]=caught}get_caught(){return HEAP8[this.ptr+12>>>0]!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13>>>0]=rethrown}get_rethrown(){return HEAP8[this.ptr+13>>>0]!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){HEAPU32[this.ptr+16>>>2>>>0]=adjustedPtr}get_adjusted_ptr(){return HEAPU32[this.ptr+16>>>2>>>0]}get_exception_ptr(){var isPointer=___cxa_is_pointer_type(this.get_type());if(isPointer){return HEAPU32[this.excPtr>>>2>>>0]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.excPtr}}Module["ExceptionInfo"]=ExceptionInfo;function ___resumeException(ptr){ptr>>>=0;if(!exceptionLast){exceptionLast=ptr}throw Module.wrapException(exceptionLast)}Module["___resumeException"]=___resumeException;___resumeException.sig="vp";var setTempRet0=val=>__emscripten_tempret_set(val);Module["setTempRet0"]=setTempRet0;var findMatchingCatch=args=>{var thrown=exceptionLast;if(!thrown){setTempRet0(0);return 0}var info=new ExceptionInfo(thrown);info.set_adjusted_ptr(thrown);var thrownType=info.get_type();if(!thrownType){setTempRet0(0);return thrown}for(var arg in args){var caughtType=args[arg];if(caughtType===0||caughtType===thrownType){break}var adjusted_ptr_addr=info.ptr+16;if(___cxa_can_catch(caughtType,thrownType,adjusted_ptr_addr)){setTempRet0(caughtType);return thrown}}setTempRet0(thrownType);return thrown};Module["findMatchingCatch"]=findMatchingCatch;function ___cxa_find_matching_catch_2(){return findMatchingCatch([])}Module["___cxa_find_matching_catch_2"]=___cxa_find_matching_catch_2;___cxa_find_matching_catch_2.sig="p";function ___cxa_find_matching_catch_3(arg0){arg0>>>=0;return findMatchingCatch([arg0])}Module["___cxa_find_matching_catch_3"]=___cxa_find_matching_catch_3;___cxa_find_matching_catch_3.sig="pp";var ___cxa_rethrow=()=>{var info=exceptionCaught.pop();if(!info){abort("no exception to throw")}var ptr=info.excPtr;if(!info.get_rethrown()){exceptionCaught.push(info);info.set_rethrown(true);info.set_caught(false);uncaughtExceptionCount++}exceptionLast=ptr;throw Module.wrapException(exceptionLast)};Module["___cxa_rethrow"]=___cxa_rethrow;___cxa_rethrow.sig="v";function ___cxa_rethrow_primary_exception(ptr){ptr>>>=0;if(!ptr)return;var info=new ExceptionInfo(ptr);exceptionCaught.push(info);info.set_rethrown(true);___cxa_rethrow()}Module["___cxa_rethrow_primary_exception"]=___cxa_rethrow_primary_exception;___cxa_rethrow_primary_exception.sig="vp";function ___cxa_throw(ptr,type,destructor){ptr>>>=0;type>>>=0;destructor>>>=0;var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw Module.wrapException(exceptionLast)}Module["___cxa_throw"]=___cxa_throw;___cxa_throw.sig="vppp";var ___cxa_uncaught_exceptions=()=>uncaughtExceptionCount;Module["___cxa_uncaught_exceptions"]=___cxa_uncaught_exceptions;___cxa_uncaught_exceptions.sig="i";var ___memory_base=new WebAssembly.Global({"value":"i32","mutable":false},1024);Module["___memory_base"]=___memory_base;var ___stack_high=9883824;Module["___stack_high"]=___stack_high;var ___stack_low=4640944;Module["___stack_low"]=___stack_low;var ___stack_pointer=new WebAssembly.Global({"value":"i32","mutable":true},9883824);Module["___stack_pointer"]=___stack_pointer;var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:(...paths)=>PATH.normalize(paths.join("/")),join2:(l,r)=>PATH.normalize(l+"/"+r)};Module["PATH"]=PATH;var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require("crypto");var randomFillSync=crypto_module["randomFillSync"];if(randomFillSync){return view=>crypto_module["randomFillSync"](view)}var randomBytes=crypto_module["randomBytes"];return view=>(view.set(randomBytes(view.byteLength)),view)}catch(e){}}abort("initRandomDevice")};Module["initRandomFill"]=initRandomFill;var randomFill=view=>(randomFill=initRandomFill())(view);Module["randomFill"]=randomFill;var PATH_FS={resolve:(...args)=>{var resolvedPath="",resolvedAbsolute=false;for(var i=args.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?args[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};Module["lengthBytesUTF8"]=lengthBytesUTF8;var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{outIdx>>>=0;if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++>>>0]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++>>>0]=192|u>>6;heap[outIdx++>>>0]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++>>>0]=224|u>>12;heap[outIdx++>>>0]=128|u>>6&63;heap[outIdx++>>>0]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++>>>0]=240|u>>18;heap[outIdx++>>>0]=128|u>>12&63;heap[outIdx++>>>0]=128|u>>6&63;heap[outIdx++>>>0]=128|u&63}}heap[outIdx>>>0]=0;return outIdx-startIdx};Module["stringToUTF8Array"]=stringToUTF8Array;function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}Module["intArrayFromString"]=intArrayFromString;var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(ENVIRONMENT_IS_NODE){var BUFSIZE=256;var buf=Buffer.alloc(BUFSIZE);var bytesRead=0;var fd=process.stdin.fd;try{bytesRead=fs.readSync(fd,buf)}catch(e){if(e.toString().includes("EOF"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};Module["FS_stdin_getChar"]=FS_stdin_getChar;var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};Module["TTY"]=TTY;var mmapAlloc=size=>{size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(!ptr)return 0;return zeroMemory(ptr,size)};Module["mmapAlloc"]=mmapAlloc;var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){throw FS.genericErrors[44]},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;old_node.parent=new_dir},unlink(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},readdir(node){var entries=[".",".."];for(var key of Object.keys(node.contents)){entries.push(key)}return entries},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length>>0)}return{ptr:ptr,allocated:allocated}},msync(stream,buffer,offset,length,mmapFlags){MEMFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};Module["MEMFS"]=MEMFS;var FS_createDataFile=(parent,name,fileData,canRead,canWrite,canOwn)=>{FS.createDataFile(parent,name,fileData,canRead,canWrite,canOwn)};Module["FS_createDataFile"]=FS_createDataFile;var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled};Module["FS_handledByPreloadPlugin"]=FS_handledByPreloadPlugin;var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}onload?.();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{onerror?.();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,processData,onerror)}else{processData(url)}};Module["FS_createPreloadedFile"]=FS_createPreloadedFile;var FS_modeStringToFlags=str=>{var flagModes={"r":0,"r+":2,"w":512|64|1,"w+":512|64|2,"a":1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};Module["FS_modeStringToFlags"]=FS_modeStringToFlags;var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};Module["FS_getMode"]=FS_getMode;var IDBFS={dbs:{},indexedDB:()=>{if(typeof indexedDB!="undefined")return indexedDB;var ret=null;if(typeof window=="object")ret=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB;return ret},DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:(...args)=>MEMFS.mount(...args),syncfs:(mount,populate,callback)=>{IDBFS.getLocalSet(mount,(err,local)=>{if(err)return callback(err);IDBFS.getRemoteSet(mount,(err,remote)=>{if(err)return callback(err);var src=populate?remote:local;var dst=populate?local:remote;IDBFS.reconcile(src,dst,callback)})})},quit:()=>{Object.values(IDBFS.dbs).forEach(value=>value.close());IDBFS.dbs={}},getDB:(name,callback)=>{var db=IDBFS.dbs[name];if(db){return callback(null,db)}var req;try{req=IDBFS.indexedDB().open(name,IDBFS.DB_VERSION)}catch(e){return callback(e)}if(!req){return callback("Unable to connect to IndexedDB")}req.onupgradeneeded=e=>{var db=e.target.result;var transaction=e.target.transaction;var fileStore;if(db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)){fileStore=transaction.objectStore(IDBFS.DB_STORE_NAME)}else{fileStore=db.createObjectStore(IDBFS.DB_STORE_NAME)}if(!fileStore.indexNames.contains("timestamp")){fileStore.createIndex("timestamp","timestamp",{unique:false})}};req.onsuccess=()=>{db=req.result;IDBFS.dbs[name]=db;callback(null,db)};req.onerror=e=>{callback(e.target.error);e.preventDefault()}},getLocalSet:(mount,callback)=>{var entries={};function isRealDir(p){return p!=="."&&p!==".."}function toAbsolute(root){return p=>PATH.join2(root,p)}var check=FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));while(check.length){var path=check.pop();var stat;try{stat=FS.stat(path)}catch(e){return callback(e)}if(FS.isDir(stat.mode)){check.push(...FS.readdir(path).filter(isRealDir).map(toAbsolute(path)))}entries[path]={"timestamp":stat.mtime}}return callback(null,{type:"local",entries:entries})},getRemoteSet:(mount,callback)=>{var entries={};IDBFS.getDB(mount.mountpoint,(err,db)=>{if(err)return callback(err);try{var transaction=db.transaction([IDBFS.DB_STORE_NAME],"readonly");transaction.onerror=e=>{callback(e.target.error);e.preventDefault()};var store=transaction.objectStore(IDBFS.DB_STORE_NAME);var index=store.index("timestamp");index.openKeyCursor().onsuccess=event=>{var cursor=event.target.result;if(!cursor){return callback(null,{type:"remote",db:db,entries:entries})}entries[cursor.primaryKey]={"timestamp":cursor.key};cursor.continue()}}catch(e){return callback(e)}})},loadLocalEntry:(path,callback)=>{var stat,node;try{var lookup=FS.lookupPath(path);node=lookup.node;stat=FS.stat(path)}catch(e){return callback(e)}if(FS.isDir(stat.mode)){return callback(null,{"timestamp":stat.mtime,"mode":stat.mode})}else if(FS.isFile(stat.mode)){node.contents=MEMFS.getFileDataAsTypedArray(node);return callback(null,{"timestamp":stat.mtime,"mode":stat.mode,"contents":node.contents})}else{return callback(new Error("node type not supported"))}},storeLocalEntry:(path,entry,callback)=>{try{if(FS.isDir(entry["mode"])){FS.mkdirTree(path,entry["mode"])}else if(FS.isFile(entry["mode"])){FS.writeFile(path,entry["contents"],{canOwn:true})}else{return callback(new Error("node type not supported"))}FS.chmod(path,entry["mode"]);FS.utime(path,entry["timestamp"],entry["timestamp"])}catch(e){return callback(e)}callback(null)},removeLocalEntry:(path,callback)=>{try{var stat=FS.stat(path);if(FS.isDir(stat.mode)){FS.rmdir(path)}else if(FS.isFile(stat.mode)){FS.unlink(path)}}catch(e){return callback(e)}callback(null)},loadRemoteEntry:(store,path,callback)=>{var req=store.get(path);req.onsuccess=event=>callback(null,event.target.result);req.onerror=e=>{callback(e.target.error);e.preventDefault()}},storeRemoteEntry:(store,path,entry,callback)=>{try{var req=store.put(entry,path)}catch(e){callback(e);return}req.onsuccess=event=>callback();req.onerror=e=>{callback(e.target.error);e.preventDefault()}},removeRemoteEntry:(store,path,callback)=>{var req=store.delete(path);req.onsuccess=event=>callback();req.onerror=e=>{callback(e.target.error);e.preventDefault()}},reconcile:(src,dst,callback)=>{var total=0;var create=[];Object.keys(src.entries).forEach(function(key){var e=src.entries[key];var e2=dst.entries[key];if(!e2||e["timestamp"].getTime()!=e2["timestamp"].getTime()){create.push(key);total++}});var remove=[];Object.keys(dst.entries).forEach(function(key){if(!src.entries[key]){remove.push(key);total++}});if(!total){return callback(null)}var errored=false;var db=src.type==="remote"?src.db:dst.db;var transaction=db.transaction([IDBFS.DB_STORE_NAME],"readwrite");var store=transaction.objectStore(IDBFS.DB_STORE_NAME);function done(err){if(err&&!errored){errored=true;return callback(err)}}transaction.onerror=transaction.onabort=e=>{done(e.target.error);e.preventDefault()};transaction.oncomplete=e=>{if(!errored){callback(null)}};create.sort().forEach(path=>{if(dst.type==="local"){IDBFS.loadRemoteEntry(store,path,(err,entry)=>{if(err)return done(err);IDBFS.storeLocalEntry(path,entry,done)})}else{IDBFS.loadLocalEntry(path,(err,entry)=>{if(err)return done(err);IDBFS.storeRemoteEntry(store,path,entry,done)})}});remove.sort().reverse().forEach(path=>{if(dst.type==="local"){IDBFS.removeLocalEntry(path,done)}else{IDBFS.removeRemoteEntry(store,path,done)}})}};Module["IDBFS"]=IDBFS;var ERRNO_CODES={"EPERM":63,"ENOENT":44,"ESRCH":71,"EINTR":27,"EIO":29,"ENXIO":60,"E2BIG":1,"ENOEXEC":45,"EBADF":8,"ECHILD":12,"EAGAIN":6,"EWOULDBLOCK":6,"ENOMEM":48,"EACCES":2,"EFAULT":21,"ENOTBLK":105,"EBUSY":10,"EEXIST":20,"EXDEV":75,"ENODEV":43,"ENOTDIR":54,"EISDIR":31,"EINVAL":28,"ENFILE":41,"EMFILE":33,"ENOTTY":59,"ETXTBSY":74,"EFBIG":22,"ENOSPC":51,"ESPIPE":70,"EROFS":69,"EMLINK":34,"EPIPE":64,"EDOM":18,"ERANGE":68,"ENOMSG":49,"EIDRM":24,"ECHRNG":106,"EL2NSYNC":156,"EL3HLT":107,"EL3RST":108,"ELNRNG":109,"EUNATCH":110,"ENOCSI":111,"EL2HLT":112,"EDEADLK":16,"ENOLCK":46,"EBADE":113,"EBADR":114,"EXFULL":115,"ENOANO":104,"EBADRQC":103,"EBADSLT":102,"EDEADLOCK":16,"EBFONT":101,"ENOSTR":100,"ENODATA":116,"ETIME":117,"ENOSR":118,"ENONET":119,"ENOPKG":120,"EREMOTE":121,"ENOLINK":47,"EADV":122,"ESRMNT":123,"ECOMM":124,"EPROTO":65,"EMULTIHOP":36,"EDOTDOT":125,"EBADMSG":9,"ENOTUNIQ":126,"EBADFD":127,"EREMCHG":128,"ELIBACC":129,"ELIBBAD":130,"ELIBSCN":131,"ELIBMAX":132,"ELIBEXEC":133,"ENOSYS":52,"ENOTEMPTY":55,"ENAMETOOLONG":37,"ELOOP":32,"EOPNOTSUPP":138,"EPFNOSUPPORT":139,"ECONNRESET":15,"ENOBUFS":42,"EAFNOSUPPORT":5,"EPROTOTYPE":67,"ENOTSOCK":57,"ENOPROTOOPT":50,"ESHUTDOWN":140,"ECONNREFUSED":14,"EADDRINUSE":3,"ECONNABORTED":13,"ENETUNREACH":40,"ENETDOWN":38,"ETIMEDOUT":73,"EHOSTDOWN":142,"EHOSTUNREACH":23,"EINPROGRESS":26,"EALREADY":7,"EDESTADDRREQ":17,"EMSGSIZE":35,"EPROTONOSUPPORT":66,"ESOCKTNOSUPPORT":137,"EADDRNOTAVAIL":4,"ENETRESET":39,"EISCONN":30,"ENOTCONN":53,"ETOOMANYREFS":141,"EUSERS":136,"EDQUOT":19,"ESTALE":72,"ENOTSUP":138,"ENOMEDIUM":148,"EILSEQ":25,"EOVERFLOW":61,"ECANCELED":11,"ENOTRECOVERABLE":56,"EOWNERDEAD":62,"ESTRPIPE":135};Module["ERRNO_CODES"]=ERRNO_CODES;var NODEFS={isWindows:false,staticInit(){NODEFS.isWindows=!!process.platform.match(/^win/);var flags=process.binding("constants");if(flags["fs"]){flags=flags["fs"]}NODEFS.flagsForNodeMap={1024:flags["O_APPEND"],64:flags["O_CREAT"],128:flags["O_EXCL"],256:flags["O_NOCTTY"],0:flags["O_RDONLY"],2:flags["O_RDWR"],4096:flags["O_SYNC"],512:flags["O_TRUNC"],1:flags["O_WRONLY"],131072:flags["O_NOFOLLOW"]}},convertNodeCode(e){var code=e.code;return ERRNO_CODES[code]},mount(mount){return NODEFS.createNode(null,"/",NODEFS.getMode(mount.opts.root),0)},createNode(parent,name,mode,dev){if(!FS.isDir(mode)&&!FS.isFile(mode)&&!FS.isLink(mode)){throw new FS.ErrnoError(28)}var node=FS.createNode(parent,name,mode);node.node_ops=NODEFS.node_ops;node.stream_ops=NODEFS.stream_ops;return node},getMode(path){var stat;try{stat=fs.lstatSync(path);if(NODEFS.isWindows){stat.mode=stat.mode|(stat.mode&292)>>2}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}return stat.mode},realPath(node){var parts=[];while(node.parent!==node){parts.push(node.name);node=node.parent}parts.push(node.mount.opts.root);parts.reverse();return PATH.join(...parts)},flagsForNode(flags){flags&=~2097152;flags&=~2048;flags&=~32768;flags&=~524288;flags&=~65536;var newFlags=0;for(var k in NODEFS.flagsForNodeMap){if(flags&k){newFlags|=NODEFS.flagsForNodeMap[k];flags^=k}}if(flags){throw new FS.ErrnoError(28)}return newFlags},node_ops:{getattr(node){var path=NODEFS.realPath(node);var stat;try{stat=fs.lstatSync(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}if(NODEFS.isWindows&&!stat.blksize){stat.blksize=4096}if(NODEFS.isWindows&&!stat.blocks){stat.blocks=(stat.size+stat.blksize-1)/stat.blksize|0}return{dev:stat.dev,ino:stat.ino,mode:stat.mode,nlink:stat.nlink,uid:stat.uid,gid:stat.gid,rdev:stat.rdev,size:stat.size,atime:stat.atime,mtime:stat.mtime,ctime:stat.ctime,blksize:stat.blksize,blocks:stat.blocks}},setattr(node,attr){var path=NODEFS.realPath(node);try{if(attr.mode!==undefined){fs.chmodSync(path,attr.mode);node.mode=attr.mode}if(attr.timestamp!==undefined){var date=new Date(attr.timestamp);fs.utimesSync(path,date,date)}if(attr.size!==undefined){fs.truncateSync(path,attr.size)}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},lookup(parent,name){var path=PATH.join2(NODEFS.realPath(parent),name);var mode=NODEFS.getMode(path);return NODEFS.createNode(parent,name,mode)},mknod(parent,name,mode,dev){var node=NODEFS.createNode(parent,name,mode,dev);var path=NODEFS.realPath(node);try{if(FS.isDir(node.mode)){fs.mkdirSync(path,node.mode)}else{fs.writeFileSync(path,"",{mode:node.mode})}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}return node},rename(oldNode,newDir,newName){var oldPath=NODEFS.realPath(oldNode);var newPath=PATH.join2(NODEFS.realPath(newDir),newName);try{fs.renameSync(oldPath,newPath)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}oldNode.name=newName},unlink(parent,name){var path=PATH.join2(NODEFS.realPath(parent),name);try{fs.unlinkSync(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},rmdir(parent,name){var path=PATH.join2(NODEFS.realPath(parent),name);try{fs.rmdirSync(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},readdir(node){var path=NODEFS.realPath(node);try{return fs.readdirSync(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},symlink(parent,newName,oldPath){var newPath=PATH.join2(NODEFS.realPath(parent),newName);try{fs.symlinkSync(oldPath,newPath)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},readlink(node){var path=NODEFS.realPath(node);try{path=fs.readlinkSync(path);path=nodePath.relative(nodePath.resolve(node.mount.opts.root),path);return path}catch(e){if(!e.code)throw e;if(e.code==="UNKNOWN")throw new FS.ErrnoError(28);throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}}},stream_ops:{open(stream){var path=NODEFS.realPath(stream.node);try{if(FS.isFile(stream.node.mode)){stream.shared.refcount=1;stream.nfd=fs.openSync(path,NODEFS.flagsForNode(stream.flags))}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},close(stream){try{if(FS.isFile(stream.node.mode)&&stream.nfd&&--stream.shared.refcount===0){fs.closeSync(stream.nfd)}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},dup(stream){stream.shared.refcount++},read(stream,buffer,offset,length,position){if(length===0)return 0;try{return fs.readSync(stream.nfd,new Int8Array(buffer.buffer,offset,length),{position:position})}catch(e){throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},write(stream,buffer,offset,length,position){try{return fs.writeSync(stream.nfd,new Int8Array(buffer.buffer,offset,length),{position:position})}catch(e){throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},llseek(stream,offset,whence){var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){try{var stat=fs.fstatSync(stream.nfd);position+=stat.size}catch(e){throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}}}if(position<0){throw new FS.ErrnoError(28)}return position},mmap(stream,length,position,prot,flags){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}var ptr=mmapAlloc(length);NODEFS.stream_ops.read(stream,HEAP8,ptr,length,position);return{ptr:ptr,allocated:true}},msync(stream,buffer,offset,length,mmapFlags){NODEFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};Module["NODEFS"]=NODEFS;var WORKERFS={DIR_MODE:16895,FILE_MODE:33279,reader:null,mount(mount){assert(ENVIRONMENT_IS_WORKER);if(!WORKERFS.reader)WORKERFS.reader=new FileReaderSync;var root=WORKERFS.createNode(null,"/",WORKERFS.DIR_MODE,0);var createdParents={};function ensureParent(path){var parts=path.split("/");var parent=root;for(var i=0;i=stream.node.size)return 0;var chunk=stream.node.contents.slice(position,position+length);var ab=WORKERFS.reader.readAsArrayBuffer(chunk);buffer.set(new Uint8Array(ab),offset);return chunk.size},write(stream,buffer,offset,length,position){throw new FS.ErrnoError(29)},llseek(stream,offset,whence){var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){position+=stream.node.size}}if(position<0){throw new FS.ErrnoError(28)}return position}}};Module["WORKERFS"]=WORKERFS;var PROXYFS={mount(mount){return PROXYFS.createNode(null,"/",mount.opts.fs.lstat(mount.opts.root).mode,0)},createNode(parent,name,mode,dev){if(!FS.isDir(mode)&&!FS.isFile(mode)&&!FS.isLink(mode)){throw new FS.ErrnoError(ERRNO_CODES.EINVAL)}var node=FS.createNode(parent,name,mode);node.node_ops=PROXYFS.node_ops;node.stream_ops=PROXYFS.stream_ops;return node},realPath(node){var parts=[];while(node.parent!==node){parts.push(node.name);node=node.parent}parts.push(node.mount.opts.root);parts.reverse();return PATH.join(...parts)},node_ops:{getattr(node){var path=PROXYFS.realPath(node);var stat;try{stat=node.mount.opts.fs.lstat(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}return{dev:stat.dev,ino:stat.ino,mode:stat.mode,nlink:stat.nlink,uid:stat.uid,gid:stat.gid,rdev:stat.rdev,size:stat.size,atime:stat.atime,mtime:stat.mtime,ctime:stat.ctime,blksize:stat.blksize,blocks:stat.blocks}},setattr(node,attr){var path=PROXYFS.realPath(node);try{if(attr.mode!==undefined){node.mount.opts.fs.chmod(path,attr.mode);node.mode=attr.mode}if(attr.timestamp!==undefined){var date=new Date(attr.timestamp);node.mount.opts.fs.utime(path,date,date)}if(attr.size!==undefined){node.mount.opts.fs.truncate(path,attr.size)}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},lookup(parent,name){try{var path=PATH.join2(PROXYFS.realPath(parent),name);var mode=parent.mount.opts.fs.lstat(path).mode;var node=PROXYFS.createNode(parent,name,mode);return node}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},mknod(parent,name,mode,dev){var node=PROXYFS.createNode(parent,name,mode,dev);var path=PROXYFS.realPath(node);try{if(FS.isDir(node.mode)){node.mount.opts.fs.mkdir(path,node.mode)}else{node.mount.opts.fs.writeFile(path,"",{mode:node.mode})}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}return node},rename(oldNode,newDir,newName){var oldPath=PROXYFS.realPath(oldNode);var newPath=PATH.join2(PROXYFS.realPath(newDir),newName);try{oldNode.mount.opts.fs.rename(oldPath,newPath);oldNode.name=newName;oldNode.parent=newDir}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},unlink(parent,name){var path=PATH.join2(PROXYFS.realPath(parent),name);try{parent.mount.opts.fs.unlink(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},rmdir(parent,name){var path=PATH.join2(PROXYFS.realPath(parent),name);try{parent.mount.opts.fs.rmdir(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},readdir(node){var path=PROXYFS.realPath(node);try{return node.mount.opts.fs.readdir(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},symlink(parent,newName,oldPath){var newPath=PATH.join2(PROXYFS.realPath(parent),newName);try{parent.mount.opts.fs.symlink(oldPath,newPath)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},readlink(node){var path=PROXYFS.realPath(node);try{return node.mount.opts.fs.readlink(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}}},stream_ops:{open(stream){var path=PROXYFS.realPath(stream.node);try{stream.nfd=stream.node.mount.opts.fs.open(path,stream.flags)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},close(stream){try{stream.node.mount.opts.fs.close(stream.nfd)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},read(stream,buffer,offset,length,position){try{return stream.node.mount.opts.fs.read(stream.nfd,buffer,offset,length,position)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},write(stream,buffer,offset,length,position){try{return stream.node.mount.opts.fs.write(stream.nfd,buffer,offset,length,position)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},llseek(stream,offset,whence){var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){try{var stat=stream.node.node_ops.getattr(stream.node);position+=stat.size}catch(e){throw new FS.ErrnoError(ERRNO_CODES[e.code])}}}if(position<0){throw new FS.ErrnoError(ERRNO_CODES.EINVAL)}return position}}};Module["PROXYFS"]=PROXYFS;var LZ4={DIR_MODE:16895,FILE_MODE:33279,CHUNK_SIZE:-1,codec:null,init(){if(LZ4.codec)return;LZ4.codec=function(){var MiniLZ4=function(){var exports={};exports.uncompress=function(input,output,sIdx,eIdx){sIdx=sIdx||0;eIdx=eIdx||input.length-sIdx;for(var i=sIdx,n=eIdx,j=0;i>4;if(literals_length>0){var l=literals_length+240;while(l===255){l=input[i++];literals_length+=l}var end=i+literals_length;while(ij)return-(i-2);var match_length=token&15;var l=match_length+240;while(l===255){l=input[i++];match_length+=l}var pos=j-offset;var end=j+match_length+4;while(jmaxInputSize?0:isize+isize/255+16|0};exports.compress=function(src,dst,sIdx,eIdx){hashTable.set(empty);return compressBlock(src,dst,0,sIdx||0,eIdx||dst.length)};function compressBlock(src,dst,pos,sIdx,eIdx){var dpos=sIdx;var dlen=eIdx-sIdx;var anchor=0;if(src.length>=maxInputSize)throw new Error("input too large");if(src.length>mfLimit){var n=exports.compressBound(src.length);if(dlen>>hashShift;var ref=hashTable[hash]-1;hashTable[hash]=pos+1;if(ref<0||pos-ref>>>16>0||((src[ref+3]<<8|src[ref+2])!=sequenceHighBits||(src[ref+1]<<8|src[ref])!=sequenceLowBits)){step=findMatchAttempts++>>skipStrength;pos+=step;continue}findMatchAttempts=(1<=runMask){dst[dpos++]=(runMask<254;len-=255){dst[dpos++]=255}dst[dpos++]=len}else{dst[dpos++]=(literals_length<>8;if(match_length>=mlMask){match_length-=mlMask;while(match_length>=255){match_length-=255;dst[dpos++]=255}dst[dpos++]=match_length}anchor=pos}}if(anchor==0)return 0;literals_length=src.length-anchor;if(literals_length>=runMask){dst[dpos++]=runMask<254;ln-=255){dst[dpos++]=255}dst[dpos++]=ln}else{dst[dpos++]=literals_length<0){assert(compressedSize<=bound);compressed=compressed.subarray(0,compressedSize);compressedChunks.push(compressed);total+=compressedSize;successes.push(1);if(verify){var back=exports.uncompress(compressed,temp);assert(back===chunk.length,[back,chunk.length]);for(var i=0;i{var dir=PATH.dirname(file.filename);var name=PATH.basename(file.filename);FS.createPath("",dir,true,true);var parent=FS.analyzePath(dir).object;LZ4.createNode(parent,name,LZ4.FILE_MODE,0,{compressedData:compressedData,start:file.start,end:file.end})});if(preloadPlugin){Browser.init();pack["metadata"].files.forEach(file=>{var handled=false;var fullname=file.filename;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){var dep=getUniqueRunDependency("fp "+fullname);addRunDependency(dep);var finish=()=>removeRunDependency(dep);var byteArray=FS.readFile(fullname);plugin["handle"](byteArray,fullname,finish,finish);handled=true}})})}},createNode(parent,name,mode,dev,contents,mtime){var node=FS.createNode(parent,name,mode);node.mode=mode;node.node_ops=LZ4.node_ops;node.stream_ops=LZ4.stream_ops;node.timestamp=(mtime||new Date).getTime();assert(LZ4.FILE_MODE!==LZ4.DIR_MODE);if(mode===LZ4.FILE_MODE){node.size=contents.end-contents.start;node.contents=contents}else{node.size=4096;node.contents={}}if(parent){parent.contents[name]=node}return node},node_ops:{getattr(node){return{dev:1,ino:node.id,mode:node.mode,nlink:1,uid:0,gid:0,rdev:0,size:node.size,atime:new Date(node.timestamp),mtime:new Date(node.timestamp),ctime:new Date(node.timestamp),blksize:4096,blocks:Math.ceil(node.size/4096)}},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}},lookup(parent,name){throw new FS.ErrnoError(44)},mknod(parent,name,mode,dev){throw new FS.ErrnoError(63)},rename(oldNode,newDir,newName){throw new FS.ErrnoError(63)},unlink(parent,name){throw new FS.ErrnoError(63)},rmdir(parent,name){throw new FS.ErrnoError(63)},readdir(node){throw new FS.ErrnoError(63)},symlink(parent,newName,oldPath){throw new FS.ErrnoError(63)}},stream_ops:{read(stream,buffer,offset,length,position){length=Math.min(length,stream.node.size-position);if(length<=0)return 0;var contents=stream.node.contents;var compressedData=contents.compressedData;var written=0;while(written=0){currChunk=compressedData["cachedChunks"][found]}else{compressedData["cachedIndexes"].pop();compressedData["cachedIndexes"].unshift(chunkIndex);currChunk=compressedData["cachedChunks"].pop();compressedData["cachedChunks"].unshift(currChunk);if(compressedData["debug"]){out("decompressing chunk "+chunkIndex);Module["decompressedChunks"]=(Module["decompressedChunks"]||0)+1}var compressed=compressedData["data"].subarray(compressedStart,compressedStart+compressedSize);var originalSize=LZ4.codec.uncompress(compressed,currChunk);if(chunkIndex8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent}},hashName(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){if(!FS.isDir(dir.mode))return 54;var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},dupStream(origStream,fd=-1){var stream=FS.createStream(origStream,fd);stream.stream_ops?.dup?.(stream);return stream},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream)},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push(...m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;if(FS.trackingDelegate["onMakeDirectory"]){FS.trackingDelegate["onMakeDirectory"](path,mode)}return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;iFS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length,llseek:()=>0});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams(){if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"])}else{FS.symlink("/dev/tty","/dev/stdin")}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"])}else{FS.symlink("/dev/tty","/dev/stdout")}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"])}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},staticInit(){[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=""});FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={"MEMFS":MEMFS,"IDBFS":IDBFS,"NODEFS":NODEFS,"WORKERFS":WORKERFS,"PROXYFS":PROXYFS}},init(input,output,error){FS.init.initialized=true;Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams()},quit(){FS.init.initialized=false;_fflush(0);for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]}setDataGetter(getter){this.getter=getter}cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true}get length(){if(!this.lengthKnown){this.cacheLength()}return this._length}get chunkSize(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=(...args)=>{FS.forceLoadFile(node);return fn(...args)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node}};Module["FS"]=FS;var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat(func,path,buf){var stat=func(path);HEAP32[buf>>>2>>>0]=stat.dev;HEAP32[buf+4>>>2>>>0]=stat.mode;HEAPU32[buf+8>>>2>>>0]=stat.nlink;HEAP32[buf+12>>>2>>>0]=stat.uid;HEAP32[buf+16>>>2>>>0]=stat.gid;HEAP32[buf+20>>>2>>>0]=stat.rdev;HEAP64[buf+24>>>3]=BigInt(stat.size);HEAP32[buf+32>>>2>>>0]=4096;HEAP32[buf+36>>>2>>>0]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();HEAP64[buf+40>>>3]=BigInt(Math.floor(atime/1e3));HEAPU32[buf+48>>>2>>>0]=atime%1e3*1e3;HEAP64[buf+56>>>3]=BigInt(Math.floor(mtime/1e3));HEAPU32[buf+64>>>2>>>0]=mtime%1e3*1e3;HEAP64[buf+72>>>3]=BigInt(Math.floor(ctime/1e3));HEAPU32[buf+80>>>2>>>0]=ctime%1e3*1e3;HEAP64[buf+88>>>3]=BigInt(stat.ino);return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream},varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};Module["SYSCALLS"]=SYSCALLS;function ___syscall__newselect(nfds,readfds,writefds,exceptfds,timeout){readfds>>>=0;writefds>>>=0;exceptfds>>>=0;timeout>>>=0;try{var total=0;var srcReadLow=readfds?HEAP32[readfds>>>2>>>0]:0,srcReadHigh=readfds?HEAP32[readfds+4>>>2>>>0]:0;var srcWriteLow=writefds?HEAP32[writefds>>>2>>>0]:0,srcWriteHigh=writefds?HEAP32[writefds+4>>>2>>>0]:0;var srcExceptLow=exceptfds?HEAP32[exceptfds>>>2>>>0]:0,srcExceptHigh=exceptfds?HEAP32[exceptfds+4>>>2>>>0]:0;var dstReadLow=0,dstReadHigh=0;var dstWriteLow=0,dstWriteHigh=0;var dstExceptLow=0,dstExceptHigh=0;var allLow=(readfds?HEAP32[readfds>>>2>>>0]:0)|(writefds?HEAP32[writefds>>>2>>>0]:0)|(exceptfds?HEAP32[exceptfds>>>2>>>0]:0);var allHigh=(readfds?HEAP32[readfds+4>>>2>>>0]:0)|(writefds?HEAP32[writefds+4>>>2>>>0]:0)|(exceptfds?HEAP32[exceptfds+4>>>2>>>0]:0);var check=function(fd,low,high,val){return fd<32?low&val:high&val};for(var fd=0;fd>>2>>>0]:0,tv_usec=readfds?HEAP32[timeout+4>>>2>>>0]:0;timeoutInMillis=(tv_sec+tv_usec/1e6)*1e3}flags=stream.stream_ops.poll(stream,timeoutInMillis)}if(flags&1&&check(fd,srcReadLow,srcReadHigh,mask)){fd<32?dstReadLow=dstReadLow|mask:dstReadHigh=dstReadHigh|mask;total++}if(flags&4&&check(fd,srcWriteLow,srcWriteHigh,mask)){fd<32?dstWriteLow=dstWriteLow|mask:dstWriteHigh=dstWriteHigh|mask;total++}if(flags&2&&check(fd,srcExceptLow,srcExceptHigh,mask)){fd<32?dstExceptLow=dstExceptLow|mask:dstExceptHigh=dstExceptHigh|mask;total++}}if(readfds){HEAP32[readfds>>>2>>>0]=dstReadLow;HEAP32[readfds+4>>>2>>>0]=dstReadHigh}if(writefds){HEAP32[writefds>>>2>>>0]=dstWriteLow;HEAP32[writefds+4>>>2>>>0]=dstWriteHigh}if(exceptfds){HEAP32[exceptfds>>>2>>>0]=dstExceptLow;HEAP32[exceptfds+4>>>2>>>0]=dstExceptHigh}return total}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall__newselect"]=___syscall__newselect;___syscall__newselect.sig="iipppp";var SOCKFS={mount(mount){Module["websocket"]=Module["websocket"]&&"object"===typeof Module["websocket"]?Module["websocket"]:{};Module["websocket"]._callbacks={};Module["websocket"]["on"]=function(event,callback){if("function"===typeof callback){this._callbacks[event]=callback}return this};Module["websocket"].emit=function(event,param){if("function"===typeof this._callbacks[event]){this._callbacks[event].call(this,param)}};return FS.createNode(null,"/",16384|511,0)},createSocket(family,type,protocol){type&=~526336;var streaming=type==1;if(streaming&&protocol&&protocol!=6){throw new FS.ErrnoError(66)}var sock={family:family,type:type,protocol:protocol,server:null,error:null,peers:{},pending:[],recv_queue:[],sock_ops:SOCKFS.websocket_sock_ops};var name=SOCKFS.nextname();var node=FS.createNode(SOCKFS.root,name,49152,0);node.sock=sock;var stream=FS.createStream({path:name,node:node,flags:2,seekable:false,stream_ops:SOCKFS.stream_ops});sock.stream=stream;return sock},getSocket(fd){var stream=FS.getStream(fd);if(!stream||!FS.isSocket(stream.node.mode)){return null}return stream.node.sock},stream_ops:{poll(stream){var sock=stream.node.sock;return sock.sock_ops.poll(sock)},ioctl(stream,request,varargs){var sock=stream.node.sock;return sock.sock_ops.ioctl(sock,request,varargs)},read(stream,buffer,offset,length,position){var sock=stream.node.sock;var msg=sock.sock_ops.recvmsg(sock,length);if(!msg){return 0}buffer.set(msg.buffer,offset);return msg.buffer.length},write(stream,buffer,offset,length,position){var sock=stream.node.sock;return sock.sock_ops.sendmsg(sock,buffer,offset,length)},close(stream){var sock=stream.node.sock;sock.sock_ops.close(sock)}},nextname(){if(!SOCKFS.nextname.current){SOCKFS.nextname.current=0}return"socket["+SOCKFS.nextname.current+++"]"},websocket_sock_ops:{createPeer(sock,addr,port){var ws;if(typeof addr=="object"){ws=addr;addr=null;port=null}if(ws){if(ws._socket){addr=ws._socket.remoteAddress;port=ws._socket.remotePort}else{var result=/ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);if(!result){throw new Error("WebSocket URL must be in the format ws(s)://address:port")}addr=result[1];port=parseInt(result[2],10)}}else{try{var runtimeConfig=Module["websocket"]&&"object"===typeof Module["websocket"];var url="ws:#".replace("#","//");if(runtimeConfig){if("string"===typeof Module["websocket"]["url"]){url=Module["websocket"]["url"]}}if(url==="ws://"||url==="wss://"){var parts=addr.split("/");url=url+parts[0]+":"+port+"/"+parts.slice(1).join("/")}var subProtocols="binary";if(runtimeConfig){if("string"===typeof Module["websocket"]["subprotocol"]){subProtocols=Module["websocket"]["subprotocol"]}}var opts=undefined;if(subProtocols!=="null"){subProtocols=subProtocols.replace(/^ +| +$/g,"").split(/ *, */);opts=subProtocols}if(runtimeConfig&&null===Module["websocket"]["subprotocol"]){subProtocols="null";opts=undefined}var WebSocketConstructor;if(ENVIRONMENT_IS_NODE){WebSocketConstructor=require("ws")}else{WebSocketConstructor=WebSocket}ws=new WebSocketConstructor(url,opts);ws.binaryType="arraybuffer"}catch(e){throw new FS.ErrnoError(23)}}var peer={addr:addr,port:port,socket:ws,dgram_send_queue:[]};SOCKFS.websocket_sock_ops.addPeer(sock,peer);SOCKFS.websocket_sock_ops.handlePeerEvents(sock,peer);if(sock.type===2&&typeof sock.sport!="undefined"){peer.dgram_send_queue.push(new Uint8Array([255,255,255,255,"p".charCodeAt(0),"o".charCodeAt(0),"r".charCodeAt(0),"t".charCodeAt(0),(sock.sport&65280)>>8,sock.sport&255]))}return peer},getPeer(sock,addr,port){return sock.peers[addr+":"+port]},addPeer(sock,peer){sock.peers[peer.addr+":"+peer.port]=peer},removePeer(sock,peer){delete sock.peers[peer.addr+":"+peer.port]},handlePeerEvents(sock,peer){var first=true;var handleOpen=function(){Module["websocket"].emit("open",sock.stream.fd);try{var queued=peer.dgram_send_queue.shift();while(queued){peer.socket.send(queued);queued=peer.dgram_send_queue.shift()}}catch(e){peer.socket.close()}};function handleMessage(data){if(typeof data=="string"){var encoder=new TextEncoder;data=encoder.encode(data)}else{assert(data.byteLength!==undefined);if(data.byteLength==0){return}data=new Uint8Array(data)}var wasfirst=first;first=false;if(wasfirst&&data.length===10&&data[0]===255&&data[1]===255&&data[2]===255&&data[3]===255&&data[4]==="p".charCodeAt(0)&&data[5]==="o".charCodeAt(0)&&data[6]==="r".charCodeAt(0)&&data[7]==="t".charCodeAt(0)){var newport=data[8]<<8|data[9];SOCKFS.websocket_sock_ops.removePeer(sock,peer);peer.port=newport;SOCKFS.websocket_sock_ops.addPeer(sock,peer);return}sock.recv_queue.push({addr:peer.addr,port:peer.port,data:data});Module["websocket"].emit("message",sock.stream.fd)}if(ENVIRONMENT_IS_NODE){peer.socket.on("open",handleOpen);peer.socket.on("message",function(data,isBinary){if(!isBinary){return}handleMessage(new Uint8Array(data).buffer)});peer.socket.on("close",function(){Module["websocket"].emit("close",sock.stream.fd)});peer.socket.on("error",function(error){sock.error=14;Module["websocket"].emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])})}else{peer.socket.onopen=handleOpen;peer.socket.onclose=function(){Module["websocket"].emit("close",sock.stream.fd)};peer.socket.onmessage=function peer_socket_onmessage(event){handleMessage(event.data)};peer.socket.onerror=function(error){sock.error=14;Module["websocket"].emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])}}},poll(sock){if(sock.type===1&&sock.server){return sock.pending.length?64|1:0}var mask=0;var dest=sock.type===1?SOCKFS.websocket_sock_ops.getPeer(sock,sock.daddr,sock.dport):null;if(sock.recv_queue.length||!dest||dest&&dest.socket.readyState===dest.socket.CLOSING||dest&&dest.socket.readyState===dest.socket.CLOSED){mask|=64|1}if(!dest||dest&&dest.socket.readyState===dest.socket.OPEN){mask|=4}if(dest&&dest.socket.readyState===dest.socket.CLOSING||dest&&dest.socket.readyState===dest.socket.CLOSED){mask|=16}return mask},ioctl(sock,request,arg){switch(request){case 21531:var bytes=0;if(sock.recv_queue.length){bytes=sock.recv_queue[0].data.length}HEAP32[arg>>>2>>>0]=bytes;return 0;default:return 28}},close(sock){if(sock.server){try{sock.server.close()}catch(e){}sock.server=null}var peers=Object.keys(sock.peers);for(var i=0;i{var socket=SOCKFS.getSocket(fd);if(!socket)throw new FS.ErrnoError(8);return socket};Module["getSocketFromFD"]=getSocketFromFD;var Sockets={BUFFER_SIZE:10240,MAX_BUFFER_SIZE:10485760,nextFd:1,fds:{},nextport:1,maxport:65535,peer:null,connections:{},portmap:{},localAddr:4261412874,addrPool:[33554442,50331658,67108874,83886090,100663306,117440522,134217738,150994954,167772170,184549386,201326602,218103818,234881034]};Module["Sockets"]=Sockets;var inetPton4=str=>{var b=str.split(".");for(var i=0;i<4;i++){var tmp=Number(b[i]);if(isNaN(tmp))return null;b[i]=tmp}return(b[0]|b[1]<<8|b[2]<<16|b[3]<<24)>>>0};Module["inetPton4"]=inetPton4;var jstoi_q=str=>parseInt(str);Module["jstoi_q"]=jstoi_q;var inetPton6=str=>{var words;var w,offset,z,i;var valid6regx=/^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i;var parts=[];if(!valid6regx.test(str)){return null}if(str==="::"){return[0,0,0,0,0,0,0,0]}if(str.startsWith("::")){str=str.replace("::","Z:")}else{str=str.replace("::",":Z:")}if(str.indexOf(".")>0){str=str.replace(new RegExp("[.]","g"),":");words=str.split(":");words[words.length-4]=jstoi_q(words[words.length-4])+jstoi_q(words[words.length-3])*256;words[words.length-3]=jstoi_q(words[words.length-2])+jstoi_q(words[words.length-1])*256;words=words.slice(0,words.length-2)}else{words=str.split(":")}offset=0;z=0;for(w=0;w{switch(family){case 2:addr=inetPton4(addr);zeroMemory(sa,16);if(addrlen){HEAP32[addrlen>>>2>>>0]=16}HEAP16[sa>>>1>>>0]=family;HEAP32[sa+4>>>2>>>0]=addr;HEAP16[sa+2>>>1>>>0]=_htons(port);break;case 10:addr=inetPton6(addr);zeroMemory(sa,28);if(addrlen){HEAP32[addrlen>>>2>>>0]=28}HEAP32[sa>>>2>>>0]=family;HEAP32[sa+8>>>2>>>0]=addr[0];HEAP32[sa+12>>>2>>>0]=addr[1];HEAP32[sa+16>>>2>>>0]=addr[2];HEAP32[sa+20>>>2>>>0]=addr[3];HEAP16[sa+2>>>1>>>0]=_htons(port);break;default:return 5}return 0};Module["writeSockaddr"]=writeSockaddr;var DNS={address_map:{id:1,addrs:{},names:{}},lookup_name(name){var res=inetPton4(name);if(res!==null){return name}res=inetPton6(name);if(res!==null){return name}var addr;if(DNS.address_map.addrs[name]){addr=DNS.address_map.addrs[name]}else{var id=DNS.address_map.id++;assert(id<65535,"exceeded max address mappings of 65535");addr="172.29."+(id&255)+"."+(id&65280);DNS.address_map.names[addr]=name;DNS.address_map.addrs[name]=addr}return addr},lookup_addr(addr){if(DNS.address_map.names[addr]){return DNS.address_map.names[addr]}return null}};Module["DNS"]=DNS;function ___syscall_accept4(fd,addr,addrlen,flags,d1,d2){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var newsock=sock.sock_ops.accept(sock);if(addr){var errno=writeSockaddr(addr,newsock.family,DNS.lookup_name(newsock.daddr),newsock.dport,addrlen)}return newsock.stream.fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_accept4"]=___syscall_accept4;___syscall_accept4.sig="iippiii";var inetNtop4=addr=>(addr&255)+"."+(addr>>8&255)+"."+(addr>>16&255)+"."+(addr>>24&255);Module["inetNtop4"]=inetNtop4;var inetNtop6=ints=>{var str="";var word=0;var longest=0;var lastzero=0;var zstart=0;var len=0;var i=0;var parts=[ints[0]&65535,ints[0]>>16,ints[1]&65535,ints[1]>>16,ints[2]&65535,ints[2]>>16,ints[3]&65535,ints[3]>>16];var hasipv4=true;var v4part="";for(i=0;i<5;i++){if(parts[i]!==0){hasipv4=false;break}}if(hasipv4){v4part=inetNtop4(parts[6]|parts[7]<<16);if(parts[5]===-1){str="::ffff:";str+=v4part;return str}if(parts[5]===0){str="::";if(v4part==="0.0.0.0")v4part="";if(v4part==="0.0.0.1")v4part="1";str+=v4part;return str}}for(word=0;word<8;word++){if(parts[word]===0){if(word-lastzero>1){len=0}lastzero=word;len++}if(len>longest){longest=len;zstart=word-longest+1}}for(word=0;word<8;word++){if(longest>1){if(parts[word]===0&&word>=zstart&&word{var family=HEAP16[sa>>>1>>>0];var port=_ntohs(HEAPU16[sa+2>>>1>>>0]);var addr;switch(family){case 2:if(salen!==16){return{errno:28}}addr=HEAP32[sa+4>>>2>>>0];addr=inetNtop4(addr);break;case 10:if(salen!==28){return{errno:28}}addr=[HEAP32[sa+8>>>2>>>0],HEAP32[sa+12>>>2>>>0],HEAP32[sa+16>>>2>>>0],HEAP32[sa+20>>>2>>>0]];addr=inetNtop6(addr);break;default:return{errno:5}}return{family:family,addr:addr,port:port}};Module["readSockaddr"]=readSockaddr;var getSocketAddress=(addrp,addrlen,allowNull)=>{if(allowNull&&addrp===0)return null;var info=readSockaddr(addrp,addrlen);if(info.errno)throw new FS.ErrnoError(info.errno);info.addr=DNS.lookup_addr(info.addr)||info.addr;return info};Module["getSocketAddress"]=getSocketAddress;function ___syscall_bind(fd,addr,addrlen,d1,d2,d3){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var info=getSocketAddress(addr,addrlen);sock.sock_ops.bind(sock,info.addr,info.port);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_bind"]=___syscall_bind;___syscall_bind.sig="iippiii";function ___syscall_chdir(path){path>>>=0;try{path=SYSCALLS.getStr(path);FS.chdir(path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_chdir"]=___syscall_chdir;___syscall_chdir.sig="ip";function ___syscall_chmod(path,mode){path>>>=0;try{path=SYSCALLS.getStr(path);FS.chmod(path,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_chmod"]=___syscall_chmod;___syscall_chmod.sig="ipi";function ___syscall_connect(fd,addr,addrlen,d1,d2,d3){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var info=getSocketAddress(addr,addrlen);sock.sock_ops.connect(sock,info.addr,info.port);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_connect"]=___syscall_connect;___syscall_connect.sig="iippiii";function ___syscall_dup(fd){try{var old=SYSCALLS.getStreamFromFD(fd);return FS.dupStream(old).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_dup"]=___syscall_dup;___syscall_dup.sig="ii";function ___syscall_dup3(fd,newfd,flags){try{var old=SYSCALLS.getStreamFromFD(fd);if(old.fd===newfd)return-28;var existing=FS.getStream(newfd);if(existing)FS.close(existing);return FS.dupStream(old,newfd).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_dup3"]=___syscall_dup3;___syscall_dup3.sig="iiii";function ___syscall_faccessat(dirfd,path,amode,flags){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(amode&~7){return-28}var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node){return-44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return-2}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_faccessat"]=___syscall_faccessat;___syscall_faccessat.sig="iipii";var ___syscall_fadvise64=(fd,offset,len,advice)=>0;Module["___syscall_fadvise64"]=___syscall_fadvise64;___syscall_fadvise64.sig="iijji";function ___syscall_fallocate(fd,mode,offset,len){offset=bigintToI53Checked(offset);len=bigintToI53Checked(len);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.allocate(stream,offset,len);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fallocate"]=___syscall_fallocate;___syscall_fallocate.sig="iiijj";function ___syscall_fchdir(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.chdir(stream.path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fchdir"]=___syscall_fchdir;___syscall_fchdir.sig="ii";function ___syscall_fchmod(fd,mode){try{FS.fchmod(fd,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fchmod"]=___syscall_fchmod;___syscall_fchmod.sig="iii";function ___syscall_fchmodat2(dirfd,path,mode,flags){path>>>=0;try{var nofollow=flags&256;path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);FS.chmod(path,mode,nofollow);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fchmodat2"]=___syscall_fchmodat2;___syscall_fchmodat2.sig="iipii";function ___syscall_fchown32(fd,owner,group){try{FS.fchown(fd,owner,group);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fchown32"]=___syscall_fchown32;___syscall_fchown32.sig="iiii";function ___syscall_fchownat(dirfd,path,owner,group,flags){path>>>=0;try{path=SYSCALLS.getStr(path);var nofollow=flags&256;flags=flags&~256;path=SYSCALLS.calculateAt(dirfd,path);(nofollow?FS.lchown:FS.chown)(path,owner,group);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fchownat"]=___syscall_fchownat;___syscall_fchownat.sig="iipiii";function syscallGetVarargI(){var ret=HEAP32[+SYSCALLS.varargs>>>2>>>0];SYSCALLS.varargs+=4;return ret}Module["syscallGetVarargI"]=syscallGetVarargI;var syscallGetVarargP=syscallGetVarargI;Module["syscallGetVarargP"]=syscallGetVarargP;function ___syscall_fcntl64(fd,cmd,varargs){varargs>>>=0;SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=syscallGetVarargI();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.dupStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=syscallGetVarargI();stream.flags|=arg;return 0}case 12:{var arg=syscallGetVarargP();var offset=0;HEAP16[arg+offset>>>1>>>0]=2;return 0}case 13:case 14:return 0}return-28}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fcntl64"]=___syscall_fcntl64;___syscall_fcntl64.sig="iiip";function ___syscall_fdatasync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fdatasync"]=___syscall_fdatasync;___syscall_fdatasync.sig="ii";function ___syscall_fstat64(fd,buf){buf>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fstat64"]=___syscall_fstat64;___syscall_fstat64.sig="iip";function ___syscall_statfs64(path,size,buf){path>>>=0;size>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);HEAP32[buf+4>>>2>>>0]=4096;HEAP32[buf+40>>>2>>>0]=4096;HEAP32[buf+8>>>2>>>0]=1e6;HEAP32[buf+12>>>2>>>0]=5e5;HEAP32[buf+16>>>2>>>0]=5e5;HEAP32[buf+20>>>2>>>0]=FS.nextInode;HEAP32[buf+24>>>2>>>0]=1e6;HEAP32[buf+28>>>2>>>0]=42;HEAP32[buf+44>>>2>>>0]=2;HEAP32[buf+36>>>2>>>0]=255;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_statfs64"]=___syscall_statfs64;___syscall_statfs64.sig="ippp";function ___syscall_fstatfs64(fd,size,buf){size>>>=0;buf>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);return ___syscall_statfs64(0,size,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fstatfs64"]=___syscall_fstatfs64;___syscall_fstatfs64.sig="iipp";function ___syscall_ftruncate64(fd,length){length=bigintToI53Checked(length);try{if(isNaN(length))return 61;FS.ftruncate(fd,length);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_ftruncate64"]=___syscall_ftruncate64;___syscall_ftruncate64.sig="iij";var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);Module["stringToUTF8"]=stringToUTF8;function ___syscall_getcwd(buf,size){buf>>>=0;size>>>=0;try{if(size===0)return-28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd)+1;if(size>>=0;count>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);stream.getdents||=FS.readdir(stream.path);var struct_size=280;var pos=0;var off=FS.llseek(stream,0,1);var idx=Math.floor(off/struct_size);while(idx>>3]=BigInt(id);HEAP64[dirp+pos+8>>>3]=BigInt((idx+1)*struct_size);HEAP16[dirp+pos+16>>>1>>>0]=280;HEAP8[dirp+pos+18>>>0]=type;stringToUTF8(name,dirp+pos+19,256);pos+=struct_size;idx+=1}FS.llseek(stream,idx*struct_size,0);return pos}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_getdents64"]=___syscall_getdents64;___syscall_getdents64.sig="iipp";function ___syscall_getpeername(fd,addr,addrlen,d1,d2,d3){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);if(!sock.daddr){return-53}var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(sock.daddr),sock.dport,addrlen);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_getpeername"]=___syscall_getpeername;___syscall_getpeername.sig="iippiii";function ___syscall_getsockname(fd,addr,addrlen,d1,d2,d3){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(sock.saddr||"0.0.0.0"),sock.sport,addrlen);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_getsockname"]=___syscall_getsockname;___syscall_getsockname.sig="iippiii";function ___syscall_getsockopt(fd,level,optname,optval,optlen,d1){optval>>>=0;optlen>>>=0;try{var sock=getSocketFromFD(fd);if(level===1){if(optname===4){HEAP32[optval>>>2>>>0]=sock.error;HEAP32[optlen>>>2>>>0]=4;sock.error=null;return 0}}return-50}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_getsockopt"]=___syscall_getsockopt;___syscall_getsockopt.sig="iiiippi";function ___syscall_ioctl(fd,op,varargs){varargs>>>=0;SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:{if(!stream.tty)return-59;return 0}case 21505:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcgets){var termios=stream.tty.ops.ioctl_tcgets(stream);var argp=syscallGetVarargP();HEAP32[argp>>>2>>>0]=termios.c_iflag||0;HEAP32[argp+4>>>2>>>0]=termios.c_oflag||0;HEAP32[argp+8>>>2>>>0]=termios.c_cflag||0;HEAP32[argp+12>>>2>>>0]=termios.c_lflag||0;for(var i=0;i<32;i++){HEAP8[argp+i+17>>>0]=termios.c_cc[i]||0}return 0}return 0}case 21510:case 21511:case 21512:{if(!stream.tty)return-59;return 0}case 21506:case 21507:case 21508:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcsets){var argp=syscallGetVarargP();var c_iflag=HEAP32[argp>>>2>>>0];var c_oflag=HEAP32[argp+4>>>2>>>0];var c_cflag=HEAP32[argp+8>>>2>>>0];var c_lflag=HEAP32[argp+12>>>2>>>0];var c_cc=[];for(var i=0;i<32;i++){c_cc.push(HEAP8[argp+i+17>>>0])}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag:c_iflag,c_oflag:c_oflag,c_cflag:c_cflag,c_lflag:c_lflag,c_cc:c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=syscallGetVarargP();HEAP32[argp>>>2>>>0]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=syscallGetVarargP();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tiocgwinsz){var winsize=stream.tty.ops.ioctl_tiocgwinsz(stream.tty);var argp=syscallGetVarargP();HEAP16[argp>>>1>>>0]=winsize[0];HEAP16[argp+2>>>1>>>0]=winsize[1]}return 0}case 21524:{if(!stream.tty)return-59;return 0}case 21515:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_ioctl"]=___syscall_ioctl;___syscall_ioctl.sig="iiip";function ___syscall_listen(fd,backlog){try{var sock=getSocketFromFD(fd);sock.sock_ops.listen(sock,backlog);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_listen"]=___syscall_listen;___syscall_listen.sig="iiiiiii";function ___syscall_lstat64(path,buf){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.lstat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_lstat64"]=___syscall_lstat64;___syscall_lstat64.sig="ipp";function ___syscall_mkdirat(dirfd,path,mode){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);path=PATH.normalize(path);if(path[path.length-1]==="/")path=path.substr(0,path.length-1);FS.mkdir(path,mode,0);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_mkdirat"]=___syscall_mkdirat;___syscall_mkdirat.sig="iipi";function ___syscall_mknodat(dirfd,path,mode,dev){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);switch(mode&61440){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}FS.mknod(path,mode,dev);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_mknodat"]=___syscall_mknodat;___syscall_mknodat.sig="iipii";function ___syscall_newfstatat(dirfd,path,buf,flags){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);var nofollow=flags&256;var allowEmpty=flags&4096;flags=flags&~6400;path=SYSCALLS.calculateAt(dirfd,path,allowEmpty);return SYSCALLS.doStat(nofollow?FS.lstat:FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_newfstatat"]=___syscall_newfstatat;___syscall_newfstatat.sig="iippi";function ___syscall_openat(dirfd,path,flags,varargs){path>>>=0;varargs>>>=0;SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?syscallGetVarargI():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_openat"]=___syscall_openat;___syscall_openat.sig="iipip";var PIPEFS={BUCKET_BUFFER_SIZE:8192,mount(mount){return FS.createNode(null,"/",16384|511,0)},createPipe(){var pipe={buckets:[],refcnt:2};pipe.buckets.push({buffer:new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),offset:0,roffset:0});var rName=PIPEFS.nextname();var wName=PIPEFS.nextname();var rNode=FS.createNode(PIPEFS.root,rName,4096,0);var wNode=FS.createNode(PIPEFS.root,wName,4096,0);rNode.pipe=pipe;wNode.pipe=pipe;var readableStream=FS.createStream({path:rName,node:rNode,flags:0,seekable:false,stream_ops:PIPEFS.stream_ops});rNode.stream=readableStream;var writableStream=FS.createStream({path:wName,node:wNode,flags:1,seekable:false,stream_ops:PIPEFS.stream_ops});wNode.stream=writableStream;return{readable_fd:readableStream.fd,writable_fd:writableStream.fd}},stream_ops:{poll(stream){var pipe=stream.node.pipe;if((stream.flags&2097155)===1){return 256|4}if(pipe.buckets.length>0){for(var i=0;i0){return 64|1}}}return 0},ioctl(stream,request,varargs){return 28},fsync(stream){return 28},read(stream,buffer,offset,length,position){var pipe=stream.node.pipe;var currentLength=0;for(var i=0;i=dataLen){currBucket.buffer.set(data,currBucket.offset);currBucket.offset+=dataLen;return dataLen}else if(freeBytesInCurrBuffer>0){currBucket.buffer.set(data.subarray(0,freeBytesInCurrBuffer),currBucket.offset);currBucket.offset+=freeBytesInCurrBuffer;data=data.subarray(freeBytesInCurrBuffer,data.byteLength)}var numBuckets=data.byteLength/PIPEFS.BUCKET_BUFFER_SIZE|0;var remElements=data.byteLength%PIPEFS.BUCKET_BUFFER_SIZE;for(var i=0;i0){var newBucket={buffer:new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),offset:data.byteLength,roffset:0};pipe.buckets.push(newBucket);newBucket.buffer.set(data)}return dataLen},close(stream){var pipe=stream.node.pipe;pipe.refcnt--;if(pipe.refcnt===0){pipe.buckets=null}}},nextname(){if(!PIPEFS.nextname.current){PIPEFS.nextname.current=0}return"pipe["+PIPEFS.nextname.current+++"]"}};Module["PIPEFS"]=PIPEFS;function ___syscall_pipe(fdPtr){fdPtr>>>=0;try{if(fdPtr==0){throw new FS.ErrnoError(21)}var res=PIPEFS.createPipe();HEAP32[fdPtr>>>2>>>0]=res.readable_fd;HEAP32[fdPtr+4>>>2>>>0]=res.writable_fd;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_pipe"]=___syscall_pipe;___syscall_pipe.sig="ip";function ___syscall_poll(fds,nfds,timeout){fds>>>=0;try{var nonzero=0;for(var i=0;i>>2>>>0];var events=HEAP16[pollfd+4>>>1>>>0];var mask=32;var stream=FS.getStream(fd);if(stream){mask=SYSCALLS.DEFAULT_POLLMASK;if(stream.stream_ops.poll){mask=stream.stream_ops.poll(stream,-1)}}mask&=events|8|16;if(mask)nonzero++;HEAP16[pollfd+6>>>1>>>0]=mask}return nonzero}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_poll"]=___syscall_poll;___syscall_poll.sig="ipii";function ___syscall_readlinkat(dirfd,path,buf,bufsize){path>>>=0;buf>>>=0;bufsize>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len>>>0];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len>>>0]=endChar;return len}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_readlinkat"]=___syscall_readlinkat;___syscall_readlinkat.sig="iippp";function ___syscall_recvfrom(fd,buf,len,flags,addr,addrlen){buf>>>=0;len>>>=0;addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var msg=sock.sock_ops.recvmsg(sock,len);if(!msg)return 0;if(addr){var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(msg.addr),msg.port,addrlen)}HEAPU8.set(msg.buffer,buf>>>0);return msg.buffer.byteLength}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_recvfrom"]=___syscall_recvfrom;___syscall_recvfrom.sig="iippipp";function ___syscall_recvmsg(fd,message,flags,d1,d2,d3){message>>>=0;try{var sock=getSocketFromFD(fd);var iov=HEAPU32[message+8>>>2>>>0];var num=HEAP32[message+12>>>2>>>0];var total=0;for(var i=0;i>>2>>>0]}var msg=sock.sock_ops.recvmsg(sock,total);if(!msg)return 0;var name=HEAPU32[message>>>2>>>0];if(name){var errno=writeSockaddr(name,sock.family,DNS.lookup_name(msg.addr),msg.port)}var bytesRead=0;var bytesRemaining=msg.buffer.byteLength;for(var i=0;bytesRemaining>0&&i>>2>>>0];var iovlen=HEAP32[iov+(8*i+4)>>>2>>>0];if(!iovlen){continue}var length=Math.min(iovlen,bytesRemaining);var buf=msg.buffer.subarray(bytesRead,bytesRead+length);HEAPU8.set(buf,iovbase+bytesRead>>>0);bytesRead+=length;bytesRemaining-=length}return bytesRead}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_recvmsg"]=___syscall_recvmsg;___syscall_recvmsg.sig="iipiiii";function ___syscall_renameat(olddirfd,oldpath,newdirfd,newpath){oldpath>>>=0;newpath>>>=0;try{oldpath=SYSCALLS.getStr(oldpath);newpath=SYSCALLS.getStr(newpath);oldpath=SYSCALLS.calculateAt(olddirfd,oldpath);newpath=SYSCALLS.calculateAt(newdirfd,newpath);FS.rename(oldpath,newpath);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_renameat"]=___syscall_renameat;___syscall_renameat.sig="iipip";function ___syscall_rmdir(path){path>>>=0;try{path=SYSCALLS.getStr(path);FS.rmdir(path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_rmdir"]=___syscall_rmdir;___syscall_rmdir.sig="ip";function ___syscall_sendmsg(fd,message,flags,d1,d2,d3){message>>>=0;d1>>>=0;d2>>>=0;try{var sock=getSocketFromFD(fd);var iov=HEAPU32[message+8>>>2>>>0];var num=HEAP32[message+12>>>2>>>0];var addr,port;var name=HEAPU32[message>>>2>>>0];var namelen=HEAP32[message+4>>>2>>>0];if(name){var info=readSockaddr(name,namelen);if(info.errno)return-info.errno;port=info.port;addr=DNS.lookup_addr(info.addr)||info.addr}var total=0;for(var i=0;i>>2>>>0]}var view=new Uint8Array(total);var offset=0;for(var i=0;i>>2>>>0];var iovlen=HEAP32[iov+(8*i+4)>>>2>>>0];for(var j=0;j>>0]}}return sock.sock_ops.sendmsg(sock,view,0,total,addr,port)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_sendmsg"]=___syscall_sendmsg;___syscall_sendmsg.sig="iipippi";function ___syscall_sendto(fd,message,length,flags,addr,addr_len){message>>>=0;length>>>=0;addr>>>=0;addr_len>>>=0;try{var sock=getSocketFromFD(fd);var dest=getSocketAddress(addr,addr_len,true);if(!dest){return FS.write(sock.stream,HEAP8,message,length)}return sock.sock_ops.sendmsg(sock,HEAP8,message,length,dest.addr,dest.port)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_sendto"]=___syscall_sendto;___syscall_sendto.sig="iippipp";function ___syscall_socket(domain,type,protocol){try{var sock=SOCKFS.createSocket(domain,type,protocol);return sock.stream.fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_socket"]=___syscall_socket;___syscall_socket.sig="iiiiiii";function ___syscall_stat64(path,buf){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_stat64"]=___syscall_stat64;___syscall_stat64.sig="ipp";function ___syscall_symlink(target,linkpath){target>>>=0;linkpath>>>=0;try{target=SYSCALLS.getStr(target);linkpath=SYSCALLS.getStr(linkpath);FS.symlink(target,linkpath);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_symlink"]=___syscall_symlink;___syscall_symlink.sig="ipp";function ___syscall_symlinkat(target,newdirfd,linkpath){target>>>=0;linkpath>>>=0;try{linkpath=SYSCALLS.calculateAt(newdirfd,linkpath);FS.symlink(target,linkpath);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_symlinkat"]=___syscall_symlinkat;___syscall_symlinkat.sig="ipip";function ___syscall_truncate64(path,length){path>>>=0;length=bigintToI53Checked(length);try{if(isNaN(length))return 61;path=SYSCALLS.getStr(path);FS.truncate(path,length);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_truncate64"]=___syscall_truncate64;___syscall_truncate64.sig="ipj";function ___syscall_unlinkat(dirfd,path,flags){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(flags===0){FS.unlink(path)}else if(flags===512){FS.rmdir(path)}else{abort("Invalid flags passed to unlinkat")}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_unlinkat"]=___syscall_unlinkat;___syscall_unlinkat.sig="iipi";var readI53FromI64=ptr=>HEAPU32[ptr>>>2>>>0]+HEAP32[ptr+4>>>2>>>0]*4294967296;Module["readI53FromI64"]=readI53FromI64;function ___syscall_utimensat(dirfd,path,times,flags){path>>>=0;times>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path,true);if(!times){var atime=Date.now();var mtime=atime}else{var seconds=readI53FromI64(times);var nanoseconds=HEAP32[times+8>>>2>>>0];atime=seconds*1e3+nanoseconds/(1e3*1e3);times+=16;seconds=readI53FromI64(times);nanoseconds=HEAP32[times+8>>>2>>>0];mtime=seconds*1e3+nanoseconds/(1e3*1e3)}FS.utime(path,atime,mtime);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_utimensat"]=___syscall_utimensat;___syscall_utimensat.sig="iippi";var ___table_base=new WebAssembly.Global({"value":"i32","mutable":false},1);Module["___table_base"]=___table_base;var ENV={};Module["ENV"]=ENV;var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};Module["stringToUTF8OnStack"]=stringToUTF8OnStack;var dlSetError=msg=>{var sp=stackSave();var cmsg=stringToUTF8OnStack(msg);___dl_seterr(cmsg,0);stackRestore(sp)};Module["dlSetError"]=dlSetError;var dlopenInternal=(handle,jsflags)=>{var filename=UTF8ToString(handle+36);var flags=HEAP32[handle+4>>>2>>>0];filename=PATH.normalize(filename);var searchpaths=[];var global=Boolean(flags&256);var localScope=global?null:{};var combinedFlags={global:global,nodelete:Boolean(flags&4096),loadAsync:jsflags.loadAsync};if(jsflags.loadAsync){return loadDynamicLibrary(filename,combinedFlags,localScope,handle)}try{return loadDynamicLibrary(filename,combinedFlags,localScope,handle)}catch(e){dlSetError(`Could not load dynamic lib: ${filename}\n${e}`);return 0}};Module["dlopenInternal"]=dlopenInternal;function __dlopen_js(handle){handle>>>=0;return dlopenInternal(handle,{loadAsync:false})}Module["__dlopen_js"]=__dlopen_js;__dlopen_js.sig="pp";function __dlsym_js(handle,symbol,symbolIndex){handle>>>=0;symbol>>>=0;symbolIndex>>>=0;symbol=UTF8ToString(symbol);var result;var newSymIndex;var lib=LDSO.loadedLibsByHandle[handle];if(!lib.exports.hasOwnProperty(symbol)||lib.exports[symbol].stub){dlSetError(`Tried to lookup unknown symbol "${symbol}" in dynamic lib: ${lib.name}`);return 0}newSymIndex=Object.keys(lib.exports).indexOf(symbol);result=lib.exports[symbol];if(typeof result=="function"){var addr=getFunctionAddress(result);if(addr){result=addr}else{result=addFunction(result,result.sig);HEAPU32[symbolIndex>>>2>>>0]=newSymIndex}}return result}Module["__dlsym_js"]=__dlsym_js;__dlsym_js.sig="pppp";var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)};Module["handleException"]=handleException;var runtimeKeepaliveCounter=0;Module["runtimeKeepaliveCounter"]=runtimeKeepaliveCounter;var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;Module["keepRuntimeAlive"]=keepRuntimeAlive;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){Module["onExit"]?.(code);ABORT=true}quit_(code,new ExitStatus(code))};Module["_proc_exit"]=_proc_exit;_proc_exit.sig="vi";var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status)};Module["exitJS"]=exitJS;var _exit=exitJS;Module["_exit"]=_exit;_exit.sig="vi";var maybeExit=()=>{if(!keepRuntimeAlive()){try{_exit(EXITSTATUS)}catch(e){handleException(e)}}};Module["maybeExit"]=maybeExit;var callUserCallback=func=>{if(ABORT){return}try{func();maybeExit()}catch(e){handleException(e)}};Module["callUserCallback"]=callUserCallback;function __emscripten_dlopen_js(handle,onsuccess,onerror,user_data){handle>>>=0;onsuccess>>>=0;onerror>>>=0;user_data>>>=0;function errorCallback(e){var filename=UTF8ToString(handle+36);dlSetError(`'Could not load dynamic lib: ${filename}\n${e}`);callUserCallback(()=>getWasmTableEntry(onerror)(handle,user_data))}function successCallback(){callUserCallback(()=>getWasmTableEntry(onsuccess)(handle,user_data))}var promise=dlopenInternal(handle,{loadAsync:true});if(promise){promise.then(successCallback,errorCallback)}else{errorCallback()}}Module["__emscripten_dlopen_js"]=__emscripten_dlopen_js;__emscripten_dlopen_js.sig="vpppp";var nowIsMonotonic=1;Module["nowIsMonotonic"]=nowIsMonotonic;var __emscripten_get_now_is_monotonic=()=>nowIsMonotonic;Module["__emscripten_get_now_is_monotonic"]=__emscripten_get_now_is_monotonic;__emscripten_get_now_is_monotonic.sig="i";function __emscripten_get_progname(str,len){str>>>=0;stringToUTF8(thisProgram,str,len)}Module["__emscripten_get_progname"]=__emscripten_get_progname;__emscripten_get_progname.sig="vpi";function __emscripten_lookup_name(name){name>>>=0;var nameString=UTF8ToString(name);return inetPton4(DNS.lookup_name(nameString))}Module["__emscripten_lookup_name"]=__emscripten_lookup_name;__emscripten_lookup_name.sig="ip";var __emscripten_runtime_keepalive_clear=()=>{noExitRuntime=false;runtimeKeepaliveCounter=0};Module["__emscripten_runtime_keepalive_clear"]=__emscripten_runtime_keepalive_clear;__emscripten_runtime_keepalive_clear.sig="v";function __emscripten_system(command){command>>>=0;if(ENVIRONMENT_IS_NODE){if(!command)return 1;var cmdstr=UTF8ToString(command);if(!cmdstr.length)return 0;var cp=require("child_process");var ret=cp.spawnSync(cmdstr,[],{shell:true,stdio:"inherit"});var _W_EXITCODE=(ret,sig)=>ret<<8|sig;if(ret.status===null){var signalToNumber=sig=>{switch(sig){case"SIGHUP":return 1;case"SIGINT":return 2;case"SIGQUIT":return 3;case"SIGFPE":return 8;case"SIGKILL":return 9;case"SIGALRM":return 14;case"SIGTERM":return 15}return 2};return _W_EXITCODE(0,signalToNumber(ret.signal))}return _W_EXITCODE(ret.status,0)}if(!command)return 0;return-52}Module["__emscripten_system"]=__emscripten_system;__emscripten_system.sig="ip";var __emscripten_throw_longjmp=()=>{throw Module.wrapException(Infinity)};Module["__emscripten_throw_longjmp"]=__emscripten_throw_longjmp;__emscripten_throw_longjmp.sig="v";function __gmtime_js(time,tmPtr){time=bigintToI53Checked(time);tmPtr>>>=0;var date=new Date(time*1e3);HEAP32[tmPtr>>>2>>>0]=date.getUTCSeconds();HEAP32[tmPtr+4>>>2>>>0]=date.getUTCMinutes();HEAP32[tmPtr+8>>>2>>>0]=date.getUTCHours();HEAP32[tmPtr+12>>>2>>>0]=date.getUTCDate();HEAP32[tmPtr+16>>>2>>>0]=date.getUTCMonth();HEAP32[tmPtr+20>>>2>>>0]=date.getUTCFullYear()-1900;HEAP32[tmPtr+24>>>2>>>0]=date.getUTCDay();var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>>2>>>0]=yday}Module["__gmtime_js"]=__gmtime_js;__gmtime_js.sig="vjp";var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);Module["isLeapYear"]=isLeapYear;var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];Module["MONTH_DAYS_LEAP_CUMULATIVE"]=MONTH_DAYS_LEAP_CUMULATIVE;var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];Module["MONTH_DAYS_REGULAR_CUMULATIVE"]=MONTH_DAYS_REGULAR_CUMULATIVE;var ydayFromDate=date=>{var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday};Module["ydayFromDate"]=ydayFromDate;function __localtime_js(time,tmPtr){time=bigintToI53Checked(time);tmPtr>>>=0;var date=new Date(time*1e3);HEAP32[tmPtr>>>2>>>0]=date.getSeconds();HEAP32[tmPtr+4>>>2>>>0]=date.getMinutes();HEAP32[tmPtr+8>>>2>>>0]=date.getHours();HEAP32[tmPtr+12>>>2>>>0]=date.getDate();HEAP32[tmPtr+16>>>2>>>0]=date.getMonth();HEAP32[tmPtr+20>>>2>>>0]=date.getFullYear()-1900;HEAP32[tmPtr+24>>>2>>>0]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>>2>>>0]=yday;HEAP32[tmPtr+36>>>2>>>0]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>>2>>>0]=dst}Module["__localtime_js"]=__localtime_js;__localtime_js.sig="vjp";var __mktime_js=function(tmPtr){tmPtr>>>=0;var ret=(()=>{var date=new Date(HEAP32[tmPtr+20>>>2>>>0]+1900,HEAP32[tmPtr+16>>>2>>>0],HEAP32[tmPtr+12>>>2>>>0],HEAP32[tmPtr+8>>>2>>>0],HEAP32[tmPtr+4>>>2>>>0],HEAP32[tmPtr>>>2>>>0],0);var dst=HEAP32[tmPtr+32>>>2>>>0];var guessedOffset=date.getTimezoneOffset();var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dstOffset=Math.min(winterOffset,summerOffset);if(dst<0){HEAP32[tmPtr+32>>>2>>>0]=Number(summerOffset!=winterOffset&&dstOffset==guessedOffset)}else if(dst>0!=(dstOffset==guessedOffset)){var nonDstOffset=Math.max(winterOffset,summerOffset);var trueOffset=dst>0?dstOffset:nonDstOffset;date.setTime(date.getTime()+(trueOffset-guessedOffset)*6e4)}HEAP32[tmPtr+24>>>2>>>0]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>>2>>>0]=yday;HEAP32[tmPtr>>>2>>>0]=date.getSeconds();HEAP32[tmPtr+4>>>2>>>0]=date.getMinutes();HEAP32[tmPtr+8>>>2>>>0]=date.getHours();HEAP32[tmPtr+12>>>2>>>0]=date.getDate();HEAP32[tmPtr+16>>>2>>>0]=date.getMonth();HEAP32[tmPtr+20>>>2>>>0]=date.getYear();var timeMs=date.getTime();if(isNaN(timeMs)){return-1}return timeMs/1e3})();return BigInt(ret)};Module["__mktime_js"]=__mktime_js;__mktime_js.sig="jp";function __mmap_js(len,prot,flags,fd,offset,allocated,addr){len>>>=0;offset=bigintToI53Checked(offset);allocated>>>=0;addr>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var res=FS.mmap(stream,len,offset,prot,flags);var ptr=res.ptr;HEAP32[allocated>>>2>>>0]=res.allocated;HEAPU32[addr>>>2>>>0]=ptr;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["__mmap_js"]=__mmap_js;__mmap_js.sig="ipiiijpp";function __msync_js(addr,len,prot,flags,fd,offset){addr>>>=0;len>>>=0;offset=bigintToI53Checked(offset);try{if(isNaN(offset))return 61;SYSCALLS.doMsync(addr,SYSCALLS.getStreamFromFD(fd),len,flags,offset);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["__msync_js"]=__msync_js;__msync_js.sig="ippiiij";function __munmap_js(addr,len,prot,flags,fd,offset){addr>>>=0;len>>>=0;offset=bigintToI53Checked(offset);try{var stream=SYSCALLS.getStreamFromFD(fd);if(prot&2){SYSCALLS.doMsync(addr,stream,len,flags,offset)}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["__munmap_js"]=__munmap_js;__munmap_js.sig="ippiiij";var timers={};Module["timers"]=timers;var _emscripten_get_now;_emscripten_get_now=()=>performance.now();Module["_emscripten_get_now"]=_emscripten_get_now;_emscripten_get_now.sig="d";var __setitimer_js=(which,timeout_ms)=>{if(timers[which]){clearTimeout(timers[which].id);delete timers[which]}if(!timeout_ms)return 0;var id=setTimeout(()=>{delete timers[which];callUserCallback(()=>__emscripten_timeout(which,_emscripten_get_now()))},timeout_ms);timers[which]={id:id,timeout_ms:timeout_ms};return 0};Module["__setitimer_js"]=__setitimer_js;__setitimer_js.sig="iid";var __timegm_js=function(tmPtr){tmPtr>>>=0;var ret=(()=>{var time=Date.UTC(HEAP32[tmPtr+20>>>2>>>0]+1900,HEAP32[tmPtr+16>>>2>>>0],HEAP32[tmPtr+12>>>2>>>0],HEAP32[tmPtr+8>>>2>>>0],HEAP32[tmPtr+4>>>2>>>0],HEAP32[tmPtr>>>2>>>0],0);var date=new Date(time);HEAP32[tmPtr+24>>>2>>>0]=date.getUTCDay();var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>>2>>>0]=yday;return date.getTime()/1e3})();return BigInt(ret)};Module["__timegm_js"]=__timegm_js;__timegm_js.sig="jp";var __tzset_js=function(timezone,daylight,std_name,dst_name){timezone>>>=0;daylight>>>=0;std_name>>>=0;dst_name>>>=0;var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>>2>>>0]=stdTimezoneOffset*60;HEAP32[daylight>>>2>>>0]=Number(winterOffset!=summerOffset);var extractZone=date=>date.toLocaleTimeString(undefined,{hour12:false,timeZoneName:"short"}).split(" ")[1];var winterName=extractZone(winter);var summerName=extractZone(summer);if(summerOffset{abort("")};Module["_abort"]=_abort;_abort.sig="v";var readEmAsmArgsArray=[];Module["readEmAsmArgsArray"]=readEmAsmArgsArray;var readEmAsmArgs=(sigPtr,buf)=>{readEmAsmArgsArray.length=0;var ch;while(ch=HEAPU8[sigPtr++>>>0]){var wide=ch!=105;wide&=ch!=112;buf+=wide&&buf%8?4:0;readEmAsmArgsArray.push(ch==112?HEAPU32[buf>>>2>>>0]:ch==106?HEAP64[buf>>>3]:ch==105?HEAP32[buf>>>2>>>0]:HEAPF64[buf>>>3>>>0]);buf+=wide?8:4}return readEmAsmArgsArray};Module["readEmAsmArgs"]=readEmAsmArgs;var runEmAsmFunction=(code,sigPtr,argbuf)=>{var args=readEmAsmArgs(sigPtr,argbuf);return ASM_CONSTS[code](...args)};Module["runEmAsmFunction"]=runEmAsmFunction;function _emscripten_asm_const_int(code,sigPtr,argbuf){code>>>=0;sigPtr>>>=0;argbuf>>>=0;return runEmAsmFunction(code,sigPtr,argbuf)}Module["_emscripten_asm_const_int"]=_emscripten_asm_const_int;_emscripten_asm_const_int.sig="ippp";function _emscripten_console_error(str){str>>>=0;console.error(UTF8ToString(str))}Module["_emscripten_console_error"]=_emscripten_console_error;_emscripten_console_error.sig="vp";function _emscripten_console_log(str){str>>>=0;console.log(UTF8ToString(str))}Module["_emscripten_console_log"]=_emscripten_console_log;_emscripten_console_log.sig="vp";function _emscripten_console_warn(str){str>>>=0;console.warn(UTF8ToString(str))}Module["_emscripten_console_warn"]=_emscripten_console_warn;_emscripten_console_warn.sig="vp";var _emscripten_date_now=()=>Date.now();Module["_emscripten_date_now"]=_emscripten_date_now;_emscripten_date_now.sig="d";function _emscripten_err(str){str>>>=0;return err(UTF8ToString(str))}Module["_emscripten_err"]=_emscripten_err;_emscripten_err.sig="vp";var _emscripten_exit_with_live_runtime=()=>{throw"unwind"};Module["_emscripten_exit_with_live_runtime"]=_emscripten_exit_with_live_runtime;_emscripten_exit_with_live_runtime.sig="v";var getHeapMax=()=>4294901760;Module["getHeapMax"]=getHeapMax;function _emscripten_get_heap_max(){return getHeapMax()}Module["_emscripten_get_heap_max"]=_emscripten_get_heap_max;_emscripten_get_heap_max.sig="p";var _emscripten_get_now_res=()=>{if(ENVIRONMENT_IS_NODE){return 1}return 1e3};Module["_emscripten_get_now_res"]=_emscripten_get_now_res;_emscripten_get_now_res.sig="d";var webgl_enable_ANGLE_instanced_arrays=ctx=>{var ext=ctx.getExtension("ANGLE_instanced_arrays");if(ext){ctx["vertexAttribDivisor"]=(index,divisor)=>ext["vertexAttribDivisorANGLE"](index,divisor);ctx["drawArraysInstanced"]=(mode,first,count,primcount)=>ext["drawArraysInstancedANGLE"](mode,first,count,primcount);ctx["drawElementsInstanced"]=(mode,count,type,indices,primcount)=>ext["drawElementsInstancedANGLE"](mode,count,type,indices,primcount);return 1}};Module["webgl_enable_ANGLE_instanced_arrays"]=webgl_enable_ANGLE_instanced_arrays;var webgl_enable_OES_vertex_array_object=ctx=>{var ext=ctx.getExtension("OES_vertex_array_object");if(ext){ctx["createVertexArray"]=()=>ext["createVertexArrayOES"]();ctx["deleteVertexArray"]=vao=>ext["deleteVertexArrayOES"](vao);ctx["bindVertexArray"]=vao=>ext["bindVertexArrayOES"](vao);ctx["isVertexArray"]=vao=>ext["isVertexArrayOES"](vao);return 1}};Module["webgl_enable_OES_vertex_array_object"]=webgl_enable_OES_vertex_array_object;var webgl_enable_WEBGL_draw_buffers=ctx=>{var ext=ctx.getExtension("WEBGL_draw_buffers");if(ext){ctx["drawBuffers"]=(n,bufs)=>ext["drawBuffersWEBGL"](n,bufs);return 1}};Module["webgl_enable_WEBGL_draw_buffers"]=webgl_enable_WEBGL_draw_buffers;var webgl_enable_WEBGL_multi_draw=ctx=>!!(ctx.multiDrawWebgl=ctx.getExtension("WEBGL_multi_draw"));Module["webgl_enable_WEBGL_multi_draw"]=webgl_enable_WEBGL_multi_draw;var getEmscriptenSupportedExtensions=ctx=>{var supportedExtensions=["ANGLE_instanced_arrays","EXT_blend_minmax","EXT_disjoint_timer_query","EXT_frag_depth","EXT_shader_texture_lod","EXT_sRGB","OES_element_index_uint","OES_fbo_render_mipmap","OES_standard_derivatives","OES_texture_float","OES_texture_half_float","OES_texture_half_float_linear","OES_vertex_array_object","WEBGL_color_buffer_float","WEBGL_depth_texture","WEBGL_draw_buffers","EXT_color_buffer_half_float","EXT_depth_clamp","EXT_float_blend","EXT_texture_compression_bptc","EXT_texture_compression_rgtc","EXT_texture_filter_anisotropic","KHR_parallel_shader_compile","OES_texture_float_linear","WEBGL_blend_func_extended","WEBGL_compressed_texture_astc","WEBGL_compressed_texture_etc","WEBGL_compressed_texture_etc1","WEBGL_compressed_texture_s3tc","WEBGL_compressed_texture_s3tc_srgb","WEBGL_debug_renderer_info","WEBGL_debug_shaders","WEBGL_lose_context","WEBGL_multi_draw"];return(ctx.getSupportedExtensions()||[]).filter(ext=>supportedExtensions.includes(ext))};Module["getEmscriptenSupportedExtensions"]=getEmscriptenSupportedExtensions;var GL={counter:1,buffers:[],programs:[],framebuffers:[],renderbuffers:[],textures:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},queries:[],stringCache:{},unpackAlignment:4,recordError:errorCode=>{if(!GL.lastError){GL.lastError=errorCode}},getNewId:table=>{var ret=GL.counter++;for(var i=table.length;i{for(var i=0;i>>2>>>0]=id}},getSource:(shader,count,string,length)=>{var source="";for(var i=0;i>>2>>>0]:undefined;source+=UTF8ToString(HEAPU32[string+i*4>>>2>>>0],len)}return source},createContext:(canvas,webGLContextAttributes)=>{var ctx=canvas.getContext("webgl",webGLContextAttributes);if(!ctx)return 0;var handle=GL.registerContext(ctx,webGLContextAttributes);return handle},registerContext:(ctx,webGLContextAttributes)=>{var handle=GL.getNewId(GL.contexts);var context={handle:handle,attributes:webGLContextAttributes,version:webGLContextAttributes.majorVersion,GLctx:ctx};if(ctx.canvas)ctx.canvas.GLctxObject=context;GL.contexts[handle]=context;if(typeof webGLContextAttributes.enableExtensionsByDefault=="undefined"||webGLContextAttributes.enableExtensionsByDefault){GL.initExtensions(context)}return handle},makeContextCurrent:contextHandle=>{GL.currentContext=GL.contexts[contextHandle];Module.ctx=GLctx=GL.currentContext?.GLctx;return!(contextHandle&&!GLctx)},getContext:contextHandle=>GL.contexts[contextHandle],deleteContext:contextHandle=>{if(GL.currentContext===GL.contexts[contextHandle]){GL.currentContext=null}if(typeof JSEvents=="object"){JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas)}if(GL.contexts[contextHandle]&&GL.contexts[contextHandle].GLctx.canvas){GL.contexts[contextHandle].GLctx.canvas.GLctxObject=undefined}GL.contexts[contextHandle]=null},initExtensions:context=>{context||=GL.currentContext;if(context.initExtensionsDone)return;context.initExtensionsDone=true;var GLctx=context.GLctx;webgl_enable_ANGLE_instanced_arrays(GLctx);webgl_enable_OES_vertex_array_object(GLctx);webgl_enable_WEBGL_draw_buffers(GLctx);{GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query")}webgl_enable_WEBGL_multi_draw(GLctx);getEmscriptenSupportedExtensions(GLctx).forEach(ext=>{if(!ext.includes("lose_context")&&!ext.includes("debug")){GLctx.getExtension(ext)}})}};Module["GL"]=GL;var _glActiveTexture=x0=>GLctx.activeTexture(x0);Module["_glActiveTexture"]=_glActiveTexture;_glActiveTexture.sig="vi";var _emscripten_glActiveTexture=_glActiveTexture;Module["_emscripten_glActiveTexture"]=_emscripten_glActiveTexture;_emscripten_glActiveTexture.sig="vi";var _glAttachShader=(program,shader)=>{GLctx.attachShader(GL.programs[program],GL.shaders[shader])};Module["_glAttachShader"]=_glAttachShader;_glAttachShader.sig="vii";var _emscripten_glAttachShader=_glAttachShader;Module["_emscripten_glAttachShader"]=_emscripten_glAttachShader;_emscripten_glAttachShader.sig="vii";var _glBeginQueryEXT=(target,id)=>{GLctx.disjointTimerQueryExt["beginQueryEXT"](target,GL.queries[id])};Module["_glBeginQueryEXT"]=_glBeginQueryEXT;_glBeginQueryEXT.sig="vii";var _emscripten_glBeginQueryEXT=_glBeginQueryEXT;Module["_emscripten_glBeginQueryEXT"]=_emscripten_glBeginQueryEXT;function _glBindAttribLocation(program,index,name){name>>>=0;GLctx.bindAttribLocation(GL.programs[program],index,UTF8ToString(name))}Module["_glBindAttribLocation"]=_glBindAttribLocation;_glBindAttribLocation.sig="viip";var _emscripten_glBindAttribLocation=_glBindAttribLocation;Module["_emscripten_glBindAttribLocation"]=_emscripten_glBindAttribLocation;_emscripten_glBindAttribLocation.sig="viip";var _glBindBuffer=(target,buffer)=>{GLctx.bindBuffer(target,GL.buffers[buffer])};Module["_glBindBuffer"]=_glBindBuffer;_glBindBuffer.sig="vii";var _emscripten_glBindBuffer=_glBindBuffer;Module["_emscripten_glBindBuffer"]=_emscripten_glBindBuffer;_emscripten_glBindBuffer.sig="vii";var _glBindFramebuffer=(target,framebuffer)=>{GLctx.bindFramebuffer(target,GL.framebuffers[framebuffer])};Module["_glBindFramebuffer"]=_glBindFramebuffer;_glBindFramebuffer.sig="vii";var _emscripten_glBindFramebuffer=_glBindFramebuffer;Module["_emscripten_glBindFramebuffer"]=_emscripten_glBindFramebuffer;_emscripten_glBindFramebuffer.sig="vii";var _glBindRenderbuffer=(target,renderbuffer)=>{GLctx.bindRenderbuffer(target,GL.renderbuffers[renderbuffer])};Module["_glBindRenderbuffer"]=_glBindRenderbuffer;_glBindRenderbuffer.sig="vii";var _emscripten_glBindRenderbuffer=_glBindRenderbuffer;Module["_emscripten_glBindRenderbuffer"]=_emscripten_glBindRenderbuffer;_emscripten_glBindRenderbuffer.sig="vii";var _glBindTexture=(target,texture)=>{GLctx.bindTexture(target,GL.textures[texture])};Module["_glBindTexture"]=_glBindTexture;_glBindTexture.sig="vii";var _emscripten_glBindTexture=_glBindTexture;Module["_emscripten_glBindTexture"]=_emscripten_glBindTexture;_emscripten_glBindTexture.sig="vii";var _glBindVertexArray=vao=>{GLctx.bindVertexArray(GL.vaos[vao])};Module["_glBindVertexArray"]=_glBindVertexArray;_glBindVertexArray.sig="vi";var _glBindVertexArrayOES=_glBindVertexArray;Module["_glBindVertexArrayOES"]=_glBindVertexArrayOES;_glBindVertexArrayOES.sig="vi";var _emscripten_glBindVertexArrayOES=_glBindVertexArrayOES;Module["_emscripten_glBindVertexArrayOES"]=_emscripten_glBindVertexArrayOES;_emscripten_glBindVertexArrayOES.sig="vi";var _glBlendColor=(x0,x1,x2,x3)=>GLctx.blendColor(x0,x1,x2,x3);Module["_glBlendColor"]=_glBlendColor;_glBlendColor.sig="vffff";var _emscripten_glBlendColor=_glBlendColor;Module["_emscripten_glBlendColor"]=_emscripten_glBlendColor;_emscripten_glBlendColor.sig="vffff";var _glBlendEquation=x0=>GLctx.blendEquation(x0);Module["_glBlendEquation"]=_glBlendEquation;_glBlendEquation.sig="vi";var _emscripten_glBlendEquation=_glBlendEquation;Module["_emscripten_glBlendEquation"]=_emscripten_glBlendEquation;_emscripten_glBlendEquation.sig="vi";var _glBlendEquationSeparate=(x0,x1)=>GLctx.blendEquationSeparate(x0,x1);Module["_glBlendEquationSeparate"]=_glBlendEquationSeparate;_glBlendEquationSeparate.sig="vii";var _emscripten_glBlendEquationSeparate=_glBlendEquationSeparate;Module["_emscripten_glBlendEquationSeparate"]=_emscripten_glBlendEquationSeparate;_emscripten_glBlendEquationSeparate.sig="vii";var _glBlendFunc=(x0,x1)=>GLctx.blendFunc(x0,x1);Module["_glBlendFunc"]=_glBlendFunc;_glBlendFunc.sig="vii";var _emscripten_glBlendFunc=_glBlendFunc;Module["_emscripten_glBlendFunc"]=_emscripten_glBlendFunc;_emscripten_glBlendFunc.sig="vii";var _glBlendFuncSeparate=(x0,x1,x2,x3)=>GLctx.blendFuncSeparate(x0,x1,x2,x3);Module["_glBlendFuncSeparate"]=_glBlendFuncSeparate;_glBlendFuncSeparate.sig="viiii";var _emscripten_glBlendFuncSeparate=_glBlendFuncSeparate;Module["_emscripten_glBlendFuncSeparate"]=_emscripten_glBlendFuncSeparate;_emscripten_glBlendFuncSeparate.sig="viiii";function _glBufferData(target,size,data,usage){size>>>=0;data>>>=0;GLctx.bufferData(target,data?HEAPU8.subarray(data>>>0,data+size>>>0):size,usage)}Module["_glBufferData"]=_glBufferData;_glBufferData.sig="vippi";var _emscripten_glBufferData=_glBufferData;Module["_emscripten_glBufferData"]=_emscripten_glBufferData;_emscripten_glBufferData.sig="vippi";function _glBufferSubData(target,offset,size,data){offset>>>=0;size>>>=0;data>>>=0;GLctx.bufferSubData(target,offset,HEAPU8.subarray(data>>>0,data+size>>>0))}Module["_glBufferSubData"]=_glBufferSubData;_glBufferSubData.sig="vippp";var _emscripten_glBufferSubData=_glBufferSubData;Module["_emscripten_glBufferSubData"]=_emscripten_glBufferSubData;_emscripten_glBufferSubData.sig="vippp";var _glCheckFramebufferStatus=x0=>GLctx.checkFramebufferStatus(x0);Module["_glCheckFramebufferStatus"]=_glCheckFramebufferStatus;_glCheckFramebufferStatus.sig="ii";var _emscripten_glCheckFramebufferStatus=_glCheckFramebufferStatus;Module["_emscripten_glCheckFramebufferStatus"]=_emscripten_glCheckFramebufferStatus;_emscripten_glCheckFramebufferStatus.sig="ii";var _glClear=x0=>GLctx.clear(x0);Module["_glClear"]=_glClear;_glClear.sig="vi";var _emscripten_glClear=_glClear;Module["_emscripten_glClear"]=_emscripten_glClear;_emscripten_glClear.sig="vi";var _glClearColor=(x0,x1,x2,x3)=>GLctx.clearColor(x0,x1,x2,x3);Module["_glClearColor"]=_glClearColor;_glClearColor.sig="vffff";var _emscripten_glClearColor=_glClearColor;Module["_emscripten_glClearColor"]=_emscripten_glClearColor;_emscripten_glClearColor.sig="vffff";var _glClearDepthf=x0=>GLctx.clearDepth(x0);Module["_glClearDepthf"]=_glClearDepthf;_glClearDepthf.sig="vf";var _emscripten_glClearDepthf=_glClearDepthf;Module["_emscripten_glClearDepthf"]=_emscripten_glClearDepthf;_emscripten_glClearDepthf.sig="vf";var _glClearStencil=x0=>GLctx.clearStencil(x0);Module["_glClearStencil"]=_glClearStencil;_glClearStencil.sig="vi";var _emscripten_glClearStencil=_glClearStencil;Module["_emscripten_glClearStencil"]=_emscripten_glClearStencil;_emscripten_glClearStencil.sig="vi";var _glColorMask=(red,green,blue,alpha)=>{GLctx.colorMask(!!red,!!green,!!blue,!!alpha)};Module["_glColorMask"]=_glColorMask;_glColorMask.sig="viiii";var _emscripten_glColorMask=_glColorMask;Module["_emscripten_glColorMask"]=_emscripten_glColorMask;_emscripten_glColorMask.sig="viiii";var _glCompileShader=shader=>{GLctx.compileShader(GL.shaders[shader])};Module["_glCompileShader"]=_glCompileShader;_glCompileShader.sig="vi";var _emscripten_glCompileShader=_glCompileShader;Module["_emscripten_glCompileShader"]=_emscripten_glCompileShader;_emscripten_glCompileShader.sig="vi";function _glCompressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data){data>>>=0;GLctx.compressedTexImage2D(target,level,internalFormat,width,height,border,data?HEAPU8.subarray(data>>>0,data+imageSize>>>0):null)}Module["_glCompressedTexImage2D"]=_glCompressedTexImage2D;_glCompressedTexImage2D.sig="viiiiiiip";var _emscripten_glCompressedTexImage2D=_glCompressedTexImage2D;Module["_emscripten_glCompressedTexImage2D"]=_emscripten_glCompressedTexImage2D;_emscripten_glCompressedTexImage2D.sig="viiiiiiip";function _glCompressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,imageSize,data){data>>>=0;GLctx.compressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,data?HEAPU8.subarray(data>>>0,data+imageSize>>>0):null)}Module["_glCompressedTexSubImage2D"]=_glCompressedTexSubImage2D;_glCompressedTexSubImage2D.sig="viiiiiiiip";var _emscripten_glCompressedTexSubImage2D=_glCompressedTexSubImage2D;Module["_emscripten_glCompressedTexSubImage2D"]=_emscripten_glCompressedTexSubImage2D;_emscripten_glCompressedTexSubImage2D.sig="viiiiiiiip";var _glCopyTexImage2D=(x0,x1,x2,x3,x4,x5,x6,x7)=>GLctx.copyTexImage2D(x0,x1,x2,x3,x4,x5,x6,x7);Module["_glCopyTexImage2D"]=_glCopyTexImage2D;_glCopyTexImage2D.sig="viiiiiiii";var _emscripten_glCopyTexImage2D=_glCopyTexImage2D;Module["_emscripten_glCopyTexImage2D"]=_emscripten_glCopyTexImage2D;_emscripten_glCopyTexImage2D.sig="viiiiiiii";var _glCopyTexSubImage2D=(x0,x1,x2,x3,x4,x5,x6,x7)=>GLctx.copyTexSubImage2D(x0,x1,x2,x3,x4,x5,x6,x7);Module["_glCopyTexSubImage2D"]=_glCopyTexSubImage2D;_glCopyTexSubImage2D.sig="viiiiiiii";var _emscripten_glCopyTexSubImage2D=_glCopyTexSubImage2D;Module["_emscripten_glCopyTexSubImage2D"]=_emscripten_glCopyTexSubImage2D;_emscripten_glCopyTexSubImage2D.sig="viiiiiiii";var _glCreateProgram=()=>{var id=GL.getNewId(GL.programs);var program=GLctx.createProgram();program.name=id;program.maxUniformLength=program.maxAttributeLength=program.maxUniformBlockNameLength=0;program.uniformIdCounter=1;GL.programs[id]=program;return id};Module["_glCreateProgram"]=_glCreateProgram;_glCreateProgram.sig="i";var _emscripten_glCreateProgram=_glCreateProgram;Module["_emscripten_glCreateProgram"]=_emscripten_glCreateProgram;_emscripten_glCreateProgram.sig="i";var _glCreateShader=shaderType=>{var id=GL.getNewId(GL.shaders);GL.shaders[id]=GLctx.createShader(shaderType);return id};Module["_glCreateShader"]=_glCreateShader;_glCreateShader.sig="ii";var _emscripten_glCreateShader=_glCreateShader;Module["_emscripten_glCreateShader"]=_emscripten_glCreateShader;_emscripten_glCreateShader.sig="ii";var _glCullFace=x0=>GLctx.cullFace(x0);Module["_glCullFace"]=_glCullFace;_glCullFace.sig="vi";var _emscripten_glCullFace=_glCullFace;Module["_emscripten_glCullFace"]=_emscripten_glCullFace;_emscripten_glCullFace.sig="vi";function _glDeleteBuffers(n,buffers){buffers>>>=0;for(var i=0;i>>2>>>0];var buffer=GL.buffers[id];if(!buffer)continue;GLctx.deleteBuffer(buffer);buffer.name=0;GL.buffers[id]=null}}Module["_glDeleteBuffers"]=_glDeleteBuffers;_glDeleteBuffers.sig="vip";var _emscripten_glDeleteBuffers=_glDeleteBuffers;Module["_emscripten_glDeleteBuffers"]=_emscripten_glDeleteBuffers;_emscripten_glDeleteBuffers.sig="vip";function _glDeleteFramebuffers(n,framebuffers){framebuffers>>>=0;for(var i=0;i>>2>>>0];var framebuffer=GL.framebuffers[id];if(!framebuffer)continue;GLctx.deleteFramebuffer(framebuffer);framebuffer.name=0;GL.framebuffers[id]=null}}Module["_glDeleteFramebuffers"]=_glDeleteFramebuffers;_glDeleteFramebuffers.sig="vip";var _emscripten_glDeleteFramebuffers=_glDeleteFramebuffers;Module["_emscripten_glDeleteFramebuffers"]=_emscripten_glDeleteFramebuffers;_emscripten_glDeleteFramebuffers.sig="vip";var _glDeleteProgram=id=>{if(!id)return;var program=GL.programs[id];if(!program){GL.recordError(1281);return}GLctx.deleteProgram(program);program.name=0;GL.programs[id]=null};Module["_glDeleteProgram"]=_glDeleteProgram;_glDeleteProgram.sig="vi";var _emscripten_glDeleteProgram=_glDeleteProgram;Module["_emscripten_glDeleteProgram"]=_emscripten_glDeleteProgram;_emscripten_glDeleteProgram.sig="vi";function _glDeleteQueriesEXT(n,ids){ids>>>=0;for(var i=0;i>>2>>>0];var query=GL.queries[id];if(!query)continue;GLctx.disjointTimerQueryExt["deleteQueryEXT"](query);GL.queries[id]=null}}Module["_glDeleteQueriesEXT"]=_glDeleteQueriesEXT;_glDeleteQueriesEXT.sig="vip";var _emscripten_glDeleteQueriesEXT=_glDeleteQueriesEXT;Module["_emscripten_glDeleteQueriesEXT"]=_emscripten_glDeleteQueriesEXT;function _glDeleteRenderbuffers(n,renderbuffers){renderbuffers>>>=0;for(var i=0;i>>2>>>0];var renderbuffer=GL.renderbuffers[id];if(!renderbuffer)continue;GLctx.deleteRenderbuffer(renderbuffer);renderbuffer.name=0;GL.renderbuffers[id]=null}}Module["_glDeleteRenderbuffers"]=_glDeleteRenderbuffers;_glDeleteRenderbuffers.sig="vip";var _emscripten_glDeleteRenderbuffers=_glDeleteRenderbuffers;Module["_emscripten_glDeleteRenderbuffers"]=_emscripten_glDeleteRenderbuffers;_emscripten_glDeleteRenderbuffers.sig="vip";var _glDeleteShader=id=>{if(!id)return;var shader=GL.shaders[id];if(!shader){GL.recordError(1281);return}GLctx.deleteShader(shader);GL.shaders[id]=null};Module["_glDeleteShader"]=_glDeleteShader;_glDeleteShader.sig="vi";var _emscripten_glDeleteShader=_glDeleteShader;Module["_emscripten_glDeleteShader"]=_emscripten_glDeleteShader;_emscripten_glDeleteShader.sig="vi";function _glDeleteTextures(n,textures){textures>>>=0;for(var i=0;i>>2>>>0];var texture=GL.textures[id];if(!texture)continue;GLctx.deleteTexture(texture);texture.name=0;GL.textures[id]=null}}Module["_glDeleteTextures"]=_glDeleteTextures;_glDeleteTextures.sig="vip";var _emscripten_glDeleteTextures=_glDeleteTextures;Module["_emscripten_glDeleteTextures"]=_emscripten_glDeleteTextures;_emscripten_glDeleteTextures.sig="vip";function _glDeleteVertexArrays(n,vaos){vaos>>>=0;for(var i=0;i>>2>>>0];GLctx.deleteVertexArray(GL.vaos[id]);GL.vaos[id]=null}}Module["_glDeleteVertexArrays"]=_glDeleteVertexArrays;_glDeleteVertexArrays.sig="vip";var _glDeleteVertexArraysOES=_glDeleteVertexArrays;Module["_glDeleteVertexArraysOES"]=_glDeleteVertexArraysOES;_glDeleteVertexArraysOES.sig="vip";var _emscripten_glDeleteVertexArraysOES=_glDeleteVertexArraysOES;Module["_emscripten_glDeleteVertexArraysOES"]=_emscripten_glDeleteVertexArraysOES;_emscripten_glDeleteVertexArraysOES.sig="vip";var _glDepthFunc=x0=>GLctx.depthFunc(x0);Module["_glDepthFunc"]=_glDepthFunc;_glDepthFunc.sig="vi";var _emscripten_glDepthFunc=_glDepthFunc;Module["_emscripten_glDepthFunc"]=_emscripten_glDepthFunc;_emscripten_glDepthFunc.sig="vi";var _glDepthMask=flag=>{GLctx.depthMask(!!flag)};Module["_glDepthMask"]=_glDepthMask;_glDepthMask.sig="vi";var _emscripten_glDepthMask=_glDepthMask;Module["_emscripten_glDepthMask"]=_emscripten_glDepthMask;_emscripten_glDepthMask.sig="vi";var _glDepthRangef=(x0,x1)=>GLctx.depthRange(x0,x1);Module["_glDepthRangef"]=_glDepthRangef;_glDepthRangef.sig="vff";var _emscripten_glDepthRangef=_glDepthRangef;Module["_emscripten_glDepthRangef"]=_emscripten_glDepthRangef;_emscripten_glDepthRangef.sig="vff";var _glDetachShader=(program,shader)=>{GLctx.detachShader(GL.programs[program],GL.shaders[shader])};Module["_glDetachShader"]=_glDetachShader;_glDetachShader.sig="vii";var _emscripten_glDetachShader=_glDetachShader;Module["_emscripten_glDetachShader"]=_emscripten_glDetachShader;_emscripten_glDetachShader.sig="vii";var _glDisable=x0=>GLctx.disable(x0);Module["_glDisable"]=_glDisable;_glDisable.sig="vi";var _emscripten_glDisable=_glDisable;Module["_emscripten_glDisable"]=_emscripten_glDisable;_emscripten_glDisable.sig="vi";var _glDisableVertexAttribArray=index=>{GLctx.disableVertexAttribArray(index)};Module["_glDisableVertexAttribArray"]=_glDisableVertexAttribArray;_glDisableVertexAttribArray.sig="vi";var _emscripten_glDisableVertexAttribArray=_glDisableVertexAttribArray;Module["_emscripten_glDisableVertexAttribArray"]=_emscripten_glDisableVertexAttribArray;_emscripten_glDisableVertexAttribArray.sig="vi";var _glDrawArrays=(mode,first,count)=>{GLctx.drawArrays(mode,first,count)};Module["_glDrawArrays"]=_glDrawArrays;_glDrawArrays.sig="viii";var _emscripten_glDrawArrays=_glDrawArrays;Module["_emscripten_glDrawArrays"]=_emscripten_glDrawArrays;_emscripten_glDrawArrays.sig="viii";var _glDrawArraysInstanced=(mode,first,count,primcount)=>{GLctx.drawArraysInstanced(mode,first,count,primcount)};Module["_glDrawArraysInstanced"]=_glDrawArraysInstanced;_glDrawArraysInstanced.sig="viiii";var _glDrawArraysInstancedANGLE=_glDrawArraysInstanced;Module["_glDrawArraysInstancedANGLE"]=_glDrawArraysInstancedANGLE;var _emscripten_glDrawArraysInstancedANGLE=_glDrawArraysInstancedANGLE;Module["_emscripten_glDrawArraysInstancedANGLE"]=_emscripten_glDrawArraysInstancedANGLE;var tempFixedLengthArray=[];Module["tempFixedLengthArray"]=tempFixedLengthArray;function _glDrawBuffers(n,bufs){bufs>>>=0;var bufArray=tempFixedLengthArray[n];for(var i=0;i>>2>>>0]}GLctx.drawBuffers(bufArray)}Module["_glDrawBuffers"]=_glDrawBuffers;_glDrawBuffers.sig="vip";var _glDrawBuffersWEBGL=_glDrawBuffers;Module["_glDrawBuffersWEBGL"]=_glDrawBuffersWEBGL;var _emscripten_glDrawBuffersWEBGL=_glDrawBuffersWEBGL;Module["_emscripten_glDrawBuffersWEBGL"]=_emscripten_glDrawBuffersWEBGL;function _glDrawElements(mode,count,type,indices){indices>>>=0;GLctx.drawElements(mode,count,type,indices)}Module["_glDrawElements"]=_glDrawElements;_glDrawElements.sig="viiip";var _emscripten_glDrawElements=_glDrawElements;Module["_emscripten_glDrawElements"]=_emscripten_glDrawElements;_emscripten_glDrawElements.sig="viiip";function _glDrawElementsInstanced(mode,count,type,indices,primcount){indices>>>=0;GLctx.drawElementsInstanced(mode,count,type,indices,primcount)}Module["_glDrawElementsInstanced"]=_glDrawElementsInstanced;_glDrawElementsInstanced.sig="viiipi";var _glDrawElementsInstancedANGLE=_glDrawElementsInstanced;Module["_glDrawElementsInstancedANGLE"]=_glDrawElementsInstancedANGLE;var _emscripten_glDrawElementsInstancedANGLE=_glDrawElementsInstancedANGLE;Module["_emscripten_glDrawElementsInstancedANGLE"]=_emscripten_glDrawElementsInstancedANGLE;var _glEnable=x0=>GLctx.enable(x0);Module["_glEnable"]=_glEnable;_glEnable.sig="vi";var _emscripten_glEnable=_glEnable;Module["_emscripten_glEnable"]=_emscripten_glEnable;_emscripten_glEnable.sig="vi";var _glEnableVertexAttribArray=index=>{GLctx.enableVertexAttribArray(index)};Module["_glEnableVertexAttribArray"]=_glEnableVertexAttribArray;_glEnableVertexAttribArray.sig="vi";var _emscripten_glEnableVertexAttribArray=_glEnableVertexAttribArray;Module["_emscripten_glEnableVertexAttribArray"]=_emscripten_glEnableVertexAttribArray;_emscripten_glEnableVertexAttribArray.sig="vi";var _glEndQueryEXT=target=>{GLctx.disjointTimerQueryExt["endQueryEXT"](target)};Module["_glEndQueryEXT"]=_glEndQueryEXT;_glEndQueryEXT.sig="vi";var _emscripten_glEndQueryEXT=_glEndQueryEXT;Module["_emscripten_glEndQueryEXT"]=_emscripten_glEndQueryEXT;var _glFinish=()=>GLctx.finish();Module["_glFinish"]=_glFinish;_glFinish.sig="v";var _emscripten_glFinish=_glFinish;Module["_emscripten_glFinish"]=_emscripten_glFinish;_emscripten_glFinish.sig="v";var _glFlush=()=>GLctx.flush();Module["_glFlush"]=_glFlush;_glFlush.sig="v";var _emscripten_glFlush=_glFlush;Module["_emscripten_glFlush"]=_emscripten_glFlush;_emscripten_glFlush.sig="v";var _glFramebufferRenderbuffer=(target,attachment,renderbuffertarget,renderbuffer)=>{GLctx.framebufferRenderbuffer(target,attachment,renderbuffertarget,GL.renderbuffers[renderbuffer])};Module["_glFramebufferRenderbuffer"]=_glFramebufferRenderbuffer;_glFramebufferRenderbuffer.sig="viiii";var _emscripten_glFramebufferRenderbuffer=_glFramebufferRenderbuffer;Module["_emscripten_glFramebufferRenderbuffer"]=_emscripten_glFramebufferRenderbuffer;_emscripten_glFramebufferRenderbuffer.sig="viiii";var _glFramebufferTexture2D=(target,attachment,textarget,texture,level)=>{GLctx.framebufferTexture2D(target,attachment,textarget,GL.textures[texture],level)};Module["_glFramebufferTexture2D"]=_glFramebufferTexture2D;_glFramebufferTexture2D.sig="viiiii";var _emscripten_glFramebufferTexture2D=_glFramebufferTexture2D;Module["_emscripten_glFramebufferTexture2D"]=_emscripten_glFramebufferTexture2D;_emscripten_glFramebufferTexture2D.sig="viiiii";var _glFrontFace=x0=>GLctx.frontFace(x0);Module["_glFrontFace"]=_glFrontFace;_glFrontFace.sig="vi";var _emscripten_glFrontFace=_glFrontFace;Module["_emscripten_glFrontFace"]=_emscripten_glFrontFace;_emscripten_glFrontFace.sig="vi";function _glGenBuffers(n,buffers){buffers>>>=0;GL.genObject(n,buffers,"createBuffer",GL.buffers)}Module["_glGenBuffers"]=_glGenBuffers;_glGenBuffers.sig="vip";var _emscripten_glGenBuffers=_glGenBuffers;Module["_emscripten_glGenBuffers"]=_emscripten_glGenBuffers;_emscripten_glGenBuffers.sig="vip";function _glGenFramebuffers(n,ids){ids>>>=0;GL.genObject(n,ids,"createFramebuffer",GL.framebuffers)}Module["_glGenFramebuffers"]=_glGenFramebuffers;_glGenFramebuffers.sig="vip";var _emscripten_glGenFramebuffers=_glGenFramebuffers;Module["_emscripten_glGenFramebuffers"]=_emscripten_glGenFramebuffers;_emscripten_glGenFramebuffers.sig="vip";function _glGenQueriesEXT(n,ids){ids>>>=0;for(var i=0;i>>2>>>0]=0;return}var id=GL.getNewId(GL.queries);query.name=id;GL.queries[id]=query;HEAP32[ids+i*4>>>2>>>0]=id}}Module["_glGenQueriesEXT"]=_glGenQueriesEXT;_glGenQueriesEXT.sig="vip";var _emscripten_glGenQueriesEXT=_glGenQueriesEXT;Module["_emscripten_glGenQueriesEXT"]=_emscripten_glGenQueriesEXT;function _glGenRenderbuffers(n,renderbuffers){renderbuffers>>>=0;GL.genObject(n,renderbuffers,"createRenderbuffer",GL.renderbuffers)}Module["_glGenRenderbuffers"]=_glGenRenderbuffers;_glGenRenderbuffers.sig="vip";var _emscripten_glGenRenderbuffers=_glGenRenderbuffers;Module["_emscripten_glGenRenderbuffers"]=_emscripten_glGenRenderbuffers;_emscripten_glGenRenderbuffers.sig="vip";function _glGenTextures(n,textures){textures>>>=0;GL.genObject(n,textures,"createTexture",GL.textures)}Module["_glGenTextures"]=_glGenTextures;_glGenTextures.sig="vip";var _emscripten_glGenTextures=_glGenTextures;Module["_emscripten_glGenTextures"]=_emscripten_glGenTextures;_emscripten_glGenTextures.sig="vip";function _glGenVertexArrays(n,arrays){arrays>>>=0;GL.genObject(n,arrays,"createVertexArray",GL.vaos)}Module["_glGenVertexArrays"]=_glGenVertexArrays;_glGenVertexArrays.sig="vip";var _glGenVertexArraysOES=_glGenVertexArrays;Module["_glGenVertexArraysOES"]=_glGenVertexArraysOES;_glGenVertexArraysOES.sig="vip";var _emscripten_glGenVertexArraysOES=_glGenVertexArraysOES;Module["_emscripten_glGenVertexArraysOES"]=_emscripten_glGenVertexArraysOES;_emscripten_glGenVertexArraysOES.sig="vip";var _glGenerateMipmap=x0=>GLctx.generateMipmap(x0);Module["_glGenerateMipmap"]=_glGenerateMipmap;_glGenerateMipmap.sig="vi";var _emscripten_glGenerateMipmap=_glGenerateMipmap;Module["_emscripten_glGenerateMipmap"]=_emscripten_glGenerateMipmap;_emscripten_glGenerateMipmap.sig="vi";var __glGetActiveAttribOrUniform=(funcName,program,index,bufSize,length,size,type,name)=>{program=GL.programs[program];var info=GLctx[funcName](program,index);if(info){var numBytesWrittenExclNull=name&&stringToUTF8(info.name,name,bufSize);if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull;if(size)HEAP32[size>>>2>>>0]=info.size;if(type)HEAP32[type>>>2>>>0]=info.type}};Module["__glGetActiveAttribOrUniform"]=__glGetActiveAttribOrUniform;function _glGetActiveAttrib(program,index,bufSize,length,size,type,name){length>>>=0;size>>>=0;type>>>=0;name>>>=0;__glGetActiveAttribOrUniform("getActiveAttrib",program,index,bufSize,length,size,type,name)}Module["_glGetActiveAttrib"]=_glGetActiveAttrib;_glGetActiveAttrib.sig="viiipppp";var _emscripten_glGetActiveAttrib=_glGetActiveAttrib;Module["_emscripten_glGetActiveAttrib"]=_emscripten_glGetActiveAttrib;_emscripten_glGetActiveAttrib.sig="viiipppp";function _glGetActiveUniform(program,index,bufSize,length,size,type,name){length>>>=0;size>>>=0;type>>>=0;name>>>=0;__glGetActiveAttribOrUniform("getActiveUniform",program,index,bufSize,length,size,type,name)}Module["_glGetActiveUniform"]=_glGetActiveUniform;_glGetActiveUniform.sig="viiipppp";var _emscripten_glGetActiveUniform=_glGetActiveUniform;Module["_emscripten_glGetActiveUniform"]=_emscripten_glGetActiveUniform;_emscripten_glGetActiveUniform.sig="viiipppp";function _glGetAttachedShaders(program,maxCount,count,shaders){count>>>=0;shaders>>>=0;var result=GLctx.getAttachedShaders(GL.programs[program]);var len=result.length;if(len>maxCount){len=maxCount}HEAP32[count>>>2>>>0]=len;for(var i=0;i>>2>>>0]=id}}Module["_glGetAttachedShaders"]=_glGetAttachedShaders;_glGetAttachedShaders.sig="viipp";var _emscripten_glGetAttachedShaders=_glGetAttachedShaders;Module["_emscripten_glGetAttachedShaders"]=_emscripten_glGetAttachedShaders;_emscripten_glGetAttachedShaders.sig="viipp";function _glGetAttribLocation(program,name){name>>>=0;return GLctx.getAttribLocation(GL.programs[program],UTF8ToString(name))}Module["_glGetAttribLocation"]=_glGetAttribLocation;_glGetAttribLocation.sig="iip";var _emscripten_glGetAttribLocation=_glGetAttribLocation;Module["_emscripten_glGetAttribLocation"]=_emscripten_glGetAttribLocation;_emscripten_glGetAttribLocation.sig="iip";var writeI53ToI64=(ptr,num)=>{HEAPU32[ptr>>>2>>>0]=num;var lower=HEAPU32[ptr>>>2>>>0];HEAPU32[ptr+4>>>2>>>0]=(num-lower)/4294967296};Module["writeI53ToI64"]=writeI53ToI64;var emscriptenWebGLGet=(name_,p,type)=>{if(!p){GL.recordError(1281);return}var ret=undefined;switch(name_){case 36346:ret=1;break;case 36344:if(type!=0&&type!=1){GL.recordError(1280)}return;case 36345:ret=0;break;case 34466:var formats=GLctx.getParameter(34467);ret=formats?formats.length:0;break}if(ret===undefined){var result=GLctx.getParameter(name_);switch(typeof result){case"number":ret=result;break;case"boolean":ret=result?1:0;break;case"string":GL.recordError(1280);return;case"object":if(result===null){switch(name_){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 34068:{ret=0;break}default:{GL.recordError(1280);return}}}else if(result instanceof Float32Array||result instanceof Uint32Array||result instanceof Int32Array||result instanceof Array){for(var i=0;i>>2>>>0]=result[i];break;case 2:HEAPF32[p+i*4>>>2>>>0]=result[i];break;case 4:HEAP8[p+i>>>0]=result[i]?1:0;break}}return}else{try{ret=result.name|0}catch(e){GL.recordError(1280);err(`GL_INVALID_ENUM in glGet${type}v: Unknown object returned from WebGL getParameter(${name_})! (error: ${e})`);return}}break;default:GL.recordError(1280);err(`GL_INVALID_ENUM in glGet${type}v: Native code calling glGet${type}v(${name_}) and it returns ${result} of type ${typeof result}!`);return}}switch(type){case 1:writeI53ToI64(p,ret);break;case 0:HEAP32[p>>>2>>>0]=ret;break;case 2:HEAPF32[p>>>2>>>0]=ret;break;case 4:HEAP8[p>>>0]=ret?1:0;break}};Module["emscriptenWebGLGet"]=emscriptenWebGLGet;function _glGetBooleanv(name_,p){p>>>=0;return emscriptenWebGLGet(name_,p,4)}Module["_glGetBooleanv"]=_glGetBooleanv;_glGetBooleanv.sig="vip";var _emscripten_glGetBooleanv=_glGetBooleanv;Module["_emscripten_glGetBooleanv"]=_emscripten_glGetBooleanv;_emscripten_glGetBooleanv.sig="vip";function _glGetBufferParameteriv(target,value,data){data>>>=0;if(!data){GL.recordError(1281);return}HEAP32[data>>>2>>>0]=GLctx.getBufferParameter(target,value)}Module["_glGetBufferParameteriv"]=_glGetBufferParameteriv;_glGetBufferParameteriv.sig="viip";var _emscripten_glGetBufferParameteriv=_glGetBufferParameteriv;Module["_emscripten_glGetBufferParameteriv"]=_emscripten_glGetBufferParameteriv;_emscripten_glGetBufferParameteriv.sig="viip";var _glGetError=()=>{var error=GLctx.getError()||GL.lastError;GL.lastError=0;return error};Module["_glGetError"]=_glGetError;_glGetError.sig="i";var _emscripten_glGetError=_glGetError;Module["_emscripten_glGetError"]=_emscripten_glGetError;_emscripten_glGetError.sig="i";function _glGetFloatv(name_,p){p>>>=0;return emscriptenWebGLGet(name_,p,2)}Module["_glGetFloatv"]=_glGetFloatv;_glGetFloatv.sig="vip";var _emscripten_glGetFloatv=_glGetFloatv;Module["_emscripten_glGetFloatv"]=_emscripten_glGetFloatv;_emscripten_glGetFloatv.sig="vip";function _glGetFramebufferAttachmentParameteriv(target,attachment,pname,params){params>>>=0;var result=GLctx.getFramebufferAttachmentParameter(target,attachment,pname);if(result instanceof WebGLRenderbuffer||result instanceof WebGLTexture){result=result.name|0}HEAP32[params>>>2>>>0]=result}Module["_glGetFramebufferAttachmentParameteriv"]=_glGetFramebufferAttachmentParameteriv;_glGetFramebufferAttachmentParameteriv.sig="viiip";var _emscripten_glGetFramebufferAttachmentParameteriv=_glGetFramebufferAttachmentParameteriv;Module["_emscripten_glGetFramebufferAttachmentParameteriv"]=_emscripten_glGetFramebufferAttachmentParameteriv;_emscripten_glGetFramebufferAttachmentParameteriv.sig="viiip";function _glGetIntegerv(name_,p){p>>>=0;return emscriptenWebGLGet(name_,p,0)}Module["_glGetIntegerv"]=_glGetIntegerv;_glGetIntegerv.sig="vip";var _emscripten_glGetIntegerv=_glGetIntegerv;Module["_emscripten_glGetIntegerv"]=_emscripten_glGetIntegerv;_emscripten_glGetIntegerv.sig="vip";function _glGetProgramInfoLog(program,maxLength,length,infoLog){length>>>=0;infoLog>>>=0;var log=GLctx.getProgramInfoLog(GL.programs[program]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}Module["_glGetProgramInfoLog"]=_glGetProgramInfoLog;_glGetProgramInfoLog.sig="viipp";var _emscripten_glGetProgramInfoLog=_glGetProgramInfoLog;Module["_emscripten_glGetProgramInfoLog"]=_emscripten_glGetProgramInfoLog;_emscripten_glGetProgramInfoLog.sig="viipp";function _glGetProgramiv(program,pname,p){p>>>=0;if(!p){GL.recordError(1281);return}if(program>=GL.counter){GL.recordError(1281);return}program=GL.programs[program];if(pname==35716){var log=GLctx.getProgramInfoLog(program);if(log===null)log="(unknown error)";HEAP32[p>>>2>>>0]=log.length+1}else if(pname==35719){if(!program.maxUniformLength){for(var i=0;i>>2>>>0]=program.maxUniformLength}else if(pname==35722){if(!program.maxAttributeLength){for(var i=0;i>>2>>>0]=program.maxAttributeLength}else if(pname==35381){if(!program.maxUniformBlockNameLength){for(var i=0;i>>2>>>0]=program.maxUniformBlockNameLength}else{HEAP32[p>>>2>>>0]=GLctx.getProgramParameter(program,pname)}}Module["_glGetProgramiv"]=_glGetProgramiv;_glGetProgramiv.sig="viip";var _emscripten_glGetProgramiv=_glGetProgramiv;Module["_emscripten_glGetProgramiv"]=_emscripten_glGetProgramiv;_emscripten_glGetProgramiv.sig="viip";function _glGetQueryObjecti64vEXT(id,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param;{param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname)}var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}writeI53ToI64(params,ret)}Module["_glGetQueryObjecti64vEXT"]=_glGetQueryObjecti64vEXT;_glGetQueryObjecti64vEXT.sig="viip";var _emscripten_glGetQueryObjecti64vEXT=_glGetQueryObjecti64vEXT;Module["_emscripten_glGetQueryObjecti64vEXT"]=_emscripten_glGetQueryObjecti64vEXT;function _glGetQueryObjectivEXT(id,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>>2>>>0]=ret}Module["_glGetQueryObjectivEXT"]=_glGetQueryObjectivEXT;_glGetQueryObjectivEXT.sig="viip";var _emscripten_glGetQueryObjectivEXT=_glGetQueryObjectivEXT;Module["_emscripten_glGetQueryObjectivEXT"]=_emscripten_glGetQueryObjectivEXT;var _glGetQueryObjectui64vEXT=_glGetQueryObjecti64vEXT;Module["_glGetQueryObjectui64vEXT"]=_glGetQueryObjectui64vEXT;var _emscripten_glGetQueryObjectui64vEXT=_glGetQueryObjectui64vEXT;Module["_emscripten_glGetQueryObjectui64vEXT"]=_emscripten_glGetQueryObjectui64vEXT;var _glGetQueryObjectuivEXT=_glGetQueryObjectivEXT;Module["_glGetQueryObjectuivEXT"]=_glGetQueryObjectuivEXT;var _emscripten_glGetQueryObjectuivEXT=_glGetQueryObjectuivEXT;Module["_emscripten_glGetQueryObjectuivEXT"]=_emscripten_glGetQueryObjectuivEXT;function _glGetQueryivEXT(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAP32[params>>>2>>>0]=GLctx.disjointTimerQueryExt["getQueryEXT"](target,pname)}Module["_glGetQueryivEXT"]=_glGetQueryivEXT;_glGetQueryivEXT.sig="viip";var _emscripten_glGetQueryivEXT=_glGetQueryivEXT;Module["_emscripten_glGetQueryivEXT"]=_emscripten_glGetQueryivEXT;function _glGetRenderbufferParameteriv(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAP32[params>>>2>>>0]=GLctx.getRenderbufferParameter(target,pname)}Module["_glGetRenderbufferParameteriv"]=_glGetRenderbufferParameteriv;_glGetRenderbufferParameteriv.sig="viip";var _emscripten_glGetRenderbufferParameteriv=_glGetRenderbufferParameteriv;Module["_emscripten_glGetRenderbufferParameteriv"]=_emscripten_glGetRenderbufferParameteriv;_emscripten_glGetRenderbufferParameteriv.sig="viip";function _glGetShaderInfoLog(shader,maxLength,length,infoLog){length>>>=0;infoLog>>>=0;var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}Module["_glGetShaderInfoLog"]=_glGetShaderInfoLog;_glGetShaderInfoLog.sig="viipp";var _emscripten_glGetShaderInfoLog=_glGetShaderInfoLog;Module["_emscripten_glGetShaderInfoLog"]=_emscripten_glGetShaderInfoLog;_emscripten_glGetShaderInfoLog.sig="viipp";function _glGetShaderPrecisionFormat(shaderType,precisionType,range,precision){range>>>=0;precision>>>=0;var result=GLctx.getShaderPrecisionFormat(shaderType,precisionType);HEAP32[range>>>2>>>0]=result.rangeMin;HEAP32[range+4>>>2>>>0]=result.rangeMax;HEAP32[precision>>>2>>>0]=result.precision}Module["_glGetShaderPrecisionFormat"]=_glGetShaderPrecisionFormat;_glGetShaderPrecisionFormat.sig="viipp";var _emscripten_glGetShaderPrecisionFormat=_glGetShaderPrecisionFormat;Module["_emscripten_glGetShaderPrecisionFormat"]=_emscripten_glGetShaderPrecisionFormat;_emscripten_glGetShaderPrecisionFormat.sig="viipp";function _glGetShaderSource(shader,bufSize,length,source){length>>>=0;source>>>=0;var result=GLctx.getShaderSource(GL.shaders[shader]);if(!result)return;var numBytesWrittenExclNull=bufSize>0&&source?stringToUTF8(result,source,bufSize):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}Module["_glGetShaderSource"]=_glGetShaderSource;_glGetShaderSource.sig="viipp";var _emscripten_glGetShaderSource=_glGetShaderSource;Module["_emscripten_glGetShaderSource"]=_emscripten_glGetShaderSource;_emscripten_glGetShaderSource.sig="viipp";function _glGetShaderiv(shader,pname,p){p>>>=0;if(!p){GL.recordError(1281);return}if(pname==35716){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var logLength=log?log.length+1:0;HEAP32[p>>>2>>>0]=logLength}else if(pname==35720){var source=GLctx.getShaderSource(GL.shaders[shader]);var sourceLength=source?source.length+1:0;HEAP32[p>>>2>>>0]=sourceLength}else{HEAP32[p>>>2>>>0]=GLctx.getShaderParameter(GL.shaders[shader],pname)}}Module["_glGetShaderiv"]=_glGetShaderiv;_glGetShaderiv.sig="viip";var _emscripten_glGetShaderiv=_glGetShaderiv;Module["_emscripten_glGetShaderiv"]=_emscripten_glGetShaderiv;_emscripten_glGetShaderiv.sig="viip";var stringToNewUTF8=str=>{var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8(str,ret,size);return ret};Module["stringToNewUTF8"]=stringToNewUTF8;var webglGetExtensions=function $webglGetExtensions(){var exts=getEmscriptenSupportedExtensions(GLctx);exts=exts.concat(exts.map(e=>"GL_"+e));return exts};Module["webglGetExtensions"]=webglGetExtensions;function _glGetString(name_){var ret=GL.stringCache[name_];if(!ret){switch(name_){case 7939:ret=stringToNewUTF8(webglGetExtensions().join(" "));break;case 7936:case 7937:case 37445:case 37446:var s=GLctx.getParameter(name_);if(!s){GL.recordError(1280)}ret=s?stringToNewUTF8(s):0;break;case 7938:var glVersion=GLctx.getParameter(7938);{glVersion=`OpenGL ES 2.0 (${glVersion})`}ret=stringToNewUTF8(glVersion);break;case 35724:var glslVersion=GLctx.getParameter(35724);var ver_re=/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/;var ver_num=glslVersion.match(ver_re);if(ver_num!==null){if(ver_num[1].length==3)ver_num[1]=ver_num[1]+"0";glslVersion=`OpenGL ES GLSL ES ${ver_num[1]} (${glslVersion})`}ret=stringToNewUTF8(glslVersion);break;default:GL.recordError(1280)}GL.stringCache[name_]=ret}return ret}Module["_glGetString"]=_glGetString;_glGetString.sig="pi";var _emscripten_glGetString=_glGetString;Module["_emscripten_glGetString"]=_emscripten_glGetString;_emscripten_glGetString.sig="pi";function _glGetTexParameterfv(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAPF32[params>>>2>>>0]=GLctx.getTexParameter(target,pname)}Module["_glGetTexParameterfv"]=_glGetTexParameterfv;_glGetTexParameterfv.sig="viip";var _emscripten_glGetTexParameterfv=_glGetTexParameterfv;Module["_emscripten_glGetTexParameterfv"]=_emscripten_glGetTexParameterfv;_emscripten_glGetTexParameterfv.sig="viip";function _glGetTexParameteriv(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAP32[params>>>2>>>0]=GLctx.getTexParameter(target,pname)}Module["_glGetTexParameteriv"]=_glGetTexParameteriv;_glGetTexParameteriv.sig="viip";var _emscripten_glGetTexParameteriv=_glGetTexParameteriv;Module["_emscripten_glGetTexParameteriv"]=_emscripten_glGetTexParameteriv;_emscripten_glGetTexParameteriv.sig="viip";var webglGetLeftBracePos=name=>name.slice(-1)=="]"&&name.lastIndexOf("[");Module["webglGetLeftBracePos"]=webglGetLeftBracePos;var webglPrepareUniformLocationsBeforeFirstUse=program=>{var uniformLocsById=program.uniformLocsById,uniformSizeAndIdsByName=program.uniformSizeAndIdsByName,i,j;if(!uniformLocsById){program.uniformLocsById=uniformLocsById={};program.uniformArrayNamesById={};for(i=0;i0?nm.slice(0,lb):nm;var id=program.uniformIdCounter;program.uniformIdCounter+=sz;uniformSizeAndIdsByName[arrayName]=[sz,id];for(j=0;j>>=0;name=UTF8ToString(name);if(program=GL.programs[program]){webglPrepareUniformLocationsBeforeFirstUse(program);var uniformLocsById=program.uniformLocsById;var arrayIndex=0;var uniformBaseName=name;var leftBrace=webglGetLeftBracePos(name);if(leftBrace>0){arrayIndex=jstoi_q(name.slice(leftBrace+1))>>>0;uniformBaseName=name.slice(0,leftBrace)}var sizeAndId=program.uniformSizeAndIdsByName[uniformBaseName];if(sizeAndId&&arrayIndex{var p=GLctx.currentProgram;if(p){var webglLoc=p.uniformLocsById[location];if(typeof webglLoc=="number"){p.uniformLocsById[location]=webglLoc=GLctx.getUniformLocation(p,p.uniformArrayNamesById[location]+(webglLoc>0?`[${webglLoc}]`:""))}return webglLoc}else{GL.recordError(1282)}};Module["webglGetUniformLocation"]=webglGetUniformLocation;var emscriptenWebGLGetUniform=(program,location,params,type)=>{if(!params){GL.recordError(1281);return}program=GL.programs[program];webglPrepareUniformLocationsBeforeFirstUse(program);var data=GLctx.getUniform(program,webglGetUniformLocation(location));if(typeof data=="number"||typeof data=="boolean"){switch(type){case 0:HEAP32[params>>>2>>>0]=data;break;case 2:HEAPF32[params>>>2>>>0]=data;break}}else{for(var i=0;i>>2>>>0]=data[i];break;case 2:HEAPF32[params+i*4>>>2>>>0]=data[i];break}}}};Module["emscriptenWebGLGetUniform"]=emscriptenWebGLGetUniform;function _glGetUniformfv(program,location,params){params>>>=0;emscriptenWebGLGetUniform(program,location,params,2)}Module["_glGetUniformfv"]=_glGetUniformfv;_glGetUniformfv.sig="viip";var _emscripten_glGetUniformfv=_glGetUniformfv;Module["_emscripten_glGetUniformfv"]=_emscripten_glGetUniformfv;_emscripten_glGetUniformfv.sig="viip";function _glGetUniformiv(program,location,params){params>>>=0;emscriptenWebGLGetUniform(program,location,params,0)}Module["_glGetUniformiv"]=_glGetUniformiv;_glGetUniformiv.sig="viip";var _emscripten_glGetUniformiv=_glGetUniformiv;Module["_emscripten_glGetUniformiv"]=_emscripten_glGetUniformiv;_emscripten_glGetUniformiv.sig="viip";function _glGetVertexAttribPointerv(index,pname,pointer){pointer>>>=0;if(!pointer){GL.recordError(1281);return}HEAP32[pointer>>>2>>>0]=GLctx.getVertexAttribOffset(index,pname)}Module["_glGetVertexAttribPointerv"]=_glGetVertexAttribPointerv;_glGetVertexAttribPointerv.sig="viip";var _emscripten_glGetVertexAttribPointerv=_glGetVertexAttribPointerv;Module["_emscripten_glGetVertexAttribPointerv"]=_emscripten_glGetVertexAttribPointerv;_emscripten_glGetVertexAttribPointerv.sig="viip";var emscriptenWebGLGetVertexAttrib=(index,pname,params,type)=>{if(!params){GL.recordError(1281);return}var data=GLctx.getVertexAttrib(index,pname);if(pname==34975){HEAP32[params>>>2>>>0]=data&&data["name"]}else if(typeof data=="number"||typeof data=="boolean"){switch(type){case 0:HEAP32[params>>>2>>>0]=data;break;case 2:HEAPF32[params>>>2>>>0]=data;break;case 5:HEAP32[params>>>2>>>0]=Math.fround(data);break}}else{for(var i=0;i>>2>>>0]=data[i];break;case 2:HEAPF32[params+i*4>>>2>>>0]=data[i];break;case 5:HEAP32[params+i*4>>>2>>>0]=Math.fround(data[i]);break}}}};Module["emscriptenWebGLGetVertexAttrib"]=emscriptenWebGLGetVertexAttrib;function _glGetVertexAttribfv(index,pname,params){params>>>=0;emscriptenWebGLGetVertexAttrib(index,pname,params,2)}Module["_glGetVertexAttribfv"]=_glGetVertexAttribfv;_glGetVertexAttribfv.sig="viip";var _emscripten_glGetVertexAttribfv=_glGetVertexAttribfv;Module["_emscripten_glGetVertexAttribfv"]=_emscripten_glGetVertexAttribfv;_emscripten_glGetVertexAttribfv.sig="viip";function _glGetVertexAttribiv(index,pname,params){params>>>=0;emscriptenWebGLGetVertexAttrib(index,pname,params,5)}Module["_glGetVertexAttribiv"]=_glGetVertexAttribiv;_glGetVertexAttribiv.sig="viip";var _emscripten_glGetVertexAttribiv=_glGetVertexAttribiv;Module["_emscripten_glGetVertexAttribiv"]=_emscripten_glGetVertexAttribiv;_emscripten_glGetVertexAttribiv.sig="viip";var _glHint=(x0,x1)=>GLctx.hint(x0,x1);Module["_glHint"]=_glHint;_glHint.sig="vii";var _emscripten_glHint=_glHint;Module["_emscripten_glHint"]=_emscripten_glHint;_emscripten_glHint.sig="vii";var _glIsBuffer=buffer=>{var b=GL.buffers[buffer];if(!b)return 0;return GLctx.isBuffer(b)};Module["_glIsBuffer"]=_glIsBuffer;_glIsBuffer.sig="ii";var _emscripten_glIsBuffer=_glIsBuffer;Module["_emscripten_glIsBuffer"]=_emscripten_glIsBuffer;_emscripten_glIsBuffer.sig="ii";var _glIsEnabled=x0=>GLctx.isEnabled(x0);Module["_glIsEnabled"]=_glIsEnabled;_glIsEnabled.sig="ii";var _emscripten_glIsEnabled=_glIsEnabled;Module["_emscripten_glIsEnabled"]=_emscripten_glIsEnabled;_emscripten_glIsEnabled.sig="ii";var _glIsFramebuffer=framebuffer=>{var fb=GL.framebuffers[framebuffer];if(!fb)return 0;return GLctx.isFramebuffer(fb)};Module["_glIsFramebuffer"]=_glIsFramebuffer;_glIsFramebuffer.sig="ii";var _emscripten_glIsFramebuffer=_glIsFramebuffer;Module["_emscripten_glIsFramebuffer"]=_emscripten_glIsFramebuffer;_emscripten_glIsFramebuffer.sig="ii";var _glIsProgram=program=>{program=GL.programs[program];if(!program)return 0;return GLctx.isProgram(program)};Module["_glIsProgram"]=_glIsProgram;_glIsProgram.sig="ii";var _emscripten_glIsProgram=_glIsProgram;Module["_emscripten_glIsProgram"]=_emscripten_glIsProgram;_emscripten_glIsProgram.sig="ii";var _glIsQueryEXT=id=>{var query=GL.queries[id];if(!query)return 0;return GLctx.disjointTimerQueryExt["isQueryEXT"](query)};Module["_glIsQueryEXT"]=_glIsQueryEXT;_glIsQueryEXT.sig="ii";var _emscripten_glIsQueryEXT=_glIsQueryEXT;Module["_emscripten_glIsQueryEXT"]=_emscripten_glIsQueryEXT;var _glIsRenderbuffer=renderbuffer=>{var rb=GL.renderbuffers[renderbuffer];if(!rb)return 0;return GLctx.isRenderbuffer(rb)};Module["_glIsRenderbuffer"]=_glIsRenderbuffer;_glIsRenderbuffer.sig="ii";var _emscripten_glIsRenderbuffer=_glIsRenderbuffer;Module["_emscripten_glIsRenderbuffer"]=_emscripten_glIsRenderbuffer;_emscripten_glIsRenderbuffer.sig="ii";var _glIsShader=shader=>{var s=GL.shaders[shader];if(!s)return 0;return GLctx.isShader(s)};Module["_glIsShader"]=_glIsShader;_glIsShader.sig="ii";var _emscripten_glIsShader=_glIsShader;Module["_emscripten_glIsShader"]=_emscripten_glIsShader;_emscripten_glIsShader.sig="ii";var _glIsTexture=id=>{var texture=GL.textures[id];if(!texture)return 0;return GLctx.isTexture(texture)};Module["_glIsTexture"]=_glIsTexture;_glIsTexture.sig="ii";var _emscripten_glIsTexture=_glIsTexture;Module["_emscripten_glIsTexture"]=_emscripten_glIsTexture;_emscripten_glIsTexture.sig="ii";var _glIsVertexArray=array=>{var vao=GL.vaos[array];if(!vao)return 0;return GLctx.isVertexArray(vao)};Module["_glIsVertexArray"]=_glIsVertexArray;_glIsVertexArray.sig="ii";var _glIsVertexArrayOES=_glIsVertexArray;Module["_glIsVertexArrayOES"]=_glIsVertexArrayOES;_glIsVertexArrayOES.sig="ii";var _emscripten_glIsVertexArrayOES=_glIsVertexArrayOES;Module["_emscripten_glIsVertexArrayOES"]=_emscripten_glIsVertexArrayOES;_emscripten_glIsVertexArrayOES.sig="ii";var _glLineWidth=x0=>GLctx.lineWidth(x0);Module["_glLineWidth"]=_glLineWidth;_glLineWidth.sig="vf";var _emscripten_glLineWidth=_glLineWidth;Module["_emscripten_glLineWidth"]=_emscripten_glLineWidth;_emscripten_glLineWidth.sig="vf";var _glLinkProgram=program=>{program=GL.programs[program];GLctx.linkProgram(program);program.uniformLocsById=0;program.uniformSizeAndIdsByName={}};Module["_glLinkProgram"]=_glLinkProgram;_glLinkProgram.sig="vi";var _emscripten_glLinkProgram=_glLinkProgram;Module["_emscripten_glLinkProgram"]=_emscripten_glLinkProgram;_emscripten_glLinkProgram.sig="vi";var _glPixelStorei=(pname,param)=>{if(pname==3317){GL.unpackAlignment=param}GLctx.pixelStorei(pname,param)};Module["_glPixelStorei"]=_glPixelStorei;_glPixelStorei.sig="vii";var _emscripten_glPixelStorei=_glPixelStorei;Module["_emscripten_glPixelStorei"]=_emscripten_glPixelStorei;_emscripten_glPixelStorei.sig="vii";var _glPolygonOffset=(x0,x1)=>GLctx.polygonOffset(x0,x1);Module["_glPolygonOffset"]=_glPolygonOffset;_glPolygonOffset.sig="vff";var _emscripten_glPolygonOffset=_glPolygonOffset;Module["_emscripten_glPolygonOffset"]=_emscripten_glPolygonOffset;_emscripten_glPolygonOffset.sig="vff";var _glQueryCounterEXT=(id,target)=>{GLctx.disjointTimerQueryExt["queryCounterEXT"](GL.queries[id],target)};Module["_glQueryCounterEXT"]=_glQueryCounterEXT;_glQueryCounterEXT.sig="vii";var _emscripten_glQueryCounterEXT=_glQueryCounterEXT;Module["_emscripten_glQueryCounterEXT"]=_emscripten_glQueryCounterEXT;var computeUnpackAlignedImageSize=(width,height,sizePerPixel,alignment)=>{function roundedToNextMultipleOf(x,y){return x+y-1&-y}var plainRowSize=width*sizePerPixel;var alignedRowSize=roundedToNextMultipleOf(plainRowSize,alignment);return height*alignedRowSize};Module["computeUnpackAlignedImageSize"]=computeUnpackAlignedImageSize;var colorChannelsInGlTextureFormat=format=>{var colorChannels={5:3,6:4,8:2,29502:3,29504:4};return colorChannels[format-6402]||1};Module["colorChannelsInGlTextureFormat"]=colorChannelsInGlTextureFormat;var heapObjectForWebGLType=type=>{type-=5120;if(type==1)return HEAPU8;if(type==4)return HEAP32;if(type==6)return HEAPF32;if(type==5||type==28922)return HEAPU32;return HEAPU16};Module["heapObjectForWebGLType"]=heapObjectForWebGLType;var toTypedArrayIndex=(pointer,heap)=>pointer>>>31-Math.clz32(heap.BYTES_PER_ELEMENT);Module["toTypedArrayIndex"]=toTypedArrayIndex;var emscriptenWebGLGetTexPixelData=(type,format,width,height,pixels,internalFormat)=>{var heap=heapObjectForWebGLType(type);var sizePerPixel=colorChannelsInGlTextureFormat(format)*heap.BYTES_PER_ELEMENT;var bytes=computeUnpackAlignedImageSize(width,height,sizePerPixel,GL.unpackAlignment);return heap.subarray(toTypedArrayIndex(pixels,heap)>>>0,toTypedArrayIndex(pixels+bytes,heap)>>>0)};Module["emscriptenWebGLGetTexPixelData"]=emscriptenWebGLGetTexPixelData;function _glReadPixels(x,y,width,height,format,type,pixels){pixels>>>=0;var pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,format);if(!pixelData){GL.recordError(1280);return}GLctx.readPixels(x,y,width,height,format,type,pixelData)}Module["_glReadPixels"]=_glReadPixels;_glReadPixels.sig="viiiiiip";var _emscripten_glReadPixels=_glReadPixels;Module["_emscripten_glReadPixels"]=_emscripten_glReadPixels;_emscripten_glReadPixels.sig="viiiiiip";var _glReleaseShaderCompiler=()=>{};Module["_glReleaseShaderCompiler"]=_glReleaseShaderCompiler;_glReleaseShaderCompiler.sig="v";var _emscripten_glReleaseShaderCompiler=_glReleaseShaderCompiler;Module["_emscripten_glReleaseShaderCompiler"]=_emscripten_glReleaseShaderCompiler;_emscripten_glReleaseShaderCompiler.sig="v";var _glRenderbufferStorage=(x0,x1,x2,x3)=>GLctx.renderbufferStorage(x0,x1,x2,x3);Module["_glRenderbufferStorage"]=_glRenderbufferStorage;_glRenderbufferStorage.sig="viiii";var _emscripten_glRenderbufferStorage=_glRenderbufferStorage;Module["_emscripten_glRenderbufferStorage"]=_emscripten_glRenderbufferStorage;_emscripten_glRenderbufferStorage.sig="viiii";var _glSampleCoverage=(value,invert)=>{GLctx.sampleCoverage(value,!!invert)};Module["_glSampleCoverage"]=_glSampleCoverage;_glSampleCoverage.sig="vfi";var _emscripten_glSampleCoverage=_glSampleCoverage;Module["_emscripten_glSampleCoverage"]=_emscripten_glSampleCoverage;_emscripten_glSampleCoverage.sig="vfi";var _glScissor=(x0,x1,x2,x3)=>GLctx.scissor(x0,x1,x2,x3);Module["_glScissor"]=_glScissor;_glScissor.sig="viiii";var _emscripten_glScissor=_glScissor;Module["_emscripten_glScissor"]=_emscripten_glScissor;_emscripten_glScissor.sig="viiii";function _glShaderBinary(count,shaders,binaryformat,binary,length){shaders>>>=0;binary>>>=0;GL.recordError(1280)}Module["_glShaderBinary"]=_glShaderBinary;_glShaderBinary.sig="vipipi";var _emscripten_glShaderBinary=_glShaderBinary;Module["_emscripten_glShaderBinary"]=_emscripten_glShaderBinary;_emscripten_glShaderBinary.sig="vipipi";function _glShaderSource(shader,count,string,length){string>>>=0;length>>>=0;var source=GL.getSource(shader,count,string,length);GLctx.shaderSource(GL.shaders[shader],source)}Module["_glShaderSource"]=_glShaderSource;_glShaderSource.sig="viipp";var _emscripten_glShaderSource=_glShaderSource;Module["_emscripten_glShaderSource"]=_emscripten_glShaderSource;_emscripten_glShaderSource.sig="viipp";var _glStencilFunc=(x0,x1,x2)=>GLctx.stencilFunc(x0,x1,x2);Module["_glStencilFunc"]=_glStencilFunc;_glStencilFunc.sig="viii";var _emscripten_glStencilFunc=_glStencilFunc;Module["_emscripten_glStencilFunc"]=_emscripten_glStencilFunc;_emscripten_glStencilFunc.sig="viii";var _glStencilFuncSeparate=(x0,x1,x2,x3)=>GLctx.stencilFuncSeparate(x0,x1,x2,x3);Module["_glStencilFuncSeparate"]=_glStencilFuncSeparate;_glStencilFuncSeparate.sig="viiii";var _emscripten_glStencilFuncSeparate=_glStencilFuncSeparate;Module["_emscripten_glStencilFuncSeparate"]=_emscripten_glStencilFuncSeparate;_emscripten_glStencilFuncSeparate.sig="viiii";var _glStencilMask=x0=>GLctx.stencilMask(x0);Module["_glStencilMask"]=_glStencilMask;_glStencilMask.sig="vi";var _emscripten_glStencilMask=_glStencilMask;Module["_emscripten_glStencilMask"]=_emscripten_glStencilMask;_emscripten_glStencilMask.sig="vi";var _glStencilMaskSeparate=(x0,x1)=>GLctx.stencilMaskSeparate(x0,x1);Module["_glStencilMaskSeparate"]=_glStencilMaskSeparate;_glStencilMaskSeparate.sig="vii";var _emscripten_glStencilMaskSeparate=_glStencilMaskSeparate;Module["_emscripten_glStencilMaskSeparate"]=_emscripten_glStencilMaskSeparate;_emscripten_glStencilMaskSeparate.sig="vii";var _glStencilOp=(x0,x1,x2)=>GLctx.stencilOp(x0,x1,x2);Module["_glStencilOp"]=_glStencilOp;_glStencilOp.sig="viii";var _emscripten_glStencilOp=_glStencilOp;Module["_emscripten_glStencilOp"]=_emscripten_glStencilOp;_emscripten_glStencilOp.sig="viii";var _glStencilOpSeparate=(x0,x1,x2,x3)=>GLctx.stencilOpSeparate(x0,x1,x2,x3);Module["_glStencilOpSeparate"]=_glStencilOpSeparate;_glStencilOpSeparate.sig="viiii";var _emscripten_glStencilOpSeparate=_glStencilOpSeparate;Module["_emscripten_glStencilOpSeparate"]=_emscripten_glStencilOpSeparate;_emscripten_glStencilOpSeparate.sig="viiii";function _glTexImage2D(target,level,internalFormat,width,height,border,format,type,pixels){pixels>>>=0;var pixelData=pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat):null;GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixelData)}Module["_glTexImage2D"]=_glTexImage2D;_glTexImage2D.sig="viiiiiiiip";var _emscripten_glTexImage2D=_glTexImage2D;Module["_emscripten_glTexImage2D"]=_emscripten_glTexImage2D;_emscripten_glTexImage2D.sig="viiiiiiiip";var _glTexParameterf=(x0,x1,x2)=>GLctx.texParameterf(x0,x1,x2);Module["_glTexParameterf"]=_glTexParameterf;_glTexParameterf.sig="viif";var _emscripten_glTexParameterf=_glTexParameterf;Module["_emscripten_glTexParameterf"]=_emscripten_glTexParameterf;_emscripten_glTexParameterf.sig="viif";function _glTexParameterfv(target,pname,params){params>>>=0;var param=HEAPF32[params>>>2>>>0];GLctx.texParameterf(target,pname,param)}Module["_glTexParameterfv"]=_glTexParameterfv;_glTexParameterfv.sig="viip";var _emscripten_glTexParameterfv=_glTexParameterfv;Module["_emscripten_glTexParameterfv"]=_emscripten_glTexParameterfv;_emscripten_glTexParameterfv.sig="viip";var _glTexParameteri=(x0,x1,x2)=>GLctx.texParameteri(x0,x1,x2);Module["_glTexParameteri"]=_glTexParameteri;_glTexParameteri.sig="viii";var _emscripten_glTexParameteri=_glTexParameteri;Module["_emscripten_glTexParameteri"]=_emscripten_glTexParameteri;_emscripten_glTexParameteri.sig="viii";function _glTexParameteriv(target,pname,params){params>>>=0;var param=HEAP32[params>>>2>>>0];GLctx.texParameteri(target,pname,param)}Module["_glTexParameteriv"]=_glTexParameteriv;_glTexParameteriv.sig="viip";var _emscripten_glTexParameteriv=_glTexParameteriv;Module["_emscripten_glTexParameteriv"]=_emscripten_glTexParameteriv;_emscripten_glTexParameteriv.sig="viip";function _glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels){pixels>>>=0;var pixelData=pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,0):null;GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixelData)}Module["_glTexSubImage2D"]=_glTexSubImage2D;_glTexSubImage2D.sig="viiiiiiiip";var _emscripten_glTexSubImage2D=_glTexSubImage2D;Module["_emscripten_glTexSubImage2D"]=_emscripten_glTexSubImage2D;_emscripten_glTexSubImage2D.sig="viiiiiiiip";var _glUniform1f=(location,v0)=>{GLctx.uniform1f(webglGetUniformLocation(location),v0)};Module["_glUniform1f"]=_glUniform1f;_glUniform1f.sig="vif";var _emscripten_glUniform1f=_glUniform1f;Module["_emscripten_glUniform1f"]=_emscripten_glUniform1f;_emscripten_glUniform1f.sig="vif";var miniTempWebGLFloatBuffers=[];Module["miniTempWebGLFloatBuffers"]=miniTempWebGLFloatBuffers;function _glUniform1fv(location,count,value){value>>>=0;if(count<=288){var view=miniTempWebGLFloatBuffers[count];for(var i=0;i>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*4>>>2>>>0)}GLctx.uniform1fv(webglGetUniformLocation(location),view)}Module["_glUniform1fv"]=_glUniform1fv;_glUniform1fv.sig="viip";var _emscripten_glUniform1fv=_glUniform1fv;Module["_emscripten_glUniform1fv"]=_emscripten_glUniform1fv;_emscripten_glUniform1fv.sig="viip";var _glUniform1i=(location,v0)=>{GLctx.uniform1i(webglGetUniformLocation(location),v0)};Module["_glUniform1i"]=_glUniform1i;_glUniform1i.sig="vii";var _emscripten_glUniform1i=_glUniform1i;Module["_emscripten_glUniform1i"]=_emscripten_glUniform1i;_emscripten_glUniform1i.sig="vii";var miniTempWebGLIntBuffers=[];Module["miniTempWebGLIntBuffers"]=miniTempWebGLIntBuffers;function _glUniform1iv(location,count,value){value>>>=0;if(count<=288){var view=miniTempWebGLIntBuffers[count];for(var i=0;i>>2>>>0]}}else{var view=HEAP32.subarray(value>>>2>>>0,value+count*4>>>2>>>0)}GLctx.uniform1iv(webglGetUniformLocation(location),view)}Module["_glUniform1iv"]=_glUniform1iv;_glUniform1iv.sig="viip";var _emscripten_glUniform1iv=_glUniform1iv;Module["_emscripten_glUniform1iv"]=_emscripten_glUniform1iv;_emscripten_glUniform1iv.sig="viip";var _glUniform2f=(location,v0,v1)=>{GLctx.uniform2f(webglGetUniformLocation(location),v0,v1)};Module["_glUniform2f"]=_glUniform2f;_glUniform2f.sig="viff";var _emscripten_glUniform2f=_glUniform2f;Module["_emscripten_glUniform2f"]=_emscripten_glUniform2f;_emscripten_glUniform2f.sig="viff";function _glUniform2fv(location,count,value){value>>>=0;if(count<=144){var view=miniTempWebGLFloatBuffers[2*count];for(var i=0;i<2*count;i+=2){view[i]=HEAPF32[value+4*i>>>2>>>0];view[i+1]=HEAPF32[value+(4*i+4)>>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*8>>>2>>>0)}GLctx.uniform2fv(webglGetUniformLocation(location),view)}Module["_glUniform2fv"]=_glUniform2fv;_glUniform2fv.sig="viip";var _emscripten_glUniform2fv=_glUniform2fv;Module["_emscripten_glUniform2fv"]=_emscripten_glUniform2fv;_emscripten_glUniform2fv.sig="viip";var _glUniform2i=(location,v0,v1)=>{GLctx.uniform2i(webglGetUniformLocation(location),v0,v1)};Module["_glUniform2i"]=_glUniform2i;_glUniform2i.sig="viii";var _emscripten_glUniform2i=_glUniform2i;Module["_emscripten_glUniform2i"]=_emscripten_glUniform2i;_emscripten_glUniform2i.sig="viii";function _glUniform2iv(location,count,value){value>>>=0;if(count<=144){var view=miniTempWebGLIntBuffers[2*count];for(var i=0;i<2*count;i+=2){view[i]=HEAP32[value+4*i>>>2>>>0];view[i+1]=HEAP32[value+(4*i+4)>>>2>>>0]}}else{var view=HEAP32.subarray(value>>>2>>>0,value+count*8>>>2>>>0)}GLctx.uniform2iv(webglGetUniformLocation(location),view)}Module["_glUniform2iv"]=_glUniform2iv;_glUniform2iv.sig="viip";var _emscripten_glUniform2iv=_glUniform2iv;Module["_emscripten_glUniform2iv"]=_emscripten_glUniform2iv;_emscripten_glUniform2iv.sig="viip";var _glUniform3f=(location,v0,v1,v2)=>{GLctx.uniform3f(webglGetUniformLocation(location),v0,v1,v2)};Module["_glUniform3f"]=_glUniform3f;_glUniform3f.sig="vifff";var _emscripten_glUniform3f=_glUniform3f;Module["_emscripten_glUniform3f"]=_emscripten_glUniform3f;_emscripten_glUniform3f.sig="vifff";function _glUniform3fv(location,count,value){value>>>=0;if(count<=96){var view=miniTempWebGLFloatBuffers[3*count];for(var i=0;i<3*count;i+=3){view[i]=HEAPF32[value+4*i>>>2>>>0];view[i+1]=HEAPF32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAPF32[value+(4*i+8)>>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*12>>>2>>>0)}GLctx.uniform3fv(webglGetUniformLocation(location),view)}Module["_glUniform3fv"]=_glUniform3fv;_glUniform3fv.sig="viip";var _emscripten_glUniform3fv=_glUniform3fv;Module["_emscripten_glUniform3fv"]=_emscripten_glUniform3fv;_emscripten_glUniform3fv.sig="viip";var _glUniform3i=(location,v0,v1,v2)=>{GLctx.uniform3i(webglGetUniformLocation(location),v0,v1,v2)};Module["_glUniform3i"]=_glUniform3i;_glUniform3i.sig="viiii";var _emscripten_glUniform3i=_glUniform3i;Module["_emscripten_glUniform3i"]=_emscripten_glUniform3i;_emscripten_glUniform3i.sig="viiii";function _glUniform3iv(location,count,value){value>>>=0;if(count<=96){var view=miniTempWebGLIntBuffers[3*count];for(var i=0;i<3*count;i+=3){view[i]=HEAP32[value+4*i>>>2>>>0];view[i+1]=HEAP32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAP32[value+(4*i+8)>>>2>>>0]}}else{var view=HEAP32.subarray(value>>>2>>>0,value+count*12>>>2>>>0)}GLctx.uniform3iv(webglGetUniformLocation(location),view)}Module["_glUniform3iv"]=_glUniform3iv;_glUniform3iv.sig="viip";var _emscripten_glUniform3iv=_glUniform3iv;Module["_emscripten_glUniform3iv"]=_emscripten_glUniform3iv;_emscripten_glUniform3iv.sig="viip";var _glUniform4f=(location,v0,v1,v2,v3)=>{GLctx.uniform4f(webglGetUniformLocation(location),v0,v1,v2,v3)};Module["_glUniform4f"]=_glUniform4f;_glUniform4f.sig="viffff";var _emscripten_glUniform4f=_glUniform4f;Module["_emscripten_glUniform4f"]=_emscripten_glUniform4f;_emscripten_glUniform4f.sig="viffff";function _glUniform4fv(location,count,value){value>>>=0;if(count<=72){var view=miniTempWebGLFloatBuffers[4*count];var heap=HEAPF32;value=value>>>2;for(var i=0;i<4*count;i+=4){var dst=value+i;view[i]=heap[dst>>>0];view[i+1]=heap[dst+1>>>0];view[i+2]=heap[dst+2>>>0];view[i+3]=heap[dst+3>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*16>>>2>>>0)}GLctx.uniform4fv(webglGetUniformLocation(location),view)}Module["_glUniform4fv"]=_glUniform4fv;_glUniform4fv.sig="viip";var _emscripten_glUniform4fv=_glUniform4fv;Module["_emscripten_glUniform4fv"]=_emscripten_glUniform4fv;_emscripten_glUniform4fv.sig="viip";var _glUniform4i=(location,v0,v1,v2,v3)=>{GLctx.uniform4i(webglGetUniformLocation(location),v0,v1,v2,v3)};Module["_glUniform4i"]=_glUniform4i;_glUniform4i.sig="viiiii";var _emscripten_glUniform4i=_glUniform4i;Module["_emscripten_glUniform4i"]=_emscripten_glUniform4i;_emscripten_glUniform4i.sig="viiiii";function _glUniform4iv(location,count,value){value>>>=0;if(count<=72){var view=miniTempWebGLIntBuffers[4*count];for(var i=0;i<4*count;i+=4){view[i]=HEAP32[value+4*i>>>2>>>0];view[i+1]=HEAP32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAP32[value+(4*i+8)>>>2>>>0];view[i+3]=HEAP32[value+(4*i+12)>>>2>>>0]}}else{var view=HEAP32.subarray(value>>>2>>>0,value+count*16>>>2>>>0)}GLctx.uniform4iv(webglGetUniformLocation(location),view)}Module["_glUniform4iv"]=_glUniform4iv;_glUniform4iv.sig="viip";var _emscripten_glUniform4iv=_glUniform4iv;Module["_emscripten_glUniform4iv"]=_emscripten_glUniform4iv;_emscripten_glUniform4iv.sig="viip";function _glUniformMatrix2fv(location,count,transpose,value){value>>>=0;if(count<=72){var view=miniTempWebGLFloatBuffers[4*count];for(var i=0;i<4*count;i+=4){view[i]=HEAPF32[value+4*i>>>2>>>0];view[i+1]=HEAPF32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAPF32[value+(4*i+8)>>>2>>>0];view[i+3]=HEAPF32[value+(4*i+12)>>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*16>>>2>>>0)}GLctx.uniformMatrix2fv(webglGetUniformLocation(location),!!transpose,view)}Module["_glUniformMatrix2fv"]=_glUniformMatrix2fv;_glUniformMatrix2fv.sig="viiip";var _emscripten_glUniformMatrix2fv=_glUniformMatrix2fv;Module["_emscripten_glUniformMatrix2fv"]=_emscripten_glUniformMatrix2fv;_emscripten_glUniformMatrix2fv.sig="viiip";function _glUniformMatrix3fv(location,count,transpose,value){value>>>=0;if(count<=32){var view=miniTempWebGLFloatBuffers[9*count];for(var i=0;i<9*count;i+=9){view[i]=HEAPF32[value+4*i>>>2>>>0];view[i+1]=HEAPF32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAPF32[value+(4*i+8)>>>2>>>0];view[i+3]=HEAPF32[value+(4*i+12)>>>2>>>0];view[i+4]=HEAPF32[value+(4*i+16)>>>2>>>0];view[i+5]=HEAPF32[value+(4*i+20)>>>2>>>0];view[i+6]=HEAPF32[value+(4*i+24)>>>2>>>0];view[i+7]=HEAPF32[value+(4*i+28)>>>2>>>0];view[i+8]=HEAPF32[value+(4*i+32)>>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*36>>>2>>>0)}GLctx.uniformMatrix3fv(webglGetUniformLocation(location),!!transpose,view)}Module["_glUniformMatrix3fv"]=_glUniformMatrix3fv;_glUniformMatrix3fv.sig="viiip";var _emscripten_glUniformMatrix3fv=_glUniformMatrix3fv;Module["_emscripten_glUniformMatrix3fv"]=_emscripten_glUniformMatrix3fv;_emscripten_glUniformMatrix3fv.sig="viiip";function _glUniformMatrix4fv(location,count,transpose,value){value>>>=0;if(count<=18){var view=miniTempWebGLFloatBuffers[16*count];var heap=HEAPF32;value=value>>>2;for(var i=0;i<16*count;i+=16){var dst=value+i;view[i]=heap[dst>>>0];view[i+1]=heap[dst+1>>>0];view[i+2]=heap[dst+2>>>0];view[i+3]=heap[dst+3>>>0];view[i+4]=heap[dst+4>>>0];view[i+5]=heap[dst+5>>>0];view[i+6]=heap[dst+6>>>0];view[i+7]=heap[dst+7>>>0];view[i+8]=heap[dst+8>>>0];view[i+9]=heap[dst+9>>>0];view[i+10]=heap[dst+10>>>0];view[i+11]=heap[dst+11>>>0];view[i+12]=heap[dst+12>>>0];view[i+13]=heap[dst+13>>>0];view[i+14]=heap[dst+14>>>0];view[i+15]=heap[dst+15>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*64>>>2>>>0)}GLctx.uniformMatrix4fv(webglGetUniformLocation(location),!!transpose,view)}Module["_glUniformMatrix4fv"]=_glUniformMatrix4fv;_glUniformMatrix4fv.sig="viiip";var _emscripten_glUniformMatrix4fv=_glUniformMatrix4fv;Module["_emscripten_glUniformMatrix4fv"]=_emscripten_glUniformMatrix4fv;_emscripten_glUniformMatrix4fv.sig="viiip";var _glUseProgram=program=>{program=GL.programs[program];GLctx.useProgram(program);GLctx.currentProgram=program};Module["_glUseProgram"]=_glUseProgram;_glUseProgram.sig="vi";var _emscripten_glUseProgram=_glUseProgram;Module["_emscripten_glUseProgram"]=_emscripten_glUseProgram;_emscripten_glUseProgram.sig="vi";var _glValidateProgram=program=>{GLctx.validateProgram(GL.programs[program])};Module["_glValidateProgram"]=_glValidateProgram;_glValidateProgram.sig="vi";var _emscripten_glValidateProgram=_glValidateProgram;Module["_emscripten_glValidateProgram"]=_emscripten_glValidateProgram;_emscripten_glValidateProgram.sig="vi";var _glVertexAttrib1f=(x0,x1)=>GLctx.vertexAttrib1f(x0,x1);Module["_glVertexAttrib1f"]=_glVertexAttrib1f;_glVertexAttrib1f.sig="vif";var _emscripten_glVertexAttrib1f=_glVertexAttrib1f;Module["_emscripten_glVertexAttrib1f"]=_emscripten_glVertexAttrib1f;_emscripten_glVertexAttrib1f.sig="vif";function _glVertexAttrib1fv(index,v){v>>>=0;GLctx.vertexAttrib1f(index,HEAPF32[v>>>2])}Module["_glVertexAttrib1fv"]=_glVertexAttrib1fv;_glVertexAttrib1fv.sig="vip";var _emscripten_glVertexAttrib1fv=_glVertexAttrib1fv;Module["_emscripten_glVertexAttrib1fv"]=_emscripten_glVertexAttrib1fv;_emscripten_glVertexAttrib1fv.sig="vip";var _glVertexAttrib2f=(x0,x1,x2)=>GLctx.vertexAttrib2f(x0,x1,x2);Module["_glVertexAttrib2f"]=_glVertexAttrib2f;_glVertexAttrib2f.sig="viff";var _emscripten_glVertexAttrib2f=_glVertexAttrib2f;Module["_emscripten_glVertexAttrib2f"]=_emscripten_glVertexAttrib2f;_emscripten_glVertexAttrib2f.sig="viff";function _glVertexAttrib2fv(index,v){v>>>=0;GLctx.vertexAttrib2f(index,HEAPF32[v>>>2],HEAPF32[v+4>>>2])}Module["_glVertexAttrib2fv"]=_glVertexAttrib2fv;_glVertexAttrib2fv.sig="vip";var _emscripten_glVertexAttrib2fv=_glVertexAttrib2fv;Module["_emscripten_glVertexAttrib2fv"]=_emscripten_glVertexAttrib2fv;_emscripten_glVertexAttrib2fv.sig="vip";var _glVertexAttrib3f=(x0,x1,x2,x3)=>GLctx.vertexAttrib3f(x0,x1,x2,x3);Module["_glVertexAttrib3f"]=_glVertexAttrib3f;_glVertexAttrib3f.sig="vifff";var _emscripten_glVertexAttrib3f=_glVertexAttrib3f;Module["_emscripten_glVertexAttrib3f"]=_emscripten_glVertexAttrib3f;_emscripten_glVertexAttrib3f.sig="vifff";function _glVertexAttrib3fv(index,v){v>>>=0;GLctx.vertexAttrib3f(index,HEAPF32[v>>>2],HEAPF32[v+4>>>2],HEAPF32[v+8>>>2])}Module["_glVertexAttrib3fv"]=_glVertexAttrib3fv;_glVertexAttrib3fv.sig="vip";var _emscripten_glVertexAttrib3fv=_glVertexAttrib3fv;Module["_emscripten_glVertexAttrib3fv"]=_emscripten_glVertexAttrib3fv;_emscripten_glVertexAttrib3fv.sig="vip";var _glVertexAttrib4f=(x0,x1,x2,x3,x4)=>GLctx.vertexAttrib4f(x0,x1,x2,x3,x4);Module["_glVertexAttrib4f"]=_glVertexAttrib4f;_glVertexAttrib4f.sig="viffff";var _emscripten_glVertexAttrib4f=_glVertexAttrib4f;Module["_emscripten_glVertexAttrib4f"]=_emscripten_glVertexAttrib4f;_emscripten_glVertexAttrib4f.sig="viffff";function _glVertexAttrib4fv(index,v){v>>>=0;GLctx.vertexAttrib4f(index,HEAPF32[v>>>2],HEAPF32[v+4>>>2],HEAPF32[v+8>>>2],HEAPF32[v+12>>>2])}Module["_glVertexAttrib4fv"]=_glVertexAttrib4fv;_glVertexAttrib4fv.sig="vip";var _emscripten_glVertexAttrib4fv=_glVertexAttrib4fv;Module["_emscripten_glVertexAttrib4fv"]=_emscripten_glVertexAttrib4fv;_emscripten_glVertexAttrib4fv.sig="vip";var _glVertexAttribDivisor=(index,divisor)=>{GLctx.vertexAttribDivisor(index,divisor)};Module["_glVertexAttribDivisor"]=_glVertexAttribDivisor;_glVertexAttribDivisor.sig="vii";var _glVertexAttribDivisorANGLE=_glVertexAttribDivisor;Module["_glVertexAttribDivisorANGLE"]=_glVertexAttribDivisorANGLE;var _emscripten_glVertexAttribDivisorANGLE=_glVertexAttribDivisorANGLE;Module["_emscripten_glVertexAttribDivisorANGLE"]=_emscripten_glVertexAttribDivisorANGLE;function _glVertexAttribPointer(index,size,type,normalized,stride,ptr){ptr>>>=0;GLctx.vertexAttribPointer(index,size,type,!!normalized,stride,ptr)}Module["_glVertexAttribPointer"]=_glVertexAttribPointer;_glVertexAttribPointer.sig="viiiiip";var _emscripten_glVertexAttribPointer=_glVertexAttribPointer;Module["_emscripten_glVertexAttribPointer"]=_emscripten_glVertexAttribPointer;_emscripten_glVertexAttribPointer.sig="viiiiip";var _glViewport=(x0,x1,x2,x3)=>GLctx.viewport(x0,x1,x2,x3);Module["_glViewport"]=_glViewport;_glViewport.sig="viiii";var _emscripten_glViewport=_glViewport;Module["_emscripten_glViewport"]=_emscripten_glViewport;_emscripten_glViewport.sig="viiii";function _emscripten_out(str){str>>>=0;return out(UTF8ToString(str))}Module["_emscripten_out"]=_emscripten_out;_emscripten_out.sig="vp";class HandleAllocator{constructor(){this.allocated=[undefined];this.freelist=[]}get(id){return this.allocated[id]}has(id){return this.allocated[id]!==undefined}allocate(handle){var id=this.freelist.pop()||this.allocated.length;this.allocated[id]=handle;return id}free(id){this.allocated[id]=undefined;this.freelist.push(id)}}Module["HandleAllocator"]=HandleAllocator;var promiseMap=new HandleAllocator;Module["promiseMap"]=promiseMap;var makePromise=()=>{var promiseInfo={};promiseInfo.promise=new Promise((resolve,reject)=>{promiseInfo.reject=reject;promiseInfo.resolve=resolve});promiseInfo.id=promiseMap.allocate(promiseInfo);return promiseInfo};Module["makePromise"]=makePromise;function _emscripten_promise_create(){return makePromise().id}Module["_emscripten_promise_create"]=_emscripten_promise_create;_emscripten_promise_create.sig="p";function _emscripten_promise_destroy(id){id>>>=0;promiseMap.free(id)}Module["_emscripten_promise_destroy"]=_emscripten_promise_destroy;_emscripten_promise_destroy.sig="vp";var getPromise=id=>promiseMap.get(id).promise;Module["getPromise"]=getPromise;function _emscripten_promise_resolve(id,result,value){id>>>=0;value>>>=0;var info=promiseMap.get(id);switch(result){case 0:info.resolve(value);return;case 1:info.resolve(getPromise(value));return;case 2:info.resolve(getPromise(value));_emscripten_promise_destroy(value);return;case 3:info.reject(value);return}}Module["_emscripten_promise_resolve"]=_emscripten_promise_resolve;_emscripten_promise_resolve.sig="vpip";var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};Module["growMemory"]=growMemory;function _emscripten_resize_heap(requestedSize){requestedSize>>>=0;var oldSize=HEAPU8.length;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false}Module["_emscripten_resize_heap"]=_emscripten_resize_heap;_emscripten_resize_heap.sig="ip";var getExecutableName=()=>thisProgram||"./this.program";Module["getExecutableName"]=getExecutableName;var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":lang,"_":getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};Module["getEnvStrings"]=getEnvStrings;var stringToAscii=(str,buffer)=>{for(var i=0;i>>0]=str.charCodeAt(i)}HEAP8[buffer>>>0]=0};Module["stringToAscii"]=stringToAscii;var _environ_get=function(__environ,environ_buf){__environ>>>=0;environ_buf>>>=0;var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>>2>>>0]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1});return 0};Module["_environ_get"]=_environ_get;_environ_get.sig="ipp";var _environ_sizes_get=function(penviron_count,penviron_buf_size){penviron_count>>>=0;penviron_buf_size>>>=0;var strings=getEnvStrings();HEAPU32[penviron_count>>>2>>>0]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);HEAPU32[penviron_buf_size>>>2>>>0]=bufSize;return 0};Module["_environ_sizes_get"]=_environ_sizes_get;_environ_sizes_get.sig="ipp";function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_close"]=_fd_close;_fd_close.sig="ii";function _fd_fdstat_get(fd,pbuf){pbuf>>>=0;try{var rightsBase=0;var rightsInheriting=0;var flags=0;{var stream=SYSCALLS.getStreamFromFD(fd);var type=stream.tty?2:FS.isDir(stream.mode)?3:FS.isLink(stream.mode)?7:4}HEAP8[pbuf>>>0]=type;HEAP16[pbuf+2>>>1>>>0]=flags;HEAP64[pbuf+8>>>3]=BigInt(rightsBase);HEAP64[pbuf+16>>>3]=BigInt(rightsInheriting);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_fdstat_get"]=_fd_fdstat_get;_fd_fdstat_get.sig="iip";var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>>2>>>0];var len=HEAPU32[iov+4>>>2>>>0];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>>=0;iovcnt>>>=0;offset=bigintToI53Checked(offset);pnum>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var num=doReadv(stream,iov,iovcnt,offset);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_pread"]=_fd_pread;_fd_pread.sig="iippjp";var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>>2>>>0];var len=HEAPU32[iov+4>>>2>>>0];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(typeof offset!="undefined"){offset+=curr}}return ret};Module["doWritev"]=doWritev;function _fd_pwrite(fd,iov,iovcnt,offset,pnum){iov>>>=0;iovcnt>>>=0;offset=bigintToI53Checked(offset);pnum>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt,offset);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_pwrite"]=_fd_pwrite;_fd_pwrite.sig="iippjp";function _fd_read(fd,iov,iovcnt,pnum){iov>>>=0;iovcnt>>>=0;pnum>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doReadv(stream,iov,iovcnt);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_read"]=_fd_read;_fd_read.sig="iippp";function _fd_seek(fd,offset,whence,newOffset){offset=bigintToI53Checked(offset);newOffset>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);HEAP64[newOffset>>>3]=BigInt(stream.position);if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_seek"]=_fd_seek;_fd_seek.sig="iijip";function _fd_sync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);if(stream.stream_ops?.fsync){return stream.stream_ops.fsync(stream)}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_sync"]=_fd_sync;_fd_sync.sig="ii";function _fd_write(fd,iov,iovcnt,pnum){iov>>>=0;iovcnt>>>=0;pnum>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_write"]=_fd_write;_fd_write.sig="iippp";function _getaddrinfo(node,service,hint,out){node>>>=0;service>>>=0;hint>>>=0;out>>>=0;var addrs=[];var canon=null;var addr=0;var port=0;var flags=0;var family=0;var type=0;var proto=0;var ai,last;function allocaddrinfo(family,type,proto,canon,addr,port){var sa,salen,ai;var errno;salen=family===10?28:16;addr=family===10?inetNtop6(addr):inetNtop4(addr);sa=_malloc(salen);errno=writeSockaddr(sa,family,addr,port);assert(!errno);ai=_malloc(32);HEAP32[ai+4>>>2>>>0]=family;HEAP32[ai+8>>>2>>>0]=type;HEAP32[ai+12>>>2>>>0]=proto;HEAPU32[ai+24>>>2>>>0]=canon;HEAPU32[ai+20>>>2>>>0]=sa;if(family===10){HEAP32[ai+16>>>2>>>0]=28}else{HEAP32[ai+16>>>2>>>0]=16}HEAP32[ai+28>>>2>>>0]=0;return ai}if(hint){flags=HEAP32[hint>>>2>>>0];family=HEAP32[hint+4>>>2>>>0];type=HEAP32[hint+8>>>2>>>0];proto=HEAP32[hint+12>>>2>>>0]}if(type&&!proto){proto=type===2?17:6}if(!type&&proto){type=proto===17?2:1}if(proto===0){proto=6}if(type===0){type=1}if(!node&&!service){return-2}if(flags&~(1|2|4|1024|8|16|32)){return-1}if(hint!==0&&HEAP32[hint>>>2>>>0]&2&&!node){return-1}if(flags&32){return-2}if(type!==0&&type!==1&&type!==2){return-7}if(family!==0&&family!==2&&family!==10){return-6}if(service){service=UTF8ToString(service);port=parseInt(service,10);if(isNaN(port)){if(flags&1024){return-2}return-8}}if(!node){if(family===0){family=2}if((flags&1)===0){if(family===2){addr=_htonl(2130706433)}else{addr=[0,0,0,1]}}ai=allocaddrinfo(family,type,proto,null,addr,port);HEAPU32[out>>>2>>>0]=ai;return 0}node=UTF8ToString(node);addr=inetPton4(node);if(addr!==null){if(family===0||family===2){family=2}else if(family===10&&flags&8){addr=[0,0,_htonl(65535),addr];family=10}else{return-2}}else{addr=inetPton6(node);if(addr!==null){if(family===0||family===10){family=10}else{return-2}}}if(addr!=null){ai=allocaddrinfo(family,type,proto,node,addr,port);HEAPU32[out>>>2>>>0]=ai;return 0}if(flags&4){return-2}node=DNS.lookup_name(node);addr=inetPton4(node);if(family===0){family=2}else if(family===10){addr=[0,0,_htonl(65535),addr]}ai=allocaddrinfo(family,type,proto,null,addr,port);HEAPU32[out>>>2>>>0]=ai;return 0}Module["_getaddrinfo"]=_getaddrinfo;_getaddrinfo.sig="ipppp";function _getentropy(buffer,size){buffer>>>=0;size>>>=0;randomFill(HEAPU8.subarray(buffer>>>0,buffer+size>>>0));return 0}Module["_getentropy"]=_getentropy;_getentropy.sig="ipp";function _getnameinfo(sa,salen,node,nodelen,serv,servlen,flags){sa>>>=0;node>>>=0;serv>>>=0;var info=readSockaddr(sa,salen);if(info.errno){return-6}var port=info.port;var addr=info.addr;var overflowed=false;if(node&&nodelen){var lookup;if(flags&1||!(lookup=DNS.lookup_addr(addr))){if(flags&8){return-2}}else{addr=lookup}var numBytesWrittenExclNull=stringToUTF8(addr,node,nodelen);if(numBytesWrittenExclNull+1>=nodelen){overflowed=true}}if(serv&&servlen){port=""+port;var numBytesWrittenExclNull=stringToUTF8(port,serv,servlen);if(numBytesWrittenExclNull+1>=servlen){overflowed=true}}if(overflowed){return-12}return 0}Module["_getnameinfo"]=_getnameinfo;_getnameinfo.sig="ipipipii";var Protocols={list:[],map:{}};Module["Protocols"]=Protocols;var _setprotoent=stayopen=>{function allocprotoent(name,proto,aliases){var nameBuf=_malloc(name.length+1);stringToAscii(name,nameBuf);var j=0;var length=aliases.length;var aliasListBuf=_malloc((length+1)*4);for(var i=0;i>>2>>>0]=aliasBuf}HEAPU32[aliasListBuf+j>>>2>>>0]=0;var pe=_malloc(12);HEAPU32[pe>>>2>>>0]=nameBuf;HEAPU32[pe+4>>>2>>>0]=aliasListBuf;HEAP32[pe+8>>>2>>>0]=proto;return pe}var list=Protocols.list;var map=Protocols.map;if(list.length===0){var entry=allocprotoent("tcp",6,["TCP"]);list.push(entry);map["tcp"]=map["6"]=entry;entry=allocprotoent("udp",17,["UDP"]);list.push(entry);map["udp"]=map["17"]=entry}_setprotoent.index=0};Module["_setprotoent"]=_setprotoent;_setprotoent.sig="vi";function _getprotobyname(name){name>>>=0;name=UTF8ToString(name);_setprotoent(true);var result=Protocols.map[name];return result}Module["_getprotobyname"]=_getprotobyname;_getprotobyname.sig="pp";var arraySum=(array,index)=>{var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum};Module["arraySum"]=arraySum;var MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];Module["MONTH_DAYS_LEAP"]=MONTH_DAYS_LEAP;var MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];Module["MONTH_DAYS_REGULAR"]=MONTH_DAYS_REGULAR;var addDays=(date,days)=>{var newDate=new Date(date.getTime());while(days>0){var leap=isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate};Module["addDays"]=addDays;var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer>>>0)};Module["writeArrayToMemory"]=writeArrayToMemory;function _strftime(s,maxsize,format,tm){s>>>=0;maxsize>>>=0;format>>>=0;tm>>>=0;var tm_zone=HEAPU32[tm+40>>>2>>>0];var date={tm_sec:HEAP32[tm>>>2>>>0],tm_min:HEAP32[tm+4>>>2>>>0],tm_hour:HEAP32[tm+8>>>2>>>0],tm_mday:HEAP32[tm+12>>>2>>>0],tm_mon:HEAP32[tm+16>>>2>>>0],tm_year:HEAP32[tm+20>>>2>>>0],tm_wday:HEAP32[tm+24>>>2>>>0],tm_yday:HEAP32[tm+28>>>2>>>0],tm_isdst:HEAP32[tm+32>>>2>>>0],tm_gmtoff:HEAP32[tm+36>>>2>>>0],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%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 rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value=="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}return thisDate.getFullYear()}return thisDate.getFullYear()-1}var EXPANSION_RULES_2={"%a":date=>WEEKDAYS[date.tm_wday].substring(0,3),"%A":date=>WEEKDAYS[date.tm_wday],"%b":date=>MONTHS[date.tm_mon].substring(0,3),"%B":date=>MONTHS[date.tm_mon],"%C":date=>{var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":date=>leadingNulls(date.tm_mday,2),"%e":date=>leadingSomething(date.tm_mday,2," "),"%g":date=>getWeekBasedYear(date).toString().substring(2),"%G":getWeekBasedYear,"%H":date=>leadingNulls(date.tm_hour,2),"%I":date=>{var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":date=>leadingNulls(date.tm_mday+arraySum(isLeapYear(date.tm_year+1900)?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR,date.tm_mon-1),3),"%m":date=>leadingNulls(date.tm_mon+1,2),"%M":date=>leadingNulls(date.tm_min,2),"%n":()=>"\n","%p":date=>{if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}return"PM"},"%S":date=>leadingNulls(date.tm_sec,2),"%t":()=>"\t","%u":date=>date.tm_wday||7,"%U":date=>{var days=date.tm_yday+7-date.tm_wday;return leadingNulls(Math.floor(days/7),2)},"%V":date=>{var val=Math.floor((date.tm_yday+7-(date.tm_wday+6)%7)/7);if((date.tm_wday+371-date.tm_yday-2)%7<=2){val++}if(!val){val=52;var dec31=(date.tm_wday+7-date.tm_yday-1)%7;if(dec31==4||dec31==5&&isLeapYear(date.tm_year%400-1)){val++}}else if(val==53){var jan1=(date.tm_wday+371-date.tm_yday)%7;if(jan1!=4&&(jan1!=3||!isLeapYear(date.tm_year)))val=1}return leadingNulls(val,2)},"%w":date=>date.tm_wday,"%W":date=>{var days=date.tm_yday+7-(date.tm_wday+6)%7;return leadingNulls(Math.floor(days/7),2)},"%y":date=>(date.tm_year+1900).toString().substring(2),"%Y":date=>date.tm_year+1900,"%z":date=>{var off=date.tm_gmtoff;var ahead=off>=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":date=>date.tm_zone,"%%":()=>"%"};pattern=pattern.replace(/%%/g,"\0\0");for(var rule in EXPANSION_RULES_2){if(pattern.includes(rule)){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}pattern=pattern.replace(/\0\0/g,"%");var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}Module["_strftime"]=_strftime;_strftime.sig="ppppp";function _strftime_l(s,maxsize,format,tm,loc){s>>>=0;maxsize>>>=0;format>>>=0;tm>>>=0;loc>>>=0;return _strftime(s,maxsize,format,tm)}Module["_strftime_l"]=_strftime_l;_strftime_l.sig="pppppp";var _stackAlloc=stackAlloc;Module["_stackAlloc"]=_stackAlloc;var _stackRestore=stackSave;Module["_stackRestore"]=_stackRestore;var _stackSave=stackSave;Module["_stackSave"]=_stackSave;var FS_unlink=path=>FS.unlink(path);Module["FS_unlink"]=FS_unlink;var writeI53ToI64Clamped=(ptr,num)=>{if(num>0x8000000000000000){HEAPU32[ptr>>>2>>>0]=4294967295;HEAPU32[ptr+4>>>2>>>0]=2147483647}else if(num<-0x8000000000000000){HEAPU32[ptr>>>2>>>0]=0;HEAPU32[ptr+4>>>2>>>0]=2147483648}else{writeI53ToI64(ptr,num)}};Module["writeI53ToI64Clamped"]=writeI53ToI64Clamped;var writeI53ToI64Signaling=(ptr,num)=>{if(num>0x8000000000000000||num<-0x8000000000000000){throw`RangeError: ${num}`}writeI53ToI64(ptr,num)};Module["writeI53ToI64Signaling"]=writeI53ToI64Signaling;var writeI53ToU64Clamped=(ptr,num)=>{if(num>0x10000000000000000){HEAPU32[ptr>>>2>>>0]=4294967295;HEAPU32[ptr+4>>>2>>>0]=4294967295}else if(num<0){HEAPU32[ptr>>>2>>>0]=0;HEAPU32[ptr+4>>>2>>>0]=0}else{writeI53ToI64(ptr,num)}};Module["writeI53ToU64Clamped"]=writeI53ToU64Clamped;var writeI53ToU64Signaling=(ptr,num)=>{if(num<0||num>0x10000000000000000){throw`RangeError: ${num}`}writeI53ToI64(ptr,num)};Module["writeI53ToU64Signaling"]=writeI53ToU64Signaling;var readI53FromU64=ptr=>HEAPU32[ptr>>>2>>>0]+HEAPU32[ptr+4>>>2>>>0]*4294967296;Module["readI53FromU64"]=readI53FromU64;var convertI32PairToI53=(lo,hi)=>(lo>>>0)+hi*4294967296;Module["convertI32PairToI53"]=convertI32PairToI53;var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;Module["convertI32PairToI53Checked"]=convertI32PairToI53Checked;var convertU32PairToI53=(lo,hi)=>(lo>>>0)+(hi>>>0)*4294967296;Module["convertU32PairToI53"]=convertU32PairToI53;var getTempRet0=val=>__emscripten_tempret_get();Module["getTempRet0"]=getTempRet0;var ptrToString=ptr=>"0x"+ptr.toString(16).padStart(8,"0");Module["ptrToString"]=ptrToString;function _emscripten_notify_memory_growth(memoryIndex){memoryIndex>>>=0;updateMemoryViews()}Module["_emscripten_notify_memory_growth"]=_emscripten_notify_memory_growth;_emscripten_notify_memory_growth.sig="vp";function ___asctime_r(tmPtr,buf){tmPtr>>>=0;buf>>>=0;var date={tm_sec:HEAP32[tmPtr>>>2>>>0],tm_min:HEAP32[tmPtr+4>>>2>>>0],tm_hour:HEAP32[tmPtr+8>>>2>>>0],tm_mday:HEAP32[tmPtr+12>>>2>>>0],tm_mon:HEAP32[tmPtr+16>>>2>>>0],tm_year:HEAP32[tmPtr+20>>>2>>>0],tm_wday:HEAP32[tmPtr+24>>>2>>>0]};var days=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];var months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];var s=days[date.tm_wday]+" "+months[date.tm_mon]+(date.tm_mday<10?" ":" ")+date.tm_mday+(date.tm_hour<10?" 0":" ")+date.tm_hour+(date.tm_min<10?":0":":")+date.tm_min+(date.tm_sec<10?":0":":")+date.tm_sec+" "+(1900+date.tm_year)+"\n";stringToUTF8(s,buf,26);return buf}Module["___asctime_r"]=___asctime_r;___asctime_r.sig="ppp";var withStackSave=f=>{var stack=stackSave();var ret=f();stackRestore(stack);return ret};Module["withStackSave"]=withStackSave;function _strptime(buf,format,tm){buf>>>=0;format>>>=0;tm>>>=0;var pattern=UTF8ToString(format);var SPECIAL_CHARS="\\!@#$^&*()+=-[]/{}|:<>?,.";for(var i=0,ii=SPECIAL_CHARS.length;iEQUIVALENT_MATCHERS[c]||m).replace(/%(.)/g,(_,c)=>{let pat=DATE_PATTERNS[c];if(pat){capture.push(c);return`(${pat})`}else{return c}}).replace(/\s+/g,"\\s*");var matches=new RegExp("^"+pattern_out,"i").exec(UTF8ToString(buf));function initDate(){function fixup(value,min,max){return typeof value!="number"||isNaN(value)?min:value>=min?value<=max?value:max:min}return{year:fixup(HEAP32[tm+20>>>2>>>0]+1900,1970,9999),month:fixup(HEAP32[tm+16>>>2>>>0],0,11),day:fixup(HEAP32[tm+12>>>2>>>0],1,31),hour:fixup(HEAP32[tm+8>>>2>>>0],0,23),min:fixup(HEAP32[tm+4>>>2>>>0],0,59),sec:fixup(HEAP32[tm>>>2>>>0],0,59),gmtoff:0}}if(matches){var date=initDate();var value;var getMatch=symbol=>{var pos=capture.indexOf(symbol);if(pos>=0){return matches[pos+1]}return};if(value=getMatch("S")){date.sec=jstoi_q(value)}if(value=getMatch("M")){date.min=jstoi_q(value)}if(value=getMatch("H")){date.hour=jstoi_q(value)}else if(value=getMatch("I")){var hour=jstoi_q(value);if(value=getMatch("p")){hour+=value.toUpperCase()[0]==="P"?12:0}date.hour=hour}if(value=getMatch("Y")){date.year=jstoi_q(value)}else if(value=getMatch("y")){var year=jstoi_q(value);if(value=getMatch("C")){year+=jstoi_q(value)*100}else{year+=year<69?2e3:1900}date.year=year}if(value=getMatch("m")){date.month=jstoi_q(value)-1}else if(value=getMatch("b")){date.month=MONTH_NUMBERS[value.substring(0,3).toUpperCase()]||0}if(value=getMatch("d")){date.day=jstoi_q(value)}else if(value=getMatch("j")){var day=jstoi_q(value);var leapYear=isLeapYear(date.year);for(var month=0;month<12;++month){var daysUntilMonth=arraySum(leapYear?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR,month-1);if(day<=daysUntilMonth+(leapYear?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR)[month]){date.day=day-daysUntilMonth}}}else if(value=getMatch("a")){var weekDay=value.substring(0,3).toUpperCase();if(value=getMatch("U")){var weekDayNumber=DAY_NUMBERS_SUN_FIRST[weekDay];var weekNumber=jstoi_q(value);var janFirst=new Date(date.year,0,1);var endDate;if(janFirst.getDay()===0){endDate=addDays(janFirst,weekDayNumber+7*(weekNumber-1))}else{endDate=addDays(janFirst,7-janFirst.getDay()+weekDayNumber+7*(weekNumber-1))}date.day=endDate.getDate();date.month=endDate.getMonth()}else if(value=getMatch("W")){var weekDayNumber=DAY_NUMBERS_MON_FIRST[weekDay];var weekNumber=jstoi_q(value);var janFirst=new Date(date.year,0,1);var endDate;if(janFirst.getDay()===1){endDate=addDays(janFirst,weekDayNumber+7*(weekNumber-1))}else{endDate=addDays(janFirst,7-janFirst.getDay()+1+weekDayNumber+7*(weekNumber-1))}date.day=endDate.getDate();date.month=endDate.getMonth()}}if(value=getMatch("z")){if(value.toLowerCase()==="z"){date.gmtoff=0}else{var match=value.match(/^((?:\-|\+)\d\d):?(\d\d)?/);date.gmtoff=match[1]*3600;if(match[2]){date.gmtoff+=date.gmtoff>0?match[2]*60:-match[2]*60}}}var fullDate=new Date(date.year,date.month,date.day,date.hour,date.min,date.sec,0);HEAP32[tm>>>2>>>0]=fullDate.getSeconds();HEAP32[tm+4>>>2>>>0]=fullDate.getMinutes();HEAP32[tm+8>>>2>>>0]=fullDate.getHours();HEAP32[tm+12>>>2>>>0]=fullDate.getDate();HEAP32[tm+16>>>2>>>0]=fullDate.getMonth();HEAP32[tm+20>>>2>>>0]=fullDate.getFullYear()-1900;HEAP32[tm+24>>>2>>>0]=fullDate.getDay();HEAP32[tm+28>>>2>>>0]=arraySum(isLeapYear(fullDate.getFullYear())?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR,fullDate.getMonth()-1)+fullDate.getDate()-1;HEAP32[tm+32>>>2>>>0]=0;HEAP32[tm+36>>>2>>>0]=date.gmtoff;return buf+intArrayFromString(matches[0]).length-1}return 0}Module["_strptime"]=_strptime;_strptime.sig="pppp";function _strptime_l(buf,format,tm,locale){buf>>>=0;format>>>=0;tm>>>=0;locale>>>=0;return _strptime(buf,format,tm)}Module["_strptime_l"]=_strptime_l;_strptime_l.sig="ppppp";var ERRNO_MESSAGES={0:"Success",1:"Arg list too long",2:"Permission denied",3:"Address already in use",4:"Address not available",5:"Address family not supported by protocol family",6:"No more processes",7:"Socket already connected",8:"Bad file number",9:"Trying to read unreadable message",10:"Mount device busy",11:"Operation canceled",12:"No children",13:"Connection aborted",14:"Connection refused",15:"Connection reset by peer",16:"File locking deadlock error",17:"Destination address required",18:"Math arg out of domain of func",19:"Quota exceeded",20:"File exists",21:"Bad address",22:"File too large",23:"Host is unreachable",24:"Identifier removed",25:"Illegal byte sequence",26:"Connection already in progress",27:"Interrupted system call",28:"Invalid argument",29:"I/O error",30:"Socket is already connected",31:"Is a directory",32:"Too many symbolic links",33:"Too many open files",34:"Too many links",35:"Message too long",36:"Multihop attempted",37:"File or path name too long",38:"Network interface is not configured",39:"Connection reset by network",40:"Network is unreachable",41:"Too many open files in system",42:"No buffer space available",43:"No such device",44:"No such file or directory",45:"Exec format error",46:"No record locks available",47:"The link has been severed",48:"Not enough core",49:"No message of desired type",50:"Protocol not available",51:"No space left on device",52:"Function not implemented",53:"Socket is not connected",54:"Not a directory",55:"Directory not empty",56:"State not recoverable",57:"Socket operation on non-socket",59:"Not a typewriter",60:"No such device or address",61:"Value too large for defined data type",62:"Previous owner died",63:"Not super-user",64:"Broken pipe",65:"Protocol error",66:"Unknown protocol",67:"Protocol wrong type for socket",68:"Math result not representable",69:"Read only file system",70:"Illegal seek",71:"No such process",72:"Stale file handle",73:"Connection timed out",74:"Text file busy",75:"Cross-device link",100:"Device not a stream",101:"Bad font file fmt",102:"Invalid slot",103:"Invalid request code",104:"No anode",105:"Block device required",106:"Channel number out of range",107:"Level 3 halted",108:"Level 3 reset",109:"Link number out of range",110:"Protocol driver not attached",111:"No CSI structure available",112:"Level 2 halted",113:"Invalid exchange",114:"Invalid request descriptor",115:"Exchange full",116:"No data (for no delay io)",117:"Timer expired",118:"Out of streams resources",119:"Machine is not on the network",120:"Package not installed",121:"The object is remote",122:"Advertise error",123:"Srmount error",124:"Communication error on send",125:"Cross mount point (not really error)",126:"Given log. name not unique",127:"f.d. invalid for this operation",128:"Remote address changed",129:"Can access a needed shared lib",130:"Accessing a corrupted shared lib",131:".lib section in a.out corrupted",132:"Attempting to link in too many libs",133:"Attempting to exec a shared library",135:"Streams pipe error",136:"Too many users",137:"Socket type not supported",138:"Not supported",139:"Protocol family not supported",140:"Can't send after socket shutdown",141:"Too many references",142:"Host is down",148:"No medium (in tape drive)",156:"Level 2 not synchronized"};Module["ERRNO_MESSAGES"]=ERRNO_MESSAGES;var _endprotoent=()=>{};Module["_endprotoent"]=_endprotoent;_endprotoent.sig="v";function _getprotoent(number){if(_setprotoent.index===Protocols.list.length){return 0}var result=Protocols.list[_setprotoent.index++];return result}Module["_getprotoent"]=_getprotoent;_getprotoent.sig="p";function _getprotobynumber(number){_setprotoent(true);var result=Protocols.map[number];return result}Module["_getprotobynumber"]=_getprotobynumber;_getprotobynumber.sig="pi";function _emscripten_run_script(ptr){ptr>>>=0;eval(UTF8ToString(ptr))}Module["_emscripten_run_script"]=_emscripten_run_script;_emscripten_run_script.sig="vp";function _emscripten_run_script_int(ptr){ptr>>>=0;return eval(UTF8ToString(ptr))|0}Module["_emscripten_run_script_int"]=_emscripten_run_script_int;_emscripten_run_script_int.sig="ip";function _emscripten_run_script_string(ptr){ptr>>>=0;var s=eval(UTF8ToString(ptr));if(s==null){return 0}s+="";var me=_emscripten_run_script_string;var len=lengthBytesUTF8(s);if(!me.bufferSize||me.bufferSizeMath.random();Module["_emscripten_random"]=_emscripten_random;_emscripten_random.sig="f";var warnOnce=text=>{warnOnce.shown||={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;if(ENVIRONMENT_IS_NODE)text="warning: "+text;err(text)}};Module["warnOnce"]=warnOnce;function jsStackTrace(){return(new Error).stack.toString()}Module["jsStackTrace"]=jsStackTrace;function getCallstack(flags){var callstack=jsStackTrace();var iThisFunc=callstack.lastIndexOf("_emscripten_log");var iThisFunc2=callstack.lastIndexOf("_emscripten_get_callstack");var iNextLine=callstack.indexOf("\n",Math.max(iThisFunc,iThisFunc2))+1;callstack=callstack.slice(iNextLine);if(flags&8&&typeof emscripten_source_map=="undefined"){warnOnce('Source map information is not available, emscripten_log with EM_LOG_C_STACK will be ignored. Build with "--pre-js $EMSCRIPTEN/src/emscripten-source-map.min.js" linker flag to add source map loading to code.');flags^=8;flags|=16}var lines=callstack.split("\n");callstack="";var newFirefoxRe=new RegExp("\\s*(.*?)@(.*?):([0-9]+):([0-9]+)");var firefoxRe=new RegExp("\\s*(.*?)@(.*):(.*)(:(.*))?");var chromeRe=new RegExp("\\s*at (.*?) \\((.*):(.*):(.*)\\)");for(var l in lines){var line=lines[l];var symbolName="";var file="";var lineno=0;var column=0;var parts=chromeRe.exec(line);if(parts&&parts.length==5){symbolName=parts[1];file=parts[2];lineno=parts[3];column=parts[4]}else{parts=newFirefoxRe.exec(line);if(!parts)parts=firefoxRe.exec(line);if(parts&&parts.length>=4){symbolName=parts[1];file=parts[2];lineno=parts[3];column=parts[4]|0}else{callstack+=line+"\n";continue}}var haveSourceMap=false;if(flags&8){var orig=emscripten_source_map.originalPositionFor({line:lineno,column:column});haveSourceMap=orig?.source;if(haveSourceMap){if(flags&64){orig.source=orig.source.substring(orig.source.replace(/\\/g,"/").lastIndexOf("/")+1)}callstack+=` at ${symbolName} (${orig.source}:${orig.line}:${orig.column})\n`}}if(flags&16||!haveSourceMap){if(flags&64){file=file.substring(file.replace(/\\/g,"/").lastIndexOf("/")+1)}callstack+=(haveSourceMap?` = ${symbolName}`:` at ${symbolName}`)+` (${file}:${lineno}:${column})\n`}}callstack=callstack.replace(/\s+$/,"");return callstack}Module["getCallstack"]=getCallstack;var emscriptenLog=(flags,str)=>{if(flags&24){str=str.replace(/\s+$/,"");str+=(str.length>0?"\n":"")+getCallstack(flags)}if(flags&1){if(flags&4){console.error(str)}else if(flags&2){console.warn(str)}else if(flags&512){console.info(str)}else if(flags&256){console.debug(str)}else{console.log(str)}}else if(flags&6){err(str)}else{out(str)}};Module["emscriptenLog"]=emscriptenLog;var reallyNegative=x=>x<0||x===0&&1/x===-Infinity;Module["reallyNegative"]=reallyNegative;var reSign=(value,bits)=>{if(value<=0){return value}var half=bits<=32?Math.abs(1<=half&&(bits<=32||value>half)){value=-2*half+value}return value};Module["reSign"]=reSign;var unSign=(value,bits)=>{if(value>=0){return value}return bits<=32?2*Math.abs(1<{var end=ptr;while(HEAPU8[end>>>0])++end;return end-ptr};Module["strLen"]=strLen;var formatString=(format,varargs)=>{var textIndex=format;var argIndex=varargs;function prepVararg(ptr,type){if(type==="double"||type==="i64"){if(ptr&7){ptr+=4}}else{}return ptr}function getNextArg(type){var ret;argIndex=prepVararg(argIndex,type);if(type==="double"){ret=HEAPF64[argIndex>>>3>>>0];argIndex+=8}else if(type=="i64"){ret=[HEAP32[argIndex>>>2>>>0],HEAP32[argIndex+4>>>2>>>0]];argIndex+=8}else{type="i32";ret=HEAP32[argIndex>>>2>>>0];argIndex+=4}return ret}var ret=[];var curr,next,currArg;while(1){var startTextIndex=textIndex;curr=HEAP8[textIndex>>>0];if(curr===0)break;next=HEAP8[textIndex+1>>>0];if(curr==37){var flagAlwaysSigned=false;var flagLeftAlign=false;var flagAlternative=false;var flagZeroPad=false;var flagPadSign=false;flagsLoop:while(1){switch(next){case 43:flagAlwaysSigned=true;break;case 45:flagLeftAlign=true;break;case 35:flagAlternative=true;break;case 48:if(flagZeroPad){break flagsLoop}else{flagZeroPad=true;break}case 32:flagPadSign=true;break;default:break flagsLoop}textIndex++;next=HEAP8[textIndex+1>>>0]}var width=0;if(next==42){width=getNextArg("i32");textIndex++;next=HEAP8[textIndex+1>>>0]}else{while(next>=48&&next<=57){width=width*10+(next-48);textIndex++;next=HEAP8[textIndex+1>>>0]}}var precisionSet=false,precision=-1;if(next==46){precision=0;precisionSet=true;textIndex++;next=HEAP8[textIndex+1>>>0];if(next==42){precision=getNextArg("i32");textIndex++}else{while(1){var precisionChr=HEAP8[textIndex+1>>>0];if(precisionChr<48||precisionChr>57)break;precision=precision*10+(precisionChr-48);textIndex++}}next=HEAP8[textIndex+1>>>0]}if(precision<0){precision=6;precisionSet=false}var argSize;switch(String.fromCharCode(next)){case"h":var nextNext=HEAP8[textIndex+2>>>0];if(nextNext==104){textIndex++;argSize=1}else{argSize=2}break;case"l":var nextNext=HEAP8[textIndex+2>>>0];if(nextNext==108){textIndex++;argSize=8}else{argSize=4}break;case"L":case"q":case"j":argSize=8;break;case"z":case"t":case"I":argSize=4;break;default:argSize=null}if(argSize)textIndex++;next=HEAP8[textIndex+1>>>0];switch(String.fromCharCode(next)){case"d":case"i":case"u":case"o":case"x":case"X":case"p":{var signed=next==100||next==105;argSize=argSize||4;currArg=getNextArg("i"+argSize*8);var argText;if(argSize==8){currArg=next==117?convertU32PairToI53(currArg[0],currArg[1]):convertI32PairToI53(currArg[0],currArg[1])}if(argSize<=4){var limit=Math.pow(256,argSize)-1;currArg=(signed?reSign:unSign)(currArg&limit,argSize*8)}var currAbsArg=Math.abs(currArg);var prefix="";if(next==100||next==105){argText=reSign(currArg,8*argSize).toString(10)}else if(next==117){argText=unSign(currArg,8*argSize).toString(10);currArg=Math.abs(currArg)}else if(next==111){argText=(flagAlternative?"0":"")+currAbsArg.toString(8)}else if(next==120||next==88){prefix=flagAlternative&&currArg!=0?"0x":"";if(currArg<0){currArg=-currArg;argText=(currAbsArg-1).toString(16);var buffer=[];for(var i=0;i=0){if(flagAlwaysSigned){prefix="+"+prefix}else if(flagPadSign){prefix=" "+prefix}}if(argText.charAt(0)=="-"){prefix="-"+prefix;argText=argText.substr(1)}while(prefix.length+argText.lengthexponent&&exponent>=-4){next=(next==103?"f":"F").charCodeAt(0);precision-=exponent+1}else{next=(next==103?"e":"E").charCodeAt(0);precision--}effectivePrecision=Math.min(precision,20)}if(next==101||next==69){argText=currArg.toExponential(effectivePrecision);if(/[eE][-+]\d$/.test(argText)){argText=argText.slice(0,-1)+"0"+argText.slice(-1)}}else if(next==102||next==70){argText=currArg.toFixed(effectivePrecision);if(currArg===0&&reallyNegative(currArg)){argText="-"+argText}}var parts=argText.split("e");if(isGeneral&&!flagAlternative){while(parts[0].length>1&&parts[0].includes(".")&&(parts[0].slice(-1)=="0"||parts[0].slice(-1)==".")){parts[0]=parts[0].slice(0,-1)}}else{if(flagAlternative&&argText.indexOf(".")==-1)parts[0]+=".";while(precision>effectivePrecision++)parts[0]+="0"}argText=parts[0]+(parts.length>1?"e"+parts[1]:"");if(next==69)argText=argText.toUpperCase();if(currArg>=0){if(flagAlwaysSigned){argText="+"+argText}else if(flagPadSign){argText=" "+argText}}}while(argText.length>>0])}}else{ret=ret.concat(intArrayFromString("(null)".substr(0,argLength),true))}if(flagLeftAlign){while(argLength0){ret.push(32)}if(!flagLeftAlign)ret.push(getNextArg("i8"));break}case"n":{var ptr=getNextArg("i32*");HEAP32[ptr>>>2>>>0]=ret.length;break}case"%":{ret.push(curr);break}default:{for(var i=startTextIndex;i>>0])}}}textIndex+=2}else{ret.push(curr);textIndex+=1}}return ret};Module["formatString"]=formatString;function _emscripten_log(flags,format,varargs){format>>>=0;varargs>>>=0;var result=formatString(format,varargs);var str=UTF8ArrayToString(result,0);emscriptenLog(flags,str)}Module["_emscripten_log"]=_emscripten_log;_emscripten_log.sig="vipp";function _emscripten_get_compiler_setting(name){name>>>=0;throw"You must build with -sRETAIN_COMPILER_SETTINGS for getCompilerSetting or emscripten_get_compiler_setting to work"}Module["_emscripten_get_compiler_setting"]=_emscripten_get_compiler_setting;_emscripten_get_compiler_setting.sig="pp";var _emscripten_has_asyncify=()=>0;Module["_emscripten_has_asyncify"]=_emscripten_has_asyncify;_emscripten_has_asyncify.sig="i";function _emscripten_debugger(){debugger}Module["_emscripten_debugger"]=_emscripten_debugger;_emscripten_debugger.sig="v";function _emscripten_print_double(x,to,max){to>>>=0;var str=x+"";if(to)return stringToUTF8(str,to,max);else return lengthBytesUTF8(str)}Module["_emscripten_print_double"]=_emscripten_print_double;_emscripten_print_double.sig="idpi";function _emscripten_get_module_name(buf,length){buf>>>=0;length>>>=0;return stringToUTF8(wasmBinaryFile,buf,length)}Module["_emscripten_get_module_name"]=_emscripten_get_module_name;_emscripten_get_module_name.sig="ppp";function _emscripten_asm_const_double(code,sigPtr,argbuf){code>>>=0;sigPtr>>>=0;argbuf>>>=0;return runEmAsmFunction(code,sigPtr,argbuf)}Module["_emscripten_asm_const_double"]=_emscripten_asm_const_double;_emscripten_asm_const_double.sig="dppp";function _emscripten_asm_const_ptr(code,sigPtr,argbuf){code>>>=0;sigPtr>>>=0;argbuf>>>=0;return runEmAsmFunction(code,sigPtr,argbuf)}Module["_emscripten_asm_const_ptr"]=_emscripten_asm_const_ptr;_emscripten_asm_const_ptr.sig="pppp";var runMainThreadEmAsm=(emAsmAddr,sigPtr,argbuf,sync)=>{var args=readEmAsmArgs(sigPtr,argbuf);return ASM_CONSTS[emAsmAddr](...args)};Module["runMainThreadEmAsm"]=runMainThreadEmAsm;function _emscripten_asm_const_int_sync_on_main_thread(emAsmAddr,sigPtr,argbuf){emAsmAddr>>>=0;sigPtr>>>=0;argbuf>>>=0;return runMainThreadEmAsm(emAsmAddr,sigPtr,argbuf,1)}Module["_emscripten_asm_const_int_sync_on_main_thread"]=_emscripten_asm_const_int_sync_on_main_thread;_emscripten_asm_const_int_sync_on_main_thread.sig="ippp";function _emscripten_asm_const_ptr_sync_on_main_thread(emAsmAddr,sigPtr,argbuf){emAsmAddr>>>=0;sigPtr>>>=0;argbuf>>>=0;return runMainThreadEmAsm(emAsmAddr,sigPtr,argbuf,1)}Module["_emscripten_asm_const_ptr_sync_on_main_thread"]=_emscripten_asm_const_ptr_sync_on_main_thread;_emscripten_asm_const_ptr_sync_on_main_thread.sig="pppp";var _emscripten_asm_const_double_sync_on_main_thread=_emscripten_asm_const_int_sync_on_main_thread;Module["_emscripten_asm_const_double_sync_on_main_thread"]=_emscripten_asm_const_double_sync_on_main_thread;_emscripten_asm_const_double_sync_on_main_thread.sig="dppp";function _emscripten_asm_const_async_on_main_thread(emAsmAddr,sigPtr,argbuf){emAsmAddr>>>=0;sigPtr>>>=0;argbuf>>>=0;return runMainThreadEmAsm(emAsmAddr,sigPtr,argbuf,0)}Module["_emscripten_asm_const_async_on_main_thread"]=_emscripten_asm_const_async_on_main_thread;_emscripten_asm_const_async_on_main_thread.sig="vppp";var jstoi_s=Number;Module["jstoi_s"]=jstoi_s;function __Unwind_Backtrace(func,arg){func>>>=0;arg>>>=0;var trace=getCallstack();var parts=trace.split("\n");for(var i=0;i>>=0;ipBefore>>>=0;return abort("Unwind_GetIPInfo")}Module["__Unwind_GetIPInfo"]=__Unwind_GetIPInfo;__Unwind_GetIPInfo.sig="ppp";function __Unwind_FindEnclosingFunction(ip){ip>>>=0;return 0}Module["__Unwind_FindEnclosingFunction"]=__Unwind_FindEnclosingFunction;__Unwind_FindEnclosingFunction.sig="pp";function __Unwind_RaiseException(ex){ex>>>=0;err("Warning: _Unwind_RaiseException is not correctly implemented");return ___cxa_throw(ex,0,0)}Module["__Unwind_RaiseException"]=__Unwind_RaiseException;__Unwind_RaiseException.sig="ip";function __Unwind_DeleteException(ex){ex>>>=0;err("TODO: Unwind_DeleteException")}Module["__Unwind_DeleteException"]=__Unwind_DeleteException;__Unwind_DeleteException.sig="vp";var listenOnce=(object,event,func)=>{object.addEventListener(event,func,{"once":true})};Module["listenOnce"]=listenOnce;var autoResumeAudioContext=(ctx,elements)=>{if(!elements){elements=[document,document.getElementById("canvas")]}["keydown","mousedown","touchstart"].forEach(event=>{elements.forEach(element=>{if(element){listenOnce(element,event,()=>{if(ctx.state==="suspended")ctx.resume()})}})})};Module["autoResumeAudioContext"]=autoResumeAudioContext;var getDynCaller=(sig,ptr)=>(...args)=>dynCall(sig,ptr,args);Module["getDynCaller"]=getDynCaller;var _emscripten_force_exit=status=>{__emscripten_runtime_keepalive_clear();_exit(status)};Module["_emscripten_force_exit"]=_emscripten_force_exit;_emscripten_force_exit.sig="vi";function _emscripten_outn(str,len){str>>>=0;len>>>=0;return out(UTF8ToString(str,len))}Module["_emscripten_outn"]=_emscripten_outn;_emscripten_outn.sig="vpp";function _emscripten_errn(str,len){str>>>=0;len>>>=0;return err(UTF8ToString(str,len))}Module["_emscripten_errn"]=_emscripten_errn;_emscripten_errn.sig="vpp";var _emscripten_throw_number=number=>{throw number};Module["_emscripten_throw_number"]=_emscripten_throw_number;_emscripten_throw_number.sig="vd";function _emscripten_throw_string(str){str>>>=0;throw UTF8ToString(str)}Module["_emscripten_throw_string"]=_emscripten_throw_string;_emscripten_throw_string.sig="vp";var runtimeKeepalivePush=()=>{runtimeKeepaliveCounter+=1};Module["runtimeKeepalivePush"]=runtimeKeepalivePush;runtimeKeepalivePush.sig="v";var runtimeKeepalivePop=()=>{runtimeKeepaliveCounter-=1};Module["runtimeKeepalivePop"]=runtimeKeepalivePop;runtimeKeepalivePop.sig="v";var _emscripten_runtime_keepalive_push=runtimeKeepalivePush;Module["_emscripten_runtime_keepalive_push"]=_emscripten_runtime_keepalive_push;_emscripten_runtime_keepalive_push.sig="v";var _emscripten_runtime_keepalive_pop=runtimeKeepalivePop;Module["_emscripten_runtime_keepalive_pop"]=_emscripten_runtime_keepalive_pop;_emscripten_runtime_keepalive_pop.sig="v";var _emscripten_runtime_keepalive_check=keepRuntimeAlive;Module["_emscripten_runtime_keepalive_check"]=_emscripten_runtime_keepalive_check;_emscripten_runtime_keepalive_check.sig="i";var asmjsMangle=x=>{if(x=="__main_argc_argv"){x="main"}return x.startsWith("dynCall_")?x:"_"+x};Module["asmjsMangle"]=asmjsMangle;var ___global_base=1024;Module["___global_base"]=___global_base;function __emscripten_fs_load_embedded_files(ptr){ptr>>>=0;do{var name_addr=HEAPU32[ptr>>>2>>>0];ptr+=4;var len=HEAPU32[ptr>>>2>>>0];ptr+=4;var content=HEAPU32[ptr>>>2>>>0];ptr+=4;var name=UTF8ToString(name_addr);FS.createPath("/",PATH.dirname(name),true,true);FS.createDataFile(name,null,HEAP8.subarray(content>>>0,content+len>>>0),true,true,true)}while(HEAPU32[ptr>>>2>>>0])}Module["__emscripten_fs_load_embedded_files"]=__emscripten_fs_load_embedded_files;__emscripten_fs_load_embedded_files.sig="vp";var POINTER_SIZE=4;Module["POINTER_SIZE"]=POINTER_SIZE;function getNativeTypeSize(type){switch(type){case"i1":case"i8":case"u8":return 1;case"i16":case"u16":return 2;case"i32":case"u32":return 4;case"i64":case"u64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return POINTER_SIZE}if(type[0]==="i"){const bits=Number(type.substr(1));assert(bits%8===0,`getNativeTypeSize invalid bits ${bits}, ${type} type`);return bits/8}return 0}}}Module["getNativeTypeSize"]=getNativeTypeSize;var STACK_SIZE=5242880;Module["STACK_SIZE"]=STACK_SIZE;var STACK_ALIGN=16;Module["STACK_ALIGN"]=STACK_ALIGN;var ASSERTIONS=0;Module["ASSERTIONS"]=ASSERTIONS;var getCFunc=ident=>{var func=Module["_"+ident];return func};Module["getCFunc"]=getCFunc;var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={"string":str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},"array":arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};Module["cwrap"]=cwrap;var removeFunction=index=>{functionsInTableMap.delete(getWasmTableEntry(index));setWasmTableEntry(index,null);freeTableIndexes.push(index)};Module["removeFunction"]=removeFunction;var _emscripten_math_cbrt=Math.cbrt;Module["_emscripten_math_cbrt"]=_emscripten_math_cbrt;_emscripten_math_cbrt.sig="dd";var _emscripten_math_pow=Math.pow;Module["_emscripten_math_pow"]=_emscripten_math_pow;_emscripten_math_pow.sig="ddd";var _emscripten_math_random=Math.random;Module["_emscripten_math_random"]=_emscripten_math_random;_emscripten_math_random.sig="d";var _emscripten_math_sign=Math.sign;Module["_emscripten_math_sign"]=_emscripten_math_sign;_emscripten_math_sign.sig="dd";var _emscripten_math_sqrt=Math.sqrt;Module["_emscripten_math_sqrt"]=_emscripten_math_sqrt;_emscripten_math_sqrt.sig="dd";var _emscripten_math_exp=Math.exp;Module["_emscripten_math_exp"]=_emscripten_math_exp;_emscripten_math_exp.sig="dd";var _emscripten_math_expm1=Math.expm1;Module["_emscripten_math_expm1"]=_emscripten_math_expm1;_emscripten_math_expm1.sig="dd";var _emscripten_math_fmod=(x,y)=>x%y;Module["_emscripten_math_fmod"]=_emscripten_math_fmod;_emscripten_math_fmod.sig="ddd";var _emscripten_math_log=Math.log;Module["_emscripten_math_log"]=_emscripten_math_log;_emscripten_math_log.sig="dd";var _emscripten_math_log1p=Math.log1p;Module["_emscripten_math_log1p"]=_emscripten_math_log1p;_emscripten_math_log1p.sig="dd";var _emscripten_math_log10=Math.log10;Module["_emscripten_math_log10"]=_emscripten_math_log10;_emscripten_math_log10.sig="dd";var _emscripten_math_log2=Math.log2;Module["_emscripten_math_log2"]=_emscripten_math_log2;_emscripten_math_log2.sig="dd";var _emscripten_math_round=Math.round;Module["_emscripten_math_round"]=_emscripten_math_round;_emscripten_math_round.sig="dd";var _emscripten_math_acos=Math.acos;Module["_emscripten_math_acos"]=_emscripten_math_acos;_emscripten_math_acos.sig="dd";var _emscripten_math_acosh=Math.acosh;Module["_emscripten_math_acosh"]=_emscripten_math_acosh;_emscripten_math_acosh.sig="dd";var _emscripten_math_asin=Math.asin;Module["_emscripten_math_asin"]=_emscripten_math_asin;_emscripten_math_asin.sig="dd";var _emscripten_math_asinh=Math.asinh;Module["_emscripten_math_asinh"]=_emscripten_math_asinh;_emscripten_math_asinh.sig="dd";var _emscripten_math_atan=Math.atan;Module["_emscripten_math_atan"]=_emscripten_math_atan;_emscripten_math_atan.sig="dd";var _emscripten_math_atanh=Math.atanh;Module["_emscripten_math_atanh"]=_emscripten_math_atanh;_emscripten_math_atanh.sig="dd";var _emscripten_math_atan2=Math.atan2;Module["_emscripten_math_atan2"]=_emscripten_math_atan2;_emscripten_math_atan2.sig="ddd";var _emscripten_math_cos=Math.cos;Module["_emscripten_math_cos"]=_emscripten_math_cos;_emscripten_math_cos.sig="dd";var _emscripten_math_cosh=Math.cosh;Module["_emscripten_math_cosh"]=_emscripten_math_cosh;_emscripten_math_cosh.sig="dd";function _emscripten_math_hypot(count,varargs){varargs>>>=0;var args=[];for(var i=0;i>>3>>>0])}return Math.hypot(...args)}Module["_emscripten_math_hypot"]=_emscripten_math_hypot;_emscripten_math_hypot.sig="dip";var _emscripten_math_sin=Math.sin;Module["_emscripten_math_sin"]=_emscripten_math_sin;_emscripten_math_sin.sig="dd";var _emscripten_math_sinh=Math.sinh;Module["_emscripten_math_sinh"]=_emscripten_math_sinh;_emscripten_math_sinh.sig="dd";var _emscripten_math_tan=Math.tan;Module["_emscripten_math_tan"]=_emscripten_math_tan;_emscripten_math_tan.sig="dd";var _emscripten_math_tanh=Math.tanh;Module["_emscripten_math_tanh"]=_emscripten_math_tanh;_emscripten_math_tanh.sig="dd";function intArrayToString(array){var ret=[];for(var i=0;i255){chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}Module["intArrayToString"]=intArrayToString;var AsciiToString=ptr=>{ptr>>>=0;var str="";while(1){var ch=HEAPU8[ptr++>>>0];if(!ch)return str;str+=String.fromCharCode(ch)}};Module["AsciiToString"]=AsciiToString;var UTF16Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf-16le"):undefined;Module["UTF16Decoder"]=UTF16Decoder;var UTF16ToString=(ptr,maxBytesToRead)=>{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx>>>0])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr>>>0,endPtr>>>0));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>>1>>>0];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str};Module["UTF16ToString"]=UTF16ToString;var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>>1>>>0]=codeUnit;outPtr+=2}HEAP16[outPtr>>>1>>>0]=0;return outPtr-startPtr};Module["stringToUTF16"]=stringToUTF16;var lengthBytesUTF16=str=>str.length*2;Module["lengthBytesUTF16"]=lengthBytesUTF16;var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>>2>>>0];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str};Module["UTF32ToString"]=UTF32ToString;var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{outPtr>>>=0;maxBytesToWrite??=2147483647;if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>>2>>>0]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>>2>>>0]=0;return outPtr-startPtr};Module["stringToUTF32"]=stringToUTF32;var lengthBytesUTF32=str=>{var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len};Module["lengthBytesUTF32"]=lengthBytesUTF32;var JSEvents={removeAllEventListeners(){while(JSEvents.eventHandlers.length){JSEvents._removeHandler(JSEvents.eventHandlers.length-1)}JSEvents.deferredCalls=[]},inEventHandler:0,deferredCalls:[],deferCall(targetFunction,precedence,argsList){function arraysHaveEqualContent(arrA,arrB){if(arrA.length!=arrB.length)return false;for(var i in arrA){if(arrA[i]!=arrB[i])return false}return true}for(var i in JSEvents.deferredCalls){var call=JSEvents.deferredCalls[i];if(call.targetFunction==targetFunction&&arraysHaveEqualContent(call.argsList,argsList)){return}}JSEvents.deferredCalls.push({targetFunction:targetFunction,precedence:precedence,argsList:argsList});JSEvents.deferredCalls.sort((x,y)=>x.precedence{for(var i=0;icString>2?UTF8ToString(cString):cString;Module["maybeCStringToJsString"]=maybeCStringToJsString;var specialHTMLTargets=[0,typeof document!="undefined"?document:0,typeof window!="undefined"?window:0];Module["specialHTMLTargets"]=specialHTMLTargets;var findEventTarget=target=>{target=maybeCStringToJsString(target);var domElement=specialHTMLTargets[target]||(typeof document!="undefined"?document.querySelector(target):undefined);return domElement};Module["findEventTarget"]=findEventTarget;var registerKeyEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.keyEvent)JSEvents.keyEvent=_malloc(176);var keyEventHandlerFunc=e=>{var keyEventData=JSEvents.keyEvent;HEAPF64[keyEventData>>>3>>>0]=e.timeStamp;var idx=keyEventData>>>2;HEAP32[idx+2>>>0]=e.location;HEAP32[idx+3>>>0]=e.ctrlKey;HEAP32[idx+4>>>0]=e.shiftKey;HEAP32[idx+5>>>0]=e.altKey;HEAP32[idx+6>>>0]=e.metaKey;HEAP32[idx+7>>>0]=e.repeat;HEAP32[idx+8>>>0]=e.charCode;HEAP32[idx+9>>>0]=e.keyCode;HEAP32[idx+10>>>0]=e.which;stringToUTF8(e.key||"",keyEventData+44,32);stringToUTF8(e.code||"",keyEventData+76,32);stringToUTF8(e.char||"",keyEventData+108,32);stringToUTF8(e.locale||"",keyEventData+140,32);if(getWasmTableEntry(callbackfunc)(eventTypeId,keyEventData,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:keyEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerKeyEventCallback"]=registerKeyEventCallback;var findCanvasEventTarget=findEventTarget;Module["findCanvasEventTarget"]=findCanvasEventTarget;function _emscripten_set_keypress_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerKeyEventCallback(target,userData,useCapture,callbackfunc,1,"keypress",targetThread)}Module["_emscripten_set_keypress_callback_on_thread"]=_emscripten_set_keypress_callback_on_thread;_emscripten_set_keypress_callback_on_thread.sig="ippipp";function _emscripten_set_keydown_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerKeyEventCallback(target,userData,useCapture,callbackfunc,2,"keydown",targetThread)}Module["_emscripten_set_keydown_callback_on_thread"]=_emscripten_set_keydown_callback_on_thread;_emscripten_set_keydown_callback_on_thread.sig="ippipp";function _emscripten_set_keyup_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerKeyEventCallback(target,userData,useCapture,callbackfunc,3,"keyup",targetThread)}Module["_emscripten_set_keyup_callback_on_thread"]=_emscripten_set_keyup_callback_on_thread;_emscripten_set_keyup_callback_on_thread.sig="ippipp";var getBoundingClientRect=e=>specialHTMLTargets.indexOf(e)<0?e.getBoundingClientRect():{"left":0,"top":0};Module["getBoundingClientRect"]=getBoundingClientRect;var fillMouseEventData=(eventStruct,e,target)=>{HEAPF64[eventStruct>>>3>>>0]=e.timeStamp;var idx=eventStruct>>>2;HEAP32[idx+2>>>0]=e.screenX;HEAP32[idx+3>>>0]=e.screenY;HEAP32[idx+4>>>0]=e.clientX;HEAP32[idx+5>>>0]=e.clientY;HEAP32[idx+6>>>0]=e.ctrlKey;HEAP32[idx+7>>>0]=e.shiftKey;HEAP32[idx+8>>>0]=e.altKey;HEAP32[idx+9>>>0]=e.metaKey;HEAP16[idx*2+20>>>0]=e.button;HEAP16[idx*2+21>>>0]=e.buttons;HEAP32[idx+11>>>0]=e["movementX"];HEAP32[idx+12>>>0]=e["movementY"];var rect=getBoundingClientRect(target);HEAP32[idx+13>>>0]=e.clientX-(rect.left|0);HEAP32[idx+14>>>0]=e.clientY-(rect.top|0)};Module["fillMouseEventData"]=fillMouseEventData;var registerMouseEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.mouseEvent)JSEvents.mouseEvent=_malloc(72);target=findEventTarget(target);var mouseEventHandlerFunc=(e=event)=>{fillMouseEventData(JSEvents.mouseEvent,e,target);if(getWasmTableEntry(callbackfunc)(eventTypeId,JSEvents.mouseEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:eventTypeString!="mousemove"&&eventTypeString!="mouseenter"&&eventTypeString!="mouseleave",eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:mouseEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerMouseEventCallback"]=registerMouseEventCallback;function _emscripten_set_click_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,4,"click",targetThread)}Module["_emscripten_set_click_callback_on_thread"]=_emscripten_set_click_callback_on_thread;_emscripten_set_click_callback_on_thread.sig="ippipp";function _emscripten_set_mousedown_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,5,"mousedown",targetThread)}Module["_emscripten_set_mousedown_callback_on_thread"]=_emscripten_set_mousedown_callback_on_thread;_emscripten_set_mousedown_callback_on_thread.sig="ippipp";function _emscripten_set_mouseup_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,6,"mouseup",targetThread)}Module["_emscripten_set_mouseup_callback_on_thread"]=_emscripten_set_mouseup_callback_on_thread;_emscripten_set_mouseup_callback_on_thread.sig="ippipp";function _emscripten_set_dblclick_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,7,"dblclick",targetThread)}Module["_emscripten_set_dblclick_callback_on_thread"]=_emscripten_set_dblclick_callback_on_thread;_emscripten_set_dblclick_callback_on_thread.sig="ippipp";function _emscripten_set_mousemove_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,8,"mousemove",targetThread)}Module["_emscripten_set_mousemove_callback_on_thread"]=_emscripten_set_mousemove_callback_on_thread;_emscripten_set_mousemove_callback_on_thread.sig="ippipp";function _emscripten_set_mouseenter_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,33,"mouseenter",targetThread)}Module["_emscripten_set_mouseenter_callback_on_thread"]=_emscripten_set_mouseenter_callback_on_thread;_emscripten_set_mouseenter_callback_on_thread.sig="ippipp";function _emscripten_set_mouseleave_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,34,"mouseleave",targetThread)}Module["_emscripten_set_mouseleave_callback_on_thread"]=_emscripten_set_mouseleave_callback_on_thread;_emscripten_set_mouseleave_callback_on_thread.sig="ippipp";function _emscripten_set_mouseover_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,35,"mouseover",targetThread)}Module["_emscripten_set_mouseover_callback_on_thread"]=_emscripten_set_mouseover_callback_on_thread;_emscripten_set_mouseover_callback_on_thread.sig="ippipp";function _emscripten_set_mouseout_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,36,"mouseout",targetThread)}Module["_emscripten_set_mouseout_callback_on_thread"]=_emscripten_set_mouseout_callback_on_thread;_emscripten_set_mouseout_callback_on_thread.sig="ippipp";function _emscripten_get_mouse_status(mouseState){mouseState>>>=0;if(!JSEvents.mouseEvent)return-7;HEAP8.set(HEAP8.subarray(JSEvents.mouseEvent>>>0,JSEvents.mouseEvent+72>>>0),mouseState>>>0);return 0}Module["_emscripten_get_mouse_status"]=_emscripten_get_mouse_status;_emscripten_get_mouse_status.sig="ip";var registerWheelEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.wheelEvent)JSEvents.wheelEvent=_malloc(104);var wheelHandlerFunc=(e=event)=>{var wheelEvent=JSEvents.wheelEvent;fillMouseEventData(wheelEvent,e,target);HEAPF64[wheelEvent+72>>>3>>>0]=e["deltaX"];HEAPF64[wheelEvent+80>>>3>>>0]=e["deltaY"];HEAPF64[wheelEvent+88>>>3>>>0]=e["deltaZ"];HEAP32[wheelEvent+96>>>2>>>0]=e["deltaMode"];if(getWasmTableEntry(callbackfunc)(eventTypeId,wheelEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:true,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:wheelHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerWheelEventCallback"]=registerWheelEventCallback;function _emscripten_set_wheel_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;target=findEventTarget(target);if(!target)return-4;if(typeof target.onwheel!="undefined"){return registerWheelEventCallback(target,userData,useCapture,callbackfunc,9,"wheel",targetThread)}else{return-1}}Module["_emscripten_set_wheel_callback_on_thread"]=_emscripten_set_wheel_callback_on_thread;_emscripten_set_wheel_callback_on_thread.sig="ippipp";var registerUiEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.uiEvent)JSEvents.uiEvent=_malloc(36);target=findEventTarget(target);var uiEventHandlerFunc=(e=event)=>{if(e.target!=target){return}var b=document.body;if(!b){return}var uiEvent=JSEvents.uiEvent;HEAP32[uiEvent>>>2>>>0]=0;HEAP32[uiEvent+4>>>2>>>0]=b.clientWidth;HEAP32[uiEvent+8>>>2>>>0]=b.clientHeight;HEAP32[uiEvent+12>>>2>>>0]=innerWidth;HEAP32[uiEvent+16>>>2>>>0]=innerHeight;HEAP32[uiEvent+20>>>2>>>0]=outerWidth;HEAP32[uiEvent+24>>>2>>>0]=outerHeight;HEAP32[uiEvent+28>>>2>>>0]=pageXOffset|0;HEAP32[uiEvent+32>>>2>>>0]=pageYOffset|0;if(getWasmTableEntry(callbackfunc)(eventTypeId,uiEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:uiEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerUiEventCallback"]=registerUiEventCallback;function _emscripten_set_resize_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerUiEventCallback(target,userData,useCapture,callbackfunc,10,"resize",targetThread)}Module["_emscripten_set_resize_callback_on_thread"]=_emscripten_set_resize_callback_on_thread;_emscripten_set_resize_callback_on_thread.sig="ippipp";function _emscripten_set_scroll_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerUiEventCallback(target,userData,useCapture,callbackfunc,11,"scroll",targetThread)}Module["_emscripten_set_scroll_callback_on_thread"]=_emscripten_set_scroll_callback_on_thread;_emscripten_set_scroll_callback_on_thread.sig="ippipp";var registerFocusEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.focusEvent)JSEvents.focusEvent=_malloc(256);var focusEventHandlerFunc=(e=event)=>{var nodeName=JSEvents.getNodeNameForTarget(e.target);var id=e.target.id?e.target.id:"";var focusEvent=JSEvents.focusEvent;stringToUTF8(nodeName,focusEvent+0,128);stringToUTF8(id,focusEvent+128,128);if(getWasmTableEntry(callbackfunc)(eventTypeId,focusEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:focusEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerFocusEventCallback"]=registerFocusEventCallback;function _emscripten_set_blur_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerFocusEventCallback(target,userData,useCapture,callbackfunc,12,"blur",targetThread)}Module["_emscripten_set_blur_callback_on_thread"]=_emscripten_set_blur_callback_on_thread;_emscripten_set_blur_callback_on_thread.sig="ippipp";function _emscripten_set_focus_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerFocusEventCallback(target,userData,useCapture,callbackfunc,13,"focus",targetThread)}Module["_emscripten_set_focus_callback_on_thread"]=_emscripten_set_focus_callback_on_thread;_emscripten_set_focus_callback_on_thread.sig="ippipp";function _emscripten_set_focusin_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerFocusEventCallback(target,userData,useCapture,callbackfunc,14,"focusin",targetThread)}Module["_emscripten_set_focusin_callback_on_thread"]=_emscripten_set_focusin_callback_on_thread;_emscripten_set_focusin_callback_on_thread.sig="ippipp";function _emscripten_set_focusout_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerFocusEventCallback(target,userData,useCapture,callbackfunc,15,"focusout",targetThread)}Module["_emscripten_set_focusout_callback_on_thread"]=_emscripten_set_focusout_callback_on_thread;_emscripten_set_focusout_callback_on_thread.sig="ippipp";var fillDeviceOrientationEventData=(eventStruct,e,target)=>{HEAPF64[eventStruct>>>3>>>0]=e.alpha;HEAPF64[eventStruct+8>>>3>>>0]=e.beta;HEAPF64[eventStruct+16>>>3>>>0]=e.gamma;HEAP32[eventStruct+24>>>2>>>0]=e.absolute};Module["fillDeviceOrientationEventData"]=fillDeviceOrientationEventData;var registerDeviceOrientationEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.deviceOrientationEvent)JSEvents.deviceOrientationEvent=_malloc(32);var deviceOrientationEventHandlerFunc=(e=event)=>{fillDeviceOrientationEventData(JSEvents.deviceOrientationEvent,e,target);if(getWasmTableEntry(callbackfunc)(eventTypeId,JSEvents.deviceOrientationEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:deviceOrientationEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerDeviceOrientationEventCallback"]=registerDeviceOrientationEventCallback;function _emscripten_set_deviceorientation_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerDeviceOrientationEventCallback(2,userData,useCapture,callbackfunc,16,"deviceorientation",targetThread)}Module["_emscripten_set_deviceorientation_callback_on_thread"]=_emscripten_set_deviceorientation_callback_on_thread;_emscripten_set_deviceorientation_callback_on_thread.sig="ipipp";function _emscripten_get_deviceorientation_status(orientationState){orientationState>>>=0;if(!JSEvents.deviceOrientationEvent)return-7;HEAP32.set(HEAP32.subarray(JSEvents.deviceOrientationEvent>>>0,32>>>0),orientationState>>>0);return 0}Module["_emscripten_get_deviceorientation_status"]=_emscripten_get_deviceorientation_status;_emscripten_get_deviceorientation_status.sig="ip";var fillDeviceMotionEventData=(eventStruct,e,target)=>{var supportedFields=0;var a=e["acceleration"];supportedFields|=a&&1;var ag=e["accelerationIncludingGravity"];supportedFields|=ag&&2;var rr=e["rotationRate"];supportedFields|=rr&&4;a=a||{};ag=ag||{};rr=rr||{};HEAPF64[eventStruct>>>3>>>0]=a["x"];HEAPF64[eventStruct+8>>>3>>>0]=a["y"];HEAPF64[eventStruct+16>>>3>>>0]=a["z"];HEAPF64[eventStruct+24>>>3>>>0]=ag["x"];HEAPF64[eventStruct+32>>>3>>>0]=ag["y"];HEAPF64[eventStruct+40>>>3>>>0]=ag["z"];HEAPF64[eventStruct+48>>>3>>>0]=rr["alpha"];HEAPF64[eventStruct+56>>>3>>>0]=rr["beta"];HEAPF64[eventStruct+64>>>3>>>0]=rr["gamma"]};Module["fillDeviceMotionEventData"]=fillDeviceMotionEventData;var registerDeviceMotionEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.deviceMotionEvent)JSEvents.deviceMotionEvent=_malloc(80);var deviceMotionEventHandlerFunc=(e=event)=>{fillDeviceMotionEventData(JSEvents.deviceMotionEvent,e,target);if(getWasmTableEntry(callbackfunc)(eventTypeId,JSEvents.deviceMotionEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:deviceMotionEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerDeviceMotionEventCallback"]=registerDeviceMotionEventCallback;function _emscripten_set_devicemotion_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerDeviceMotionEventCallback(2,userData,useCapture,callbackfunc,17,"devicemotion",targetThread)}Module["_emscripten_set_devicemotion_callback_on_thread"]=_emscripten_set_devicemotion_callback_on_thread;_emscripten_set_devicemotion_callback_on_thread.sig="ipipp";function _emscripten_get_devicemotion_status(motionState){motionState>>>=0;if(!JSEvents.deviceMotionEvent)return-7;HEAP32.set(HEAP32.subarray(JSEvents.deviceMotionEvent>>>0,80>>>0),motionState>>>0);return 0}Module["_emscripten_get_devicemotion_status"]=_emscripten_get_devicemotion_status;_emscripten_get_devicemotion_status.sig="ip";var screenOrientation=()=>{if(!window.screen)return undefined;return screen.orientation||screen["mozOrientation"]||screen["webkitOrientation"]};Module["screenOrientation"]=screenOrientation;var fillOrientationChangeEventData=eventStruct=>{var orientationsType1=["portrait-primary","portrait-secondary","landscape-primary","landscape-secondary"];var orientationsType2=["portrait","portrait","landscape","landscape"];var orientationIndex=0;var orientationAngle=0;var screenOrientObj=screenOrientation();if(typeof screenOrientObj==="object"){orientationIndex=orientationsType1.indexOf(screenOrientObj.type);if(orientationIndex<0){orientationIndex=orientationsType2.indexOf(screenOrientObj.type)}if(orientationIndex>=0){orientationIndex=1<>>2>>>0]=orientationIndex;HEAP32[eventStruct+4>>>2>>>0]=orientationAngle};Module["fillOrientationChangeEventData"]=fillOrientationChangeEventData;var registerOrientationChangeEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.orientationChangeEvent)JSEvents.orientationChangeEvent=_malloc(8);var orientationChangeEventHandlerFunc=(e=event)=>{var orientationChangeEvent=JSEvents.orientationChangeEvent;fillOrientationChangeEventData(orientationChangeEvent);if(getWasmTableEntry(callbackfunc)(eventTypeId,orientationChangeEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:orientationChangeEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerOrientationChangeEventCallback"]=registerOrientationChangeEventCallback;function _emscripten_set_orientationchange_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!window.screen||!screen.orientation)return-1;return registerOrientationChangeEventCallback(screen.orientation,userData,useCapture,callbackfunc,18,"change",targetThread)}Module["_emscripten_set_orientationchange_callback_on_thread"]=_emscripten_set_orientationchange_callback_on_thread;_emscripten_set_orientationchange_callback_on_thread.sig="ipipp";function _emscripten_get_orientation_status(orientationChangeEvent){orientationChangeEvent>>>=0;if(!screenOrientation()&&typeof orientation=="undefined")return-1;fillOrientationChangeEventData(orientationChangeEvent);return 0}Module["_emscripten_get_orientation_status"]=_emscripten_get_orientation_status;_emscripten_get_orientation_status.sig="ip";var _emscripten_lock_orientation=allowedOrientations=>{var orientations=[];if(allowedOrientations&1)orientations.push("portrait-primary");if(allowedOrientations&2)orientations.push("portrait-secondary");if(allowedOrientations&4)orientations.push("landscape-primary");if(allowedOrientations&8)orientations.push("landscape-secondary");var succeeded;if(screen.lockOrientation){succeeded=screen.lockOrientation(orientations)}else if(screen.mozLockOrientation){succeeded=screen.mozLockOrientation(orientations)}else if(screen.webkitLockOrientation){succeeded=screen.webkitLockOrientation(orientations)}else{return-1}if(succeeded){return 0}return-6};Module["_emscripten_lock_orientation"]=_emscripten_lock_orientation;_emscripten_lock_orientation.sig="ii";var _emscripten_unlock_orientation=()=>{if(screen.unlockOrientation){screen.unlockOrientation()}else if(screen.mozUnlockOrientation){screen.mozUnlockOrientation()}else if(screen.webkitUnlockOrientation){screen.webkitUnlockOrientation()}else{return-1}return 0};Module["_emscripten_unlock_orientation"]=_emscripten_unlock_orientation;_emscripten_unlock_orientation.sig="i";var fillFullscreenChangeEventData=eventStruct=>{var fullscreenElement=document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement;var isFullscreen=!!fullscreenElement;HEAP32[eventStruct>>>2>>>0]=isFullscreen;HEAP32[eventStruct+4>>>2>>>0]=JSEvents.fullscreenEnabled();var reportedElement=isFullscreen?fullscreenElement:JSEvents.previousFullscreenElement;var nodeName=JSEvents.getNodeNameForTarget(reportedElement);var id=reportedElement?.id||"";stringToUTF8(nodeName,eventStruct+8,128);stringToUTF8(id,eventStruct+136,128);HEAP32[eventStruct+264>>>2>>>0]=reportedElement?reportedElement.clientWidth:0;HEAP32[eventStruct+268>>>2>>>0]=reportedElement?reportedElement.clientHeight:0;HEAP32[eventStruct+272>>>2>>>0]=screen.width;HEAP32[eventStruct+276>>>2>>>0]=screen.height;if(isFullscreen){JSEvents.previousFullscreenElement=fullscreenElement}};Module["fillFullscreenChangeEventData"]=fillFullscreenChangeEventData;var registerFullscreenChangeEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.fullscreenChangeEvent)JSEvents.fullscreenChangeEvent=_malloc(280);var fullscreenChangeEventhandlerFunc=(e=event)=>{var fullscreenChangeEvent=JSEvents.fullscreenChangeEvent;fillFullscreenChangeEventData(fullscreenChangeEvent);if(getWasmTableEntry(callbackfunc)(eventTypeId,fullscreenChangeEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:fullscreenChangeEventhandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerFullscreenChangeEventCallback"]=registerFullscreenChangeEventCallback;function _emscripten_set_fullscreenchange_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!JSEvents.fullscreenEnabled())return-1;target=findEventTarget(target);if(!target)return-4;registerFullscreenChangeEventCallback(target,userData,useCapture,callbackfunc,19,"webkitfullscreenchange",targetThread);return registerFullscreenChangeEventCallback(target,userData,useCapture,callbackfunc,19,"fullscreenchange",targetThread)}Module["_emscripten_set_fullscreenchange_callback_on_thread"]=_emscripten_set_fullscreenchange_callback_on_thread;_emscripten_set_fullscreenchange_callback_on_thread.sig="ippipp";function _emscripten_get_fullscreen_status(fullscreenStatus){fullscreenStatus>>>=0;if(!JSEvents.fullscreenEnabled())return-1;fillFullscreenChangeEventData(fullscreenStatus);return 0}Module["_emscripten_get_fullscreen_status"]=_emscripten_get_fullscreen_status;_emscripten_get_fullscreen_status.sig="ip";function _emscripten_get_canvas_element_size(target,width,height){target>>>=0;width>>>=0;height>>>=0;var canvas=findCanvasEventTarget(target);if(!canvas)return-4;HEAP32[width>>>2>>>0]=canvas.width;HEAP32[height>>>2>>>0]=canvas.height}Module["_emscripten_get_canvas_element_size"]=_emscripten_get_canvas_element_size;_emscripten_get_canvas_element_size.sig="ippp";var getCanvasElementSize=target=>{var sp=stackSave();var w=stackAlloc(8);var h=w+4;var targetInt=stringToUTF8OnStack(target.id);var ret=_emscripten_get_canvas_element_size(targetInt,w,h);var size=[HEAP32[w>>>2>>>0],HEAP32[h>>>2>>>0]];stackRestore(sp);return size};Module["getCanvasElementSize"]=getCanvasElementSize;function _emscripten_set_canvas_element_size(target,width,height){target>>>=0;var canvas=findCanvasEventTarget(target);if(!canvas)return-4;canvas.width=width;canvas.height=height;return 0}Module["_emscripten_set_canvas_element_size"]=_emscripten_set_canvas_element_size;_emscripten_set_canvas_element_size.sig="ipii";var setCanvasElementSize=(target,width,height)=>{if(!target.controlTransferredOffscreen){target.width=width;target.height=height}else{var sp=stackSave();var targetInt=stringToUTF8OnStack(target.id);_emscripten_set_canvas_element_size(targetInt,width,height);stackRestore(sp)}};Module["setCanvasElementSize"]=setCanvasElementSize;var registerRestoreOldStyle=canvas=>{var canvasSize=getCanvasElementSize(canvas);var oldWidth=canvasSize[0];var oldHeight=canvasSize[1];var oldCssWidth=canvas.style.width;var oldCssHeight=canvas.style.height;var oldBackgroundColor=canvas.style.backgroundColor;var oldDocumentBackgroundColor=document.body.style.backgroundColor;var oldPaddingLeft=canvas.style.paddingLeft;var oldPaddingRight=canvas.style.paddingRight;var oldPaddingTop=canvas.style.paddingTop;var oldPaddingBottom=canvas.style.paddingBottom;var oldMarginLeft=canvas.style.marginLeft;var oldMarginRight=canvas.style.marginRight;var oldMarginTop=canvas.style.marginTop;var oldMarginBottom=canvas.style.marginBottom;var oldDocumentBodyMargin=document.body.style.margin;var oldDocumentOverflow=document.documentElement.style.overflow;var oldDocumentScroll=document.body.scroll;var oldImageRendering=canvas.style.imageRendering;function restoreOldStyle(){var fullscreenElement=document.fullscreenElement||document.webkitFullscreenElement;if(!fullscreenElement){document.removeEventListener("fullscreenchange",restoreOldStyle);document.removeEventListener("webkitfullscreenchange",restoreOldStyle);setCanvasElementSize(canvas,oldWidth,oldHeight);canvas.style.width=oldCssWidth;canvas.style.height=oldCssHeight;canvas.style.backgroundColor=oldBackgroundColor;if(!oldDocumentBackgroundColor)document.body.style.backgroundColor="white";document.body.style.backgroundColor=oldDocumentBackgroundColor;canvas.style.paddingLeft=oldPaddingLeft;canvas.style.paddingRight=oldPaddingRight;canvas.style.paddingTop=oldPaddingTop;canvas.style.paddingBottom=oldPaddingBottom;canvas.style.marginLeft=oldMarginLeft;canvas.style.marginRight=oldMarginRight;canvas.style.marginTop=oldMarginTop;canvas.style.marginBottom=oldMarginBottom;document.body.style.margin=oldDocumentBodyMargin;document.documentElement.style.overflow=oldDocumentOverflow;document.body.scroll=oldDocumentScroll;canvas.style.imageRendering=oldImageRendering;if(canvas.GLctxObject)canvas.GLctxObject.GLctx.viewport(0,0,oldWidth,oldHeight);if(currentFullscreenStrategy.canvasResizedCallback){getWasmTableEntry(currentFullscreenStrategy.canvasResizedCallback)(37,0,currentFullscreenStrategy.canvasResizedCallbackUserData)}}}document.addEventListener("fullscreenchange",restoreOldStyle);document.addEventListener("webkitfullscreenchange",restoreOldStyle);return restoreOldStyle};Module["registerRestoreOldStyle"]=registerRestoreOldStyle;var setLetterbox=(element,topBottom,leftRight)=>{element.style.paddingLeft=element.style.paddingRight=leftRight+"px";element.style.paddingTop=element.style.paddingBottom=topBottom+"px"};Module["setLetterbox"]=setLetterbox;var JSEvents_resizeCanvasForFullscreen=(target,strategy)=>{var restoreOldStyle=registerRestoreOldStyle(target);var cssWidth=strategy.softFullscreen?innerWidth:screen.width;var cssHeight=strategy.softFullscreen?innerHeight:screen.height;var rect=getBoundingClientRect(target);var windowedCssWidth=rect.width;var windowedCssHeight=rect.height;var canvasSize=getCanvasElementSize(target);var windowedRttWidth=canvasSize[0];var windowedRttHeight=canvasSize[1];if(strategy.scaleMode==3){setLetterbox(target,(cssHeight-windowedCssHeight)/2,(cssWidth-windowedCssWidth)/2);cssWidth=windowedCssWidth;cssHeight=windowedCssHeight}else if(strategy.scaleMode==2){if(cssWidth*windowedRttHeight{if(strategy.scaleMode!=0||strategy.canvasResolutionScaleMode!=0){JSEvents_resizeCanvasForFullscreen(target,strategy)}if(target.requestFullscreen){target.requestFullscreen()}else if(target.webkitRequestFullscreen){target.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}else{return JSEvents.fullscreenEnabled()?-3:-1}currentFullscreenStrategy=strategy;if(strategy.canvasResizedCallback){getWasmTableEntry(strategy.canvasResizedCallback)(37,0,strategy.canvasResizedCallbackUserData)}return 0};Module["JSEvents_requestFullscreen"]=JSEvents_requestFullscreen;var hideEverythingExceptGivenElement=onlyVisibleElement=>{var child=onlyVisibleElement;var parent=child.parentNode;var hiddenElements=[];while(child!=document.body){var children=parent.children;for(var i=0;i{for(var i=0;i{var dpr=devicePixelRatio;var inHiDPIFullscreenMode=currentFullscreenStrategy.canvasResolutionScaleMode==2;var inAspectRatioFixedFullscreenMode=currentFullscreenStrategy.scaleMode==2;var inPixelPerfectFullscreenMode=currentFullscreenStrategy.canvasResolutionScaleMode!=0;var inCenteredWithoutScalingFullscreenMode=currentFullscreenStrategy.scaleMode==3;var screenWidth=inHiDPIFullscreenMode?Math.round(innerWidth*dpr):innerWidth;var screenHeight=inHiDPIFullscreenMode?Math.round(innerHeight*dpr):innerHeight;var w=screenWidth;var h=screenHeight;var canvas=currentFullscreenStrategy.target;var canvasSize=getCanvasElementSize(canvas);var x=canvasSize[0];var y=canvasSize[1];var topMargin;if(inAspectRatioFixedFullscreenMode){if(w*yx*h)w=h*x/y|0;topMargin=(screenHeight-h)/2|0}if(inPixelPerfectFullscreenMode){setCanvasElementSize(canvas,w,h);if(canvas.GLctxObject)canvas.GLctxObject.GLctx.viewport(0,0,w,h)}if(inHiDPIFullscreenMode){topMargin/=dpr;w/=dpr;h/=dpr;w=Math.round(w*1e4)/1e4;h=Math.round(h*1e4)/1e4;topMargin=Math.round(topMargin*1e4)/1e4}if(inCenteredWithoutScalingFullscreenMode){var t=(innerHeight-jstoi_q(canvas.style.height))/2;var b=(innerWidth-jstoi_q(canvas.style.width))/2;setLetterbox(canvas,t,b)}else{canvas.style.width=w+"px";canvas.style.height=h+"px";var b=(innerWidth-w)/2;setLetterbox(canvas,topMargin,b)}if(!inCenteredWithoutScalingFullscreenMode&¤tFullscreenStrategy.canvasResizedCallback){getWasmTableEntry(currentFullscreenStrategy.canvasResizedCallback)(37,0,currentFullscreenStrategy.canvasResizedCallbackUserData)}};Module["softFullscreenResizeWebGLRenderTarget"]=softFullscreenResizeWebGLRenderTarget;var doRequestFullscreen=(target,strategy)=>{if(!JSEvents.fullscreenEnabled())return-1;target=findEventTarget(target);if(!target)return-4;if(!target.requestFullscreen&&!target.webkitRequestFullscreen){return-3}var canPerformRequests=JSEvents.canPerformEventHandlerRequests();if(!canPerformRequests){if(strategy.deferUntilInEventHandler){JSEvents.deferCall(JSEvents_requestFullscreen,1,[target,strategy]);return 1}return-2}return JSEvents_requestFullscreen(target,strategy)};Module["doRequestFullscreen"]=doRequestFullscreen;function _emscripten_request_fullscreen(target,deferUntilInEventHandler){target>>>=0;var strategy={scaleMode:0,canvasResolutionScaleMode:0,filteringMode:0,deferUntilInEventHandler:deferUntilInEventHandler,canvasResizedCallbackTargetThread:2};return doRequestFullscreen(target,strategy)}Module["_emscripten_request_fullscreen"]=_emscripten_request_fullscreen;_emscripten_request_fullscreen.sig="ipi";function _emscripten_request_fullscreen_strategy(target,deferUntilInEventHandler,fullscreenStrategy){target>>>=0;fullscreenStrategy>>>=0;var strategy={scaleMode:HEAP32[fullscreenStrategy>>>2>>>0],canvasResolutionScaleMode:HEAP32[fullscreenStrategy+4>>>2>>>0],filteringMode:HEAP32[fullscreenStrategy+8>>>2>>>0],deferUntilInEventHandler:deferUntilInEventHandler,canvasResizedCallback:HEAP32[fullscreenStrategy+12>>>2>>>0],canvasResizedCallbackUserData:HEAP32[fullscreenStrategy+16>>>2>>>0]};return doRequestFullscreen(target,strategy)}Module["_emscripten_request_fullscreen_strategy"]=_emscripten_request_fullscreen_strategy;_emscripten_request_fullscreen_strategy.sig="ipip";function _emscripten_enter_soft_fullscreen(target,fullscreenStrategy){target>>>=0;fullscreenStrategy>>>=0;target=findEventTarget(target);if(!target)return-4;var strategy={scaleMode:HEAP32[fullscreenStrategy>>>2>>>0],canvasResolutionScaleMode:HEAP32[fullscreenStrategy+4>>>2>>>0],filteringMode:HEAP32[fullscreenStrategy+8>>>2>>>0],canvasResizedCallback:HEAP32[fullscreenStrategy+12>>>2>>>0],canvasResizedCallbackUserData:HEAP32[fullscreenStrategy+16>>>2>>>0],target:target,softFullscreen:true};var restoreOldStyle=JSEvents_resizeCanvasForFullscreen(target,strategy);document.documentElement.style.overflow="hidden";document.body.scroll="no";document.body.style.margin="0px";var hiddenElements=hideEverythingExceptGivenElement(target);function restoreWindowedState(){restoreOldStyle();restoreHiddenElements(hiddenElements);removeEventListener("resize",softFullscreenResizeWebGLRenderTarget);if(strategy.canvasResizedCallback){getWasmTableEntry(strategy.canvasResizedCallback)(37,0,strategy.canvasResizedCallbackUserData)}currentFullscreenStrategy=0}restoreOldWindowedStyle=restoreWindowedState;currentFullscreenStrategy=strategy;addEventListener("resize",softFullscreenResizeWebGLRenderTarget);if(strategy.canvasResizedCallback){getWasmTableEntry(strategy.canvasResizedCallback)(37,0,strategy.canvasResizedCallbackUserData)}return 0}Module["_emscripten_enter_soft_fullscreen"]=_emscripten_enter_soft_fullscreen;_emscripten_enter_soft_fullscreen.sig="ipp";var _emscripten_exit_soft_fullscreen=()=>{restoreOldWindowedStyle?.();restoreOldWindowedStyle=null;return 0};Module["_emscripten_exit_soft_fullscreen"]=_emscripten_exit_soft_fullscreen;_emscripten_exit_soft_fullscreen.sig="i";var _emscripten_exit_fullscreen=()=>{if(!JSEvents.fullscreenEnabled())return-1;JSEvents.removeDeferredCalls(JSEvents_requestFullscreen);var d=specialHTMLTargets[1];if(d.exitFullscreen){d.fullscreenElement&&d.exitFullscreen()}else if(d.webkitExitFullscreen){d.webkitFullscreenElement&&d.webkitExitFullscreen()}else{return-1}return 0};Module["_emscripten_exit_fullscreen"]=_emscripten_exit_fullscreen;_emscripten_exit_fullscreen.sig="i";var fillPointerlockChangeEventData=eventStruct=>{var pointerLockElement=document.pointerLockElement||document.mozPointerLockElement||document.webkitPointerLockElement||document.msPointerLockElement;var isPointerlocked=!!pointerLockElement;HEAP32[eventStruct>>>2>>>0]=isPointerlocked;var nodeName=JSEvents.getNodeNameForTarget(pointerLockElement);var id=pointerLockElement?.id||"";stringToUTF8(nodeName,eventStruct+4,128);stringToUTF8(id,eventStruct+132,128)};Module["fillPointerlockChangeEventData"]=fillPointerlockChangeEventData;var registerPointerlockChangeEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.pointerlockChangeEvent)JSEvents.pointerlockChangeEvent=_malloc(260);var pointerlockChangeEventHandlerFunc=(e=event)=>{var pointerlockChangeEvent=JSEvents.pointerlockChangeEvent;fillPointerlockChangeEventData(pointerlockChangeEvent);if(getWasmTableEntry(callbackfunc)(eventTypeId,pointerlockChangeEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:pointerlockChangeEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerPointerlockChangeEventCallback"]=registerPointerlockChangeEventCallback;function _emscripten_set_pointerlockchange_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!document||!document.body||!document.body.requestPointerLock&&!document.body.mozRequestPointerLock&&!document.body.webkitRequestPointerLock&&!document.body.msRequestPointerLock){return-1}target=findEventTarget(target);if(!target)return-4;registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,20,"mozpointerlockchange",targetThread);registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,20,"webkitpointerlockchange",targetThread);registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,20,"mspointerlockchange",targetThread);return registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,20,"pointerlockchange",targetThread)}Module["_emscripten_set_pointerlockchange_callback_on_thread"]=_emscripten_set_pointerlockchange_callback_on_thread;_emscripten_set_pointerlockchange_callback_on_thread.sig="ippipp";var registerPointerlockErrorEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{var pointerlockErrorEventHandlerFunc=(e=event)=>{if(getWasmTableEntry(callbackfunc)(eventTypeId,0,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:pointerlockErrorEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerPointerlockErrorEventCallback"]=registerPointerlockErrorEventCallback;function _emscripten_set_pointerlockerror_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!document||!document.body.requestPointerLock&&!document.body.mozRequestPointerLock&&!document.body.webkitRequestPointerLock&&!document.body.msRequestPointerLock){return-1}target=findEventTarget(target);if(!target)return-4;registerPointerlockErrorEventCallback(target,userData,useCapture,callbackfunc,38,"mozpointerlockerror",targetThread);registerPointerlockErrorEventCallback(target,userData,useCapture,callbackfunc,38,"webkitpointerlockerror",targetThread);registerPointerlockErrorEventCallback(target,userData,useCapture,callbackfunc,38,"mspointerlockerror",targetThread);return registerPointerlockErrorEventCallback(target,userData,useCapture,callbackfunc,38,"pointerlockerror",targetThread)}Module["_emscripten_set_pointerlockerror_callback_on_thread"]=_emscripten_set_pointerlockerror_callback_on_thread;_emscripten_set_pointerlockerror_callback_on_thread.sig="ippipp";function _emscripten_get_pointerlock_status(pointerlockStatus){pointerlockStatus>>>=0;if(pointerlockStatus)fillPointerlockChangeEventData(pointerlockStatus);if(!document.body||!document.body.requestPointerLock&&!document.body.mozRequestPointerLock&&!document.body.webkitRequestPointerLock&&!document.body.msRequestPointerLock){return-1}return 0}Module["_emscripten_get_pointerlock_status"]=_emscripten_get_pointerlock_status;_emscripten_get_pointerlock_status.sig="ip";var requestPointerLock=target=>{if(target.requestPointerLock){target.requestPointerLock()}else{if(document.body.requestPointerLock){return-3}return-1}return 0};Module["requestPointerLock"]=requestPointerLock;function _emscripten_request_pointerlock(target,deferUntilInEventHandler){target>>>=0;target=findEventTarget(target);if(!target)return-4;if(!target.requestPointerLock){return-1}var canPerformRequests=JSEvents.canPerformEventHandlerRequests();if(!canPerformRequests){if(deferUntilInEventHandler){JSEvents.deferCall(requestPointerLock,2,[target]);return 1}return-2}return requestPointerLock(target)}Module["_emscripten_request_pointerlock"]=_emscripten_request_pointerlock;_emscripten_request_pointerlock.sig="ipi";var _emscripten_exit_pointerlock=()=>{JSEvents.removeDeferredCalls(requestPointerLock);if(document.exitPointerLock){document.exitPointerLock()}else{return-1}return 0};Module["_emscripten_exit_pointerlock"]=_emscripten_exit_pointerlock;_emscripten_exit_pointerlock.sig="i";var _emscripten_vibrate=msecs=>{if(!navigator.vibrate)return-1;navigator.vibrate(msecs);return 0};Module["_emscripten_vibrate"]=_emscripten_vibrate;_emscripten_vibrate.sig="ii";function _emscripten_vibrate_pattern(msecsArray,numEntries){msecsArray>>>=0;if(!navigator.vibrate)return-1;var vibrateList=[];for(var i=0;i>>2>>>0];vibrateList.push(msecs)}navigator.vibrate(vibrateList);return 0}Module["_emscripten_vibrate_pattern"]=_emscripten_vibrate_pattern;_emscripten_vibrate_pattern.sig="ipi";var fillVisibilityChangeEventData=eventStruct=>{var visibilityStates=["hidden","visible","prerender","unloaded"];var visibilityState=visibilityStates.indexOf(document.visibilityState);HEAP32[eventStruct>>>2>>>0]=document.hidden;HEAP32[eventStruct+4>>>2>>>0]=visibilityState};Module["fillVisibilityChangeEventData"]=fillVisibilityChangeEventData;var registerVisibilityChangeEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.visibilityChangeEvent)JSEvents.visibilityChangeEvent=_malloc(8);var visibilityChangeEventHandlerFunc=(e=event)=>{var visibilityChangeEvent=JSEvents.visibilityChangeEvent;fillVisibilityChangeEventData(visibilityChangeEvent);if(getWasmTableEntry(callbackfunc)(eventTypeId,visibilityChangeEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:visibilityChangeEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerVisibilityChangeEventCallback"]=registerVisibilityChangeEventCallback;function _emscripten_set_visibilitychange_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!specialHTMLTargets[1]){return-4}return registerVisibilityChangeEventCallback(specialHTMLTargets[1],userData,useCapture,callbackfunc,21,"visibilitychange",targetThread)}Module["_emscripten_set_visibilitychange_callback_on_thread"]=_emscripten_set_visibilitychange_callback_on_thread;_emscripten_set_visibilitychange_callback_on_thread.sig="ipipp";function _emscripten_get_visibility_status(visibilityStatus){visibilityStatus>>>=0;if(typeof document.visibilityState=="undefined"&&typeof document.hidden=="undefined"){return-1}fillVisibilityChangeEventData(visibilityStatus);return 0}Module["_emscripten_get_visibility_status"]=_emscripten_get_visibility_status;_emscripten_get_visibility_status.sig="ip";var registerTouchEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.touchEvent)JSEvents.touchEvent=_malloc(1696);target=findEventTarget(target);var touchEventHandlerFunc=e=>{var t,touches={},et=e.touches;for(var i=0;i>>3>>>0]=e.timeStamp;var idx=touchEvent>>>2;HEAP32[idx+3>>>0]=e.ctrlKey;HEAP32[idx+4>>>0]=e.shiftKey;HEAP32[idx+5>>>0]=e.altKey;HEAP32[idx+6>>>0]=e.metaKey;idx+=7;var targetRect=getBoundingClientRect(target);var numTouches=0;for(var i in touches){t=touches[i];HEAP32[idx+0>>>0]=t.identifier;HEAP32[idx+1>>>0]=t.screenX;HEAP32[idx+2>>>0]=t.screenY;HEAP32[idx+3>>>0]=t.clientX;HEAP32[idx+4>>>0]=t.clientY;HEAP32[idx+5>>>0]=t.pageX;HEAP32[idx+6>>>0]=t.pageY;HEAP32[idx+7>>>0]=t.isChanged;HEAP32[idx+8>>>0]=t.onTarget;HEAP32[idx+9>>>0]=t.clientX-(targetRect.left|0);HEAP32[idx+10>>>0]=t.clientY-(targetRect.top|0);idx+=13;if(++numTouches>31){break}}HEAP32[touchEvent+8>>>2>>>0]=numTouches;if(getWasmTableEntry(callbackfunc)(eventTypeId,touchEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:eventTypeString=="touchstart"||eventTypeString=="touchend",eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:touchEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerTouchEventCallback"]=registerTouchEventCallback;function _emscripten_set_touchstart_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerTouchEventCallback(target,userData,useCapture,callbackfunc,22,"touchstart",targetThread)}Module["_emscripten_set_touchstart_callback_on_thread"]=_emscripten_set_touchstart_callback_on_thread;_emscripten_set_touchstart_callback_on_thread.sig="ippipp";function _emscripten_set_touchend_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerTouchEventCallback(target,userData,useCapture,callbackfunc,23,"touchend",targetThread)}Module["_emscripten_set_touchend_callback_on_thread"]=_emscripten_set_touchend_callback_on_thread;_emscripten_set_touchend_callback_on_thread.sig="ippipp";function _emscripten_set_touchmove_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerTouchEventCallback(target,userData,useCapture,callbackfunc,24,"touchmove",targetThread)}Module["_emscripten_set_touchmove_callback_on_thread"]=_emscripten_set_touchmove_callback_on_thread;_emscripten_set_touchmove_callback_on_thread.sig="ippipp";function _emscripten_set_touchcancel_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerTouchEventCallback(target,userData,useCapture,callbackfunc,25,"touchcancel",targetThread)}Module["_emscripten_set_touchcancel_callback_on_thread"]=_emscripten_set_touchcancel_callback_on_thread;_emscripten_set_touchcancel_callback_on_thread.sig="ippipp";var fillGamepadEventData=(eventStruct,e)=>{HEAPF64[eventStruct>>>3>>>0]=e.timestamp;for(var i=0;i>>3>>>0]=e.axes[i]}for(var i=0;i>>3>>>0]=e.buttons[i].value}else{HEAPF64[eventStruct+i*8+528>>>3>>>0]=e.buttons[i]}}for(var i=0;i>>2>>>0]=e.buttons[i].pressed}else{HEAP32[eventStruct+i*4+1040>>>2>>>0]=e.buttons[i]==1}}HEAP32[eventStruct+1296>>>2>>>0]=e.connected;HEAP32[eventStruct+1300>>>2>>>0]=e.index;HEAP32[eventStruct+8>>>2>>>0]=e.axes.length;HEAP32[eventStruct+12>>>2>>>0]=e.buttons.length;stringToUTF8(e.id,eventStruct+1304,64);stringToUTF8(e.mapping,eventStruct+1368,64)};Module["fillGamepadEventData"]=fillGamepadEventData;var registerGamepadEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.gamepadEvent)JSEvents.gamepadEvent=_malloc(1432);var gamepadEventHandlerFunc=(e=event)=>{var gamepadEvent=JSEvents.gamepadEvent;fillGamepadEventData(gamepadEvent,e["gamepad"]);if(getWasmTableEntry(callbackfunc)(eventTypeId,gamepadEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),allowsDeferredCalls:true,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:gamepadEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerGamepadEventCallback"]=registerGamepadEventCallback;var _emscripten_sample_gamepad_data=()=>{try{if(navigator.getGamepads)return(JSEvents.lastGamepadState=navigator.getGamepads())?0:-1}catch(e){navigator.getGamepads=null}return-1};Module["_emscripten_sample_gamepad_data"]=_emscripten_sample_gamepad_data;_emscripten_sample_gamepad_data.sig="i";function _emscripten_set_gamepadconnected_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(_emscripten_sample_gamepad_data())return-1;return registerGamepadEventCallback(2,userData,useCapture,callbackfunc,26,"gamepadconnected",targetThread)}Module["_emscripten_set_gamepadconnected_callback_on_thread"]=_emscripten_set_gamepadconnected_callback_on_thread;_emscripten_set_gamepadconnected_callback_on_thread.sig="ipipp";function _emscripten_set_gamepaddisconnected_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(_emscripten_sample_gamepad_data())return-1;return registerGamepadEventCallback(2,userData,useCapture,callbackfunc,27,"gamepaddisconnected",targetThread)}Module["_emscripten_set_gamepaddisconnected_callback_on_thread"]=_emscripten_set_gamepaddisconnected_callback_on_thread;_emscripten_set_gamepaddisconnected_callback_on_thread.sig="ipipp";var _emscripten_get_num_gamepads=()=>JSEvents.lastGamepadState.length;Module["_emscripten_get_num_gamepads"]=_emscripten_get_num_gamepads;_emscripten_get_num_gamepads.sig="i";function _emscripten_get_gamepad_status(index,gamepadState){gamepadState>>>=0;if(index<0||index>=JSEvents.lastGamepadState.length)return-5;if(!JSEvents.lastGamepadState[index])return-7;fillGamepadEventData(gamepadState,JSEvents.lastGamepadState[index]);return 0}Module["_emscripten_get_gamepad_status"]=_emscripten_get_gamepad_status;_emscripten_get_gamepad_status.sig="iip";var registerBeforeUnloadEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString)=>{var beforeUnloadEventHandlerFunc=(e=event)=>{var confirmationMessage=getWasmTableEntry(callbackfunc)(eventTypeId,0,userData);if(confirmationMessage){confirmationMessage=UTF8ToString(confirmationMessage)}if(confirmationMessage){e.preventDefault();e.returnValue=confirmationMessage;return confirmationMessage}};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:beforeUnloadEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerBeforeUnloadEventCallback"]=registerBeforeUnloadEventCallback;function _emscripten_set_beforeunload_callback_on_thread(userData,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(typeof onbeforeunload=="undefined")return-1;if(targetThread!==1)return-5;return registerBeforeUnloadEventCallback(2,userData,true,callbackfunc,28,"beforeunload")}Module["_emscripten_set_beforeunload_callback_on_thread"]=_emscripten_set_beforeunload_callback_on_thread;_emscripten_set_beforeunload_callback_on_thread.sig="ippp";var fillBatteryEventData=(eventStruct,e)=>{HEAPF64[eventStruct>>>3>>>0]=e.chargingTime;HEAPF64[eventStruct+8>>>3>>>0]=e.dischargingTime;HEAPF64[eventStruct+16>>>3>>>0]=e.level;HEAP32[eventStruct+24>>>2>>>0]=e.charging};Module["fillBatteryEventData"]=fillBatteryEventData;var battery=()=>navigator.battery||navigator.mozBattery||navigator.webkitBattery;Module["battery"]=battery;var registerBatteryEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.batteryEvent)JSEvents.batteryEvent=_malloc(32);var batteryEventHandlerFunc=(e=event)=>{var batteryEvent=JSEvents.batteryEvent;fillBatteryEventData(batteryEvent,battery());if(getWasmTableEntry(callbackfunc)(eventTypeId,batteryEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:batteryEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerBatteryEventCallback"]=registerBatteryEventCallback;function _emscripten_set_batterychargingchange_callback_on_thread(userData,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!battery())return-1;return registerBatteryEventCallback(battery(),userData,true,callbackfunc,29,"chargingchange",targetThread)}Module["_emscripten_set_batterychargingchange_callback_on_thread"]=_emscripten_set_batterychargingchange_callback_on_thread;_emscripten_set_batterychargingchange_callback_on_thread.sig="ippp";function _emscripten_set_batterylevelchange_callback_on_thread(userData,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!battery())return-1;return registerBatteryEventCallback(battery(),userData,true,callbackfunc,30,"levelchange",targetThread)}Module["_emscripten_set_batterylevelchange_callback_on_thread"]=_emscripten_set_batterylevelchange_callback_on_thread;_emscripten_set_batterylevelchange_callback_on_thread.sig="ippp";function _emscripten_get_battery_status(batteryState){batteryState>>>=0;if(!battery())return-1;fillBatteryEventData(batteryState,battery());return 0}Module["_emscripten_get_battery_status"]=_emscripten_get_battery_status;_emscripten_get_battery_status.sig="ip";function __emscripten_set_offscreencanvas_size(target,width,height){target>>>=0;return-1}Module["__emscripten_set_offscreencanvas_size"]=__emscripten_set_offscreencanvas_size;__emscripten_set_offscreencanvas_size.sig="ipii";function _emscripten_set_element_css_size(target,width,height){target>>>=0;target=findEventTarget(target);if(!target)return-4;target.style.width=width+"px";target.style.height=height+"px";return 0}Module["_emscripten_set_element_css_size"]=_emscripten_set_element_css_size;_emscripten_set_element_css_size.sig="ipdd";function _emscripten_get_element_css_size(target,width,height){target>>>=0;width>>>=0;height>>>=0;target=findEventTarget(target);if(!target)return-4;var rect=getBoundingClientRect(target);HEAPF64[width>>>3>>>0]=rect.width;HEAPF64[height>>>3>>>0]=rect.height;return 0}Module["_emscripten_get_element_css_size"]=_emscripten_get_element_css_size;_emscripten_get_element_css_size.sig="ippp";var _emscripten_html5_remove_all_event_listeners=()=>JSEvents.removeAllEventListeners();Module["_emscripten_html5_remove_all_event_listeners"]=_emscripten_html5_remove_all_event_listeners;_emscripten_html5_remove_all_event_listeners.sig="v";var _emscripten_request_animation_frame=function(cb,userData){cb>>>=0;userData>>>=0;return requestAnimationFrame(timeStamp=>getWasmTableEntry(cb)(timeStamp,userData))};Module["_emscripten_request_animation_frame"]=_emscripten_request_animation_frame;_emscripten_request_animation_frame.sig="ipp";var _emscripten_cancel_animation_frame=id=>cancelAnimationFrame(id);Module["_emscripten_cancel_animation_frame"]=_emscripten_cancel_animation_frame;_emscripten_cancel_animation_frame.sig="vi";function _emscripten_request_animation_frame_loop(cb,userData){cb>>>=0;userData>>>=0;function tick(timeStamp){if(getWasmTableEntry(cb)(timeStamp,userData)){requestAnimationFrame(tick)}}return requestAnimationFrame(tick)}Module["_emscripten_request_animation_frame_loop"]=_emscripten_request_animation_frame_loop;_emscripten_request_animation_frame_loop.sig="vpp";var _emscripten_performance_now=()=>performance.now();Module["_emscripten_performance_now"]=_emscripten_performance_now;_emscripten_performance_now.sig="d";var _emscripten_get_device_pixel_ratio=()=>typeof devicePixelRatio=="number"&&devicePixelRatio||1;Module["_emscripten_get_device_pixel_ratio"]=_emscripten_get_device_pixel_ratio;_emscripten_get_device_pixel_ratio.sig="d";function _emscripten_get_callstack(flags,str,maxbytes){str>>>=0;var callstack=getCallstack(flags);if(!str||maxbytes<=0){return lengthBytesUTF8(callstack)+1}var bytesWrittenExcludingNull=stringToUTF8(callstack,str,maxbytes);return bytesWrittenExcludingNull+1}Module["_emscripten_get_callstack"]=_emscripten_get_callstack;_emscripten_get_callstack.sig="iipi";var convertFrameToPC=frame=>{abort("Cannot use convertFrameToPC (needed by __builtin_return_address) without -sUSE_OFFSET_CONVERTER");return 0};Module["convertFrameToPC"]=convertFrameToPC;function _emscripten_return_address(level){var callstack=jsStackTrace().split("\n");if(callstack[0]=="Error"){callstack.shift()}var caller=callstack[level+3];return convertFrameToPC(caller)}Module["_emscripten_return_address"]=_emscripten_return_address;_emscripten_return_address.sig="pi";var UNWIND_CACHE={};Module["UNWIND_CACHE"]=UNWIND_CACHE;var saveInUnwindCache=callstack=>{callstack.forEach(frame=>{var pc=convertFrameToPC(frame);if(pc){UNWIND_CACHE[pc]=frame}})};Module["saveInUnwindCache"]=saveInUnwindCache;function _emscripten_stack_snapshot(){var callstack=jsStackTrace().split("\n");if(callstack[0]=="Error"){callstack.shift()}saveInUnwindCache(callstack);UNWIND_CACHE.last_addr=convertFrameToPC(callstack[3]);UNWIND_CACHE.last_stack=callstack;return UNWIND_CACHE.last_addr}Module["_emscripten_stack_snapshot"]=_emscripten_stack_snapshot;_emscripten_stack_snapshot.sig="p";function _emscripten_stack_unwind_buffer(addr,buffer,count){addr>>>=0;buffer>>>=0;var stack;if(UNWIND_CACHE.last_addr==addr){stack=UNWIND_CACHE.last_stack}else{stack=jsStackTrace().split("\n");if(stack[0]=="Error"){stack.shift()}saveInUnwindCache(stack)}var offset=3;while(stack[offset]&&convertFrameToPC(stack[offset])!=addr){++offset}for(var i=0;i>>2>>>0]=convertFrameToPC(stack[i+offset])}return i}Module["_emscripten_stack_unwind_buffer"]=_emscripten_stack_unwind_buffer;_emscripten_stack_unwind_buffer.sig="ippi";function _emscripten_pc_get_function(pc){pc>>>=0;abort("Cannot use emscripten_pc_get_function without -sUSE_OFFSET_CONVERTER");return 0}Module["_emscripten_pc_get_function"]=_emscripten_pc_get_function;_emscripten_pc_get_function.sig="pp";var convertPCtoSourceLocation=pc=>{if(UNWIND_CACHE.last_get_source_pc==pc)return UNWIND_CACHE.last_source;var match;var source;if(!source){var frame=UNWIND_CACHE[pc];if(!frame)return null;if(match=/\((.*):(\d+):(\d+)\)$/.exec(frame)){source={file:match[1],line:match[2],column:match[3]}}else if(match=/@(.*):(\d+):(\d+)/.exec(frame)){source={file:match[1],line:match[2],column:match[3]}}}UNWIND_CACHE.last_get_source_pc=pc;UNWIND_CACHE.last_source=source;return source};Module["convertPCtoSourceLocation"]=convertPCtoSourceLocation;function _emscripten_pc_get_file(pc){pc>>>=0;var result=convertPCtoSourceLocation(pc);if(!result)return 0;if(_emscripten_pc_get_file.ret)_free(_emscripten_pc_get_file.ret);_emscripten_pc_get_file.ret=stringToNewUTF8(result.file);return _emscripten_pc_get_file.ret}Module["_emscripten_pc_get_file"]=_emscripten_pc_get_file;_emscripten_pc_get_file.sig="pp";function _emscripten_pc_get_line(pc){pc>>>=0;var result=convertPCtoSourceLocation(pc);return result?result.line:0}Module["_emscripten_pc_get_line"]=_emscripten_pc_get_line;_emscripten_pc_get_line.sig="ip";function _emscripten_pc_get_column(pc){pc>>>=0;var result=convertPCtoSourceLocation(pc);return result?result.column||0:0}Module["_emscripten_pc_get_column"]=_emscripten_pc_get_column;_emscripten_pc_get_column.sig="ip";function _random_get(buf,buf_len){buf>>>=0;buf_len>>>=0;try{_getentropy(buf,buf_len);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_random_get"]=_random_get;_random_get.sig="ipp";var checkWasiClock=clock_id=>clock_id==0||clock_id==1||clock_id==2||clock_id==3;Module["checkWasiClock"]=checkWasiClock;function _clock_time_get(clk_id,ignored_precision,ptime){ignored_precision=bigintToI53Checked(ignored_precision);ptime>>>=0;if(!checkWasiClock(clk_id)){return 28}var now;if(clk_id===0){now=Date.now()}else if(nowIsMonotonic){now=_emscripten_get_now()}else{return 52}var nsec=Math.round(now*1e3*1e3);HEAP32[ptime>>>2>>>0]=nsec>>>0;HEAP32[ptime+4>>>2>>>0]=nsec/Math.pow(2,32)>>>0;return 0}Module["_clock_time_get"]=_clock_time_get;_clock_time_get.sig="iijp";function _clock_res_get(clk_id,pres){pres>>>=0;if(!checkWasiClock(clk_id)){return 28}var nsec;if(clk_id===0){nsec=1e3*1e3}else if(nowIsMonotonic){nsec=_emscripten_get_now_res()}else{return 52}HEAP32[pres>>>2>>>0]=nsec>>>0;HEAP32[pres+4>>>2>>>0]=nsec/Math.pow(2,32)>>>0;return 0}Module["_clock_res_get"]=_clock_res_get;_clock_res_get.sig="iip";var wasiRightsToMuslOFlags=rights=>{if(rights&2&&rights&64){return 2}if(rights&2){return 0}if(rights&64){return 1}throw new FS.ErrnoError(28)};Module["wasiRightsToMuslOFlags"]=wasiRightsToMuslOFlags;var wasiOFlagsToMuslOFlags=oflags=>{var musl_oflags=0;if(oflags&1){musl_oflags|=64}if(oflags&8){musl_oflags|=512}if(oflags&2){musl_oflags|=65536}if(oflags&4){musl_oflags|=128}return musl_oflags};Module["wasiOFlagsToMuslOFlags"]=wasiOFlagsToMuslOFlags;var createDyncallWrapper=sig=>{var sections=[];var prelude=[0,97,115,109,1,0,0,0];sections.push(prelude);var wrappersig=[sig[0].replace("j","i"),"i",sig.slice(1).replace(/j/g,"ii")].join("");var typeSectionBody=[3];generateFuncType(wrappersig,typeSectionBody);generateFuncType(sig,typeSectionBody);generateFuncType("vi",typeSectionBody);var typeSection=[1];uleb128Encode(typeSectionBody.length,typeSection);typeSection.push(...typeSectionBody);sections.push(typeSection);var importSection=[2,15,2,1,101,1,116,1,112,0,0,1,101,1,114,0,2];sections.push(importSection);var functionSection=[3,2,1,0];sections.push(functionSection);var exportSection=[7,5,1,1,102,0,1];sections.push(exportSection);var convert_code=[];if(sig[0]==="j"){convert_code=[1,1,126]}else{convert_code.push(0)}function localGet(j){convert_code.push(32);uleb128Encode(j,convert_code)}var j=1;for(var i=1;i{throw"unwind"};Module["_emscripten_unwind_to_js_event_loop"]=_emscripten_unwind_to_js_event_loop;_emscripten_unwind_to_js_event_loop.sig="v";var safeSetTimeout=(func,timeout)=>setTimeout(()=>{callUserCallback(func)},timeout);Module["safeSetTimeout"]=safeSetTimeout;var setImmediateWrapped=func=>{setImmediateWrapped.mapping||=[];var id=setImmediateWrapped.mapping.length;setImmediateWrapped.mapping[id]=setImmediate(()=>{setImmediateWrapped.mapping[id]=undefined;func()});return id};Module["setImmediateWrapped"]=setImmediateWrapped;var clearImmediateWrapped=id=>{clearImmediate(setImmediateWrapped.mapping[id]);setImmediateWrapped.mapping[id]=undefined};Module["clearImmediateWrapped"]=clearImmediateWrapped;var polyfillSetImmediate=()=>{};Module["polyfillSetImmediate"]=polyfillSetImmediate;var _emscripten_set_immediate=function(cb,userData){cb>>>=0;userData>>>=0;return emSetImmediate(()=>{callUserCallback(()=>getWasmTableEntry(cb)(userData))})};Module["_emscripten_set_immediate"]=_emscripten_set_immediate;_emscripten_set_immediate.sig="ipp";var _emscripten_clear_immediate=id=>{emClearImmediate(id)};Module["_emscripten_clear_immediate"]=_emscripten_clear_immediate;_emscripten_clear_immediate.sig="vi";var _emscripten_set_immediate_loop=function(cb,userData){cb>>>=0;userData>>>=0;function tick(){callUserCallback(()=>{if(getWasmTableEntry(cb)(userData)){emSetImmediate(tick)}else{}})}emSetImmediate(tick)};Module["_emscripten_set_immediate_loop"]=_emscripten_set_immediate_loop;_emscripten_set_immediate_loop.sig="vpp";var _emscripten_set_timeout=function(cb,msecs,userData){cb>>>=0;userData>>>=0;return safeSetTimeout(()=>getWasmTableEntry(cb)(userData),msecs)};Module["_emscripten_set_timeout"]=_emscripten_set_timeout;_emscripten_set_timeout.sig="ipdp";var _emscripten_clear_timeout=clearTimeout;Module["_emscripten_clear_timeout"]=_emscripten_clear_timeout;_emscripten_clear_timeout.sig="vi";var _emscripten_set_timeout_loop=function(cb,msecs,userData){cb>>>=0;userData>>>=0;function tick(){var t=_emscripten_get_now();var n=t+msecs;callUserCallback(()=>{if(getWasmTableEntry(cb)(t,userData)){setTimeout(tick,n-_emscripten_get_now())}})}return setTimeout(tick,0)};Module["_emscripten_set_timeout_loop"]=_emscripten_set_timeout_loop;_emscripten_set_timeout_loop.sig="vpdp";var _emscripten_set_interval=function(cb,msecs,userData){cb>>>=0;userData>>>=0;return setInterval(()=>{callUserCallback(()=>getWasmTableEntry(cb)(userData))},msecs)};Module["_emscripten_set_interval"]=_emscripten_set_interval;_emscripten_set_interval.sig="ipdp";var _emscripten_clear_interval=id=>{clearInterval(id)};Module["_emscripten_clear_interval"]=_emscripten_clear_interval;_emscripten_clear_interval.sig="vi";var idsToPromises=(idBuf,size)=>{var promises=[];for(var i=0;i>>2>>>0];promises[i]=getPromise(id)}return promises};Module["idsToPromises"]=idsToPromises;var makePromiseCallback=(callback,userData)=>value=>{var stack=stackSave();var resultPtr=stackAlloc(POINTER_SIZE);HEAPU32[resultPtr>>>2>>>0]=0;try{var result=getWasmTableEntry(callback)(resultPtr,userData,value);var resultVal=HEAPU32[resultPtr>>>2>>>0]}catch(e){if(typeof e!="number"){throw 0}throw e}finally{stackRestore(stack)}switch(result){case 0:return resultVal;case 1:return getPromise(resultVal);case 2:var ret=getPromise(resultVal);_emscripten_promise_destroy(resultVal);return ret;case 3:throw resultVal}};Module["makePromiseCallback"]=makePromiseCallback;function _emscripten_promise_then(id,onFulfilled,onRejected,userData){id>>>=0;onFulfilled>>>=0;onRejected>>>=0;userData>>>=0;var promise=getPromise(id);var newId=promiseMap.allocate({promise:promise.then(makePromiseCallback(onFulfilled,userData),makePromiseCallback(onRejected,userData))});return newId}Module["_emscripten_promise_then"]=_emscripten_promise_then;_emscripten_promise_then.sig="ppppp";var _emscripten_promise_all=function(idBuf,resultBuf,size){idBuf>>>=0;resultBuf>>>=0;size>>>=0;var promises=idsToPromises(idBuf,size);var id=promiseMap.allocate({promise:Promise.all(promises).then(results=>{if(resultBuf){for(var i=0;i>>2>>>0]=result}}return resultBuf})});return id};Module["_emscripten_promise_all"]=_emscripten_promise_all;_emscripten_promise_all.sig="pppp";var setPromiseResult=(ptr,fulfill,value)=>{var result=fulfill?0:3;HEAP32[ptr>>>2>>>0]=result;HEAPU32[ptr+4>>>2>>>0]=value};Module["setPromiseResult"]=setPromiseResult;var _emscripten_promise_all_settled=function(idBuf,resultBuf,size){idBuf>>>=0;resultBuf>>>=0;size>>>=0;var promises=idsToPromises(idBuf,size);var id=promiseMap.allocate({promise:Promise.allSettled(promises).then(results=>{if(resultBuf){var offset=resultBuf;for(var i=0;i>>=0;errorBuf>>>=0;size>>>=0;var promises=idsToPromises(idBuf,size);var id=promiseMap.allocate({promise:Promise.any(promises).catch(err=>{if(errorBuf){for(var i=0;i>>2>>>0]=err.errors[i]}}throw errorBuf})});return id};Module["_emscripten_promise_any"]=_emscripten_promise_any;_emscripten_promise_any.sig="pppp";function _emscripten_promise_race(idBuf,size){idBuf>>>=0;size>>>=0;var promises=idsToPromises(idBuf,size);var id=promiseMap.allocate({promise:Promise.race(promises)});return id}Module["_emscripten_promise_race"]=_emscripten_promise_race;_emscripten_promise_race.sig="ppp";function _emscripten_promise_await(returnValuePtr,id){returnValuePtr>>>=0;id>>>=0;abort("emscripten_promise_await is only available with ASYNCIFY")}Module["_emscripten_promise_await"]=_emscripten_promise_await;_emscripten_promise_await.sig="vpp";function ___cxa_find_matching_catch_4(arg0,arg1){arg0>>>=0;arg1>>>=0;return findMatchingCatch([arg0,arg1])}Module["___cxa_find_matching_catch_4"]=___cxa_find_matching_catch_4;___cxa_find_matching_catch_4.sig="ppp";function _llvm_eh_typeid_for(type){type>>>=0;return type}Module["_llvm_eh_typeid_for"]=_llvm_eh_typeid_for;_llvm_eh_typeid_for.sig="vp";function ___cxa_get_exception_ptr(ptr){ptr>>>=0;var rtn=new ExceptionInfo(ptr).get_exception_ptr();return rtn}Module["___cxa_get_exception_ptr"]=___cxa_get_exception_ptr;___cxa_get_exception_ptr.sig="pp";function ___cxa_call_unexpected(exception){exception>>>=0;return abort("Unexpected exception thrown, this is not properly supported - aborting")}Module["___cxa_call_unexpected"]=___cxa_call_unexpected;___cxa_call_unexpected.sig="vp";var _emscripten_set_main_loop_timing=(mode,value)=>{Browser.mainLoop.timingMode=mode;Browser.mainLoop.timingValue=value;if(!Browser.mainLoop.func){return 1}if(!Browser.mainLoop.running){Browser.mainLoop.running=true}if(mode==0){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setTimeout(){var timeUntilNextTick=Math.max(0,Browser.mainLoop.tickStartTime+value-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,timeUntilNextTick)};Browser.mainLoop.method="timeout"}else if(mode==1){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_rAF(){Browser.requestAnimationFrame(Browser.mainLoop.runner)};Browser.mainLoop.method="rAF"}else if(mode==2){if(typeof Browser.setImmediate=="undefined"){if(typeof setImmediate=="undefined"){var setImmediates=[];var emscriptenMainLoopMessageId="setimmediate";var Browser_setImmediate_messageHandler=event=>{if(event.data===emscriptenMainLoopMessageId||event.data.target===emscriptenMainLoopMessageId){event.stopPropagation();setImmediates.shift()()}};addEventListener("message",Browser_setImmediate_messageHandler,true);Browser.setImmediate=function Browser_emulated_setImmediate(func){setImmediates.push(func);if(ENVIRONMENT_IS_WORKER){if(Module["setImmediates"]===undefined)Module["setImmediates"]=[];Module["setImmediates"].push(func);postMessage({target:emscriptenMainLoopMessageId})}else postMessage(emscriptenMainLoopMessageId,"*")}}else{Browser.setImmediate=setImmediate}}Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setImmediate(){Browser.setImmediate(Browser.mainLoop.runner)};Browser.mainLoop.method="immediate"}return 0};Module["_emscripten_set_main_loop_timing"]=_emscripten_set_main_loop_timing;_emscripten_set_main_loop_timing.sig="iii";var setMainLoop=(browserIterationFunc,fps,simulateInfiniteLoop,arg,noSetTiming)=>{Browser.mainLoop.func=browserIterationFunc;Browser.mainLoop.arg=arg;var thisMainLoopId=Browser.mainLoop.currentlyRunningMainloop;function checkIsRunning(){if(thisMainLoopId0){var start=Date.now();var blocker=Browser.mainLoop.queue.shift();blocker.func(blocker.arg);if(Browser.mainLoop.remainingBlockers){var remaining=Browser.mainLoop.remainingBlockers;var next=remaining%1==0?remaining-1:Math.floor(remaining);if(blocker.counted){Browser.mainLoop.remainingBlockers=next}else{next=next+.5;Browser.mainLoop.remainingBlockers=(8*remaining+next)/9}}Browser.mainLoop.updateStatus();if(!checkIsRunning())return;setTimeout(Browser.mainLoop.runner,0);return}if(!checkIsRunning())return;Browser.mainLoop.currentFrameNumber=Browser.mainLoop.currentFrameNumber+1|0;if(Browser.mainLoop.timingMode==1&&Browser.mainLoop.timingValue>1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else if(Browser.mainLoop.timingMode==0){Browser.mainLoop.tickStartTime=_emscripten_get_now()}Browser.mainLoop.runIter(browserIterationFunc);if(!checkIsRunning())return;if(typeof SDL=="object")SDL.audio?.queueNewAudioData?.();Browser.mainLoop.scheduler()};if(!noSetTiming){if(fps&&fps>0){_emscripten_set_main_loop_timing(0,1e3/fps)}else{_emscripten_set_main_loop_timing(1,1)}Browser.mainLoop.scheduler()}if(simulateInfiniteLoop){throw"unwind"}};Module["setMainLoop"]=setMainLoop;var Browser={mainLoop:{running:false,scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause(){Browser.mainLoop.scheduler=null;Browser.mainLoop.currentlyRunningMainloop++},resume(){Browser.mainLoop.currentlyRunningMainloop++;var timingMode=Browser.mainLoop.timingMode;var timingValue=Browser.mainLoop.timingValue;var func=Browser.mainLoop.func;Browser.mainLoop.func=null;setMainLoop(func,0,false,Browser.mainLoop.arg,true);_emscripten_set_main_loop_timing(timingMode,timingValue);Browser.mainLoop.scheduler()},updateStatus(){if(Module["setStatus"]){var message=Module["statusMessage"]||"Please wait...";var remaining=Browser.mainLoop.remainingBlockers;var expected=Browser.mainLoop.expectedBlockers;if(remaining){if(remaining{var canvas=document.createElement("canvas");canvas.width=img.width;canvas.height=img.height;var ctx=canvas.getContext("2d");ctx.drawImage(img,0,0);preloadedImages[name]=canvas;URL.revokeObjectURL(url);onload?.(byteArray)};img.onerror=event=>{err(`Image ${url} could not be decoded`);onerror?.()};img.src=url};preloadPlugins.push(imagePlugin);var audioPlugin={};audioPlugin["canHandle"]=function audioPlugin_canHandle(name){return!Module.noAudioDecoding&&name.substr(-4)in{".ogg":1,".wav":1,".mp3":1}};audioPlugin["handle"]=function audioPlugin_handle(byteArray,name,onload,onerror){var done=false;function finish(audio){if(done)return;done=true;preloadedAudios[name]=audio;onload?.(byteArray)}function fail(){if(done)return;done=true;preloadedAudios[name]=new Audio;onerror?.()}var b=new Blob([byteArray],{type:Browser.getMimetype(name)});var url=URL.createObjectURL(b);var audio=new Audio;audio.addEventListener("canplaythrough",()=>finish(audio),false);audio.onerror=function audio_onerror(event){if(done)return;err(`warning: browser could not fully decode audio ${name}, trying slower base64 approach`);function encode64(data){var BASE="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var PAD="=";var ret="";var leftchar=0;var leftbits=0;for(var i=0;i=6){var curr=leftchar>>leftbits-6&63;leftbits-=6;ret+=BASE[curr]}}if(leftbits==2){ret+=BASE[(leftchar&3)<<4];ret+=PAD+PAD}else if(leftbits==4){ret+=BASE[(leftchar&15)<<2];ret+=PAD}return ret}audio.src="data:audio/x-"+name.substr(-3)+";base64,"+encode64(byteArray);finish(audio)};audio.src=url;safeSetTimeout(()=>{finish(audio)},1e4)};preloadPlugins.push(audioPlugin);function pointerLockChange(){Browser.pointerLock=document["pointerLockElement"]===Module["canvas"]||document["mozPointerLockElement"]===Module["canvas"]||document["webkitPointerLockElement"]===Module["canvas"]||document["msPointerLockElement"]===Module["canvas"]}var canvas=Module["canvas"];if(canvas){canvas.requestPointerLock=canvas["requestPointerLock"]||canvas["mozRequestPointerLock"]||canvas["webkitRequestPointerLock"]||canvas["msRequestPointerLock"]||(()=>{});canvas.exitPointerLock=document["exitPointerLock"]||document["mozExitPointerLock"]||document["webkitExitPointerLock"]||document["msExitPointerLock"]||(()=>{});canvas.exitPointerLock=canvas.exitPointerLock.bind(document);document.addEventListener("pointerlockchange",pointerLockChange,false);document.addEventListener("mozpointerlockchange",pointerLockChange,false);document.addEventListener("webkitpointerlockchange",pointerLockChange,false);document.addEventListener("mspointerlockchange",pointerLockChange,false);if(Module["elementPointerLock"]){canvas.addEventListener("click",ev=>{if(!Browser.pointerLock&&Module["canvas"].requestPointerLock){Module["canvas"].requestPointerLock();ev.preventDefault()}},false)}}},createContext(canvas,useWebGL,setInModule,webGLContextAttributes){if(useWebGL&&Module.ctx&&canvas==Module.canvas)return Module.ctx;var ctx;var contextHandle;if(useWebGL){var contextAttributes={antialias:false,alpha:false,majorVersion:1};if(webGLContextAttributes){for(var attribute in webGLContextAttributes){contextAttributes[attribute]=webGLContextAttributes[attribute]}}if(typeof GL!="undefined"){contextHandle=GL.createContext(canvas,contextAttributes);if(contextHandle){ctx=GL.getContext(contextHandle).GLctx}}}else{ctx=canvas.getContext("2d")}if(!ctx)return null;if(setInModule){Module.ctx=ctx;if(useWebGL)GL.makeContextCurrent(contextHandle);Module.useWebGL=useWebGL;Browser.moduleContextCreatedCallbacks.forEach(callback=>callback());Browser.init()}return ctx},destroyContext(canvas,useWebGL,setInModule){},fullscreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullscreen(lockPointer,resizeCanvas){Browser.lockPointer=lockPointer;Browser.resizeCanvas=resizeCanvas;if(typeof Browser.lockPointer=="undefined")Browser.lockPointer=true;if(typeof Browser.resizeCanvas=="undefined")Browser.resizeCanvas=false;var canvas=Module["canvas"];function fullscreenChange(){Browser.isFullscreen=false;var canvasContainer=canvas.parentNode;if((document["fullscreenElement"]||document["mozFullScreenElement"]||document["msFullscreenElement"]||document["webkitFullscreenElement"]||document["webkitCurrentFullScreenElement"])===canvasContainer){canvas.exitFullscreen=Browser.exitFullscreen;if(Browser.lockPointer)canvas.requestPointerLock();Browser.isFullscreen=true;if(Browser.resizeCanvas){Browser.setFullscreenCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}else{canvasContainer.parentNode.insertBefore(canvas,canvasContainer);canvasContainer.parentNode.removeChild(canvasContainer);if(Browser.resizeCanvas){Browser.setWindowedCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}Module["onFullScreen"]?.(Browser.isFullscreen);Module["onFullscreen"]?.(Browser.isFullscreen)}if(!Browser.fullscreenHandlersInstalled){Browser.fullscreenHandlersInstalled=true;document.addEventListener("fullscreenchange",fullscreenChange,false);document.addEventListener("mozfullscreenchange",fullscreenChange,false);document.addEventListener("webkitfullscreenchange",fullscreenChange,false);document.addEventListener("MSFullscreenChange",fullscreenChange,false)}var canvasContainer=document.createElement("div");canvas.parentNode.insertBefore(canvasContainer,canvas);canvasContainer.appendChild(canvas);canvasContainer.requestFullscreen=canvasContainer["requestFullscreen"]||canvasContainer["mozRequestFullScreen"]||canvasContainer["msRequestFullscreen"]||(canvasContainer["webkitRequestFullscreen"]?()=>canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"]):null)||(canvasContainer["webkitRequestFullScreen"]?()=>canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"]):null);canvasContainer.requestFullscreen()},exitFullscreen(){if(!Browser.isFullscreen){return false}var CFS=document["exitFullscreen"]||document["cancelFullScreen"]||document["mozCancelFullScreen"]||document["msExitFullscreen"]||document["webkitCancelFullScreen"]||(()=>{});CFS.apply(document,[]);return true},nextRAF:0,fakeRequestAnimationFrame(func){var now=Date.now();if(Browser.nextRAF===0){Browser.nextRAF=now+1e3/60}else{while(now+2>=Browser.nextRAF){Browser.nextRAF+=1e3/60}}var delay=Math.max(Browser.nextRAF-now,0);setTimeout(func,delay)},requestAnimationFrame(func){if(typeof requestAnimationFrame=="function"){requestAnimationFrame(func);return}var RAF=Browser.fakeRequestAnimationFrame;RAF(func)},safeSetTimeout(func,timeout){return safeSetTimeout(func,timeout)},safeRequestAnimationFrame(func){return Browser.requestAnimationFrame(()=>{callUserCallback(func)})},getMimetype(name){return{"jpg":"image/jpeg","jpeg":"image/jpeg","png":"image/png","bmp":"image/bmp","ogg":"audio/ogg","wav":"audio/wav","mp3":"audio/mpeg"}[name.substr(name.lastIndexOf(".")+1)]},getUserMedia(func){window.getUserMedia||=navigator["getUserMedia"]||navigator["mozGetUserMedia"];window.getUserMedia(func)},getMovementX(event){return event["movementX"]||event["mozMovementX"]||event["webkitMovementX"]||0},getMovementY(event){return event["movementY"]||event["mozMovementY"]||event["webkitMovementY"]||0},getMouseWheelDelta(event){var delta=0;switch(event.type){case"DOMMouseScroll":delta=event.detail/3;break;case"mousewheel":delta=event.wheelDelta/120;break;case"wheel":delta=event.deltaY;switch(event.deltaMode){case 0:delta/=100;break;case 1:delta/=3;break;case 2:delta*=80;break;default:throw"unrecognized mouse wheel delta mode: "+event.deltaMode}break;default:throw"unrecognized mouse wheel event: "+event.type}return delta},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseCoords(pageX,pageY){var rect=Module["canvas"].getBoundingClientRect();var cw=Module["canvas"].width;var ch=Module["canvas"].height;var scrollX=typeof window.scrollX!="undefined"?window.scrollX:window.pageXOffset;var scrollY=typeof window.scrollY!="undefined"?window.scrollY:window.pageYOffset;var adjustedX=pageX-(scrollX+rect.left);var adjustedY=pageY-(scrollY+rect.top);adjustedX=adjustedX*(cw/rect.width);adjustedY=adjustedY*(ch/rect.height);return{x:adjustedX,y:adjustedY}},setMouseCoords(pageX,pageY){const{x:x,y:y}=Browser.calculateMouseCoords(pageX,pageY);Browser.mouseMovementX=x-Browser.mouseX;Browser.mouseMovementY=y-Browser.mouseY;Browser.mouseX=x;Browser.mouseY=y},calculateMouseEvent(event){if(Browser.pointerLock){if(event.type!="mousemove"&&"mozMovementX"in event){Browser.mouseMovementX=Browser.mouseMovementY=0}else{Browser.mouseMovementX=Browser.getMovementX(event);Browser.mouseMovementY=Browser.getMovementY(event)}Browser.mouseX+=Browser.mouseMovementX;Browser.mouseY+=Browser.mouseMovementY}else{if(event.type==="touchstart"||event.type==="touchend"||event.type==="touchmove"){var touch=event.touch;if(touch===undefined){return}var coords=Browser.calculateMouseCoords(touch.pageX,touch.pageY);if(event.type==="touchstart"){Browser.lastTouches[touch.identifier]=coords;Browser.touches[touch.identifier]=coords}else if(event.type==="touchend"||event.type==="touchmove"){var last=Browser.touches[touch.identifier];last||=coords;Browser.lastTouches[touch.identifier]=last;Browser.touches[touch.identifier]=coords}return}Browser.setMouseCoords(event.pageX,event.pageY)}},resizeListeners:[],updateResizeListeners(){var canvas=Module["canvas"];Browser.resizeListeners.forEach(listener=>listener(canvas.width,canvas.height))},setCanvasSize(width,height,noUpdates){var canvas=Module["canvas"];Browser.updateCanvasDimensions(canvas,width,height);if(!noUpdates)Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>>2>>>0];flags=flags|8388608;HEAP32[SDL.screen>>>2>>>0]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},setWindowedCanvasSize(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>>2>>>0];flags=flags&~8388608;HEAP32[SDL.screen>>>2>>>0]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},updateCanvasDimensions(canvas,wNative,hNative){if(wNative&&hNative){canvas.widthNative=wNative;canvas.heightNative=hNative}else{wNative=canvas.widthNative;hNative=canvas.heightNative}var w=wNative;var h=hNative;if(Module["forcedAspectRatio"]&&Module["forcedAspectRatio"]>0){if(w/h>>=0;onload>>>=0;onerror>>>=0;var _file=UTF8ToString(file);var data=FS.analyzePath(_file);if(!data.exists)return-1;FS.createPreloadedFile(PATH.dirname(_file),PATH.basename(_file),new Uint8Array(data.object.contents),true,true,()=>{if(onload)getWasmTableEntry(onload)(file)},()=>{if(onerror)getWasmTableEntry(onerror)(file)},true);return 0};Module["_emscripten_run_preload_plugins"]=_emscripten_run_preload_plugins;_emscripten_run_preload_plugins.sig="ippp";var Browser_asyncPrepareDataCounter=0;Module["Browser_asyncPrepareDataCounter"]=Browser_asyncPrepareDataCounter;var _emscripten_run_preload_plugins_data=function(data,size,suffix,arg,onload,onerror){data>>>=0;suffix>>>=0;arg>>>=0;onload>>>=0;onerror>>>=0;var _suffix=UTF8ToString(suffix);var name="prepare_data_"+Browser_asyncPrepareDataCounter+++"."+_suffix;var cname=stringToNewUTF8(name);FS.createPreloadedFile("/",name,HEAPU8.subarray(data>>>0,data+size>>>0),true,true,()=>{if(onload)getWasmTableEntry(onload)(arg,cname)},()=>{if(onerror)getWasmTableEntry(onerror)(arg)},true)};Module["_emscripten_run_preload_plugins_data"]=_emscripten_run_preload_plugins_data;_emscripten_run_preload_plugins_data.sig="vpipppp";var _emscripten_async_run_script=function(script,millis){script>>>=0;safeSetTimeout(()=>_emscripten_run_script(script),millis)};Module["_emscripten_async_run_script"]=_emscripten_async_run_script;_emscripten_async_run_script.sig="vpi";var _emscripten_async_load_script=function(url,onload,onerror){url>>>=0;onload>>>=0;onerror>>>=0;url=UTF8ToString(url);onload=getWasmTableEntry(onload);onerror=getWasmTableEntry(onerror);var loadDone=()=>{if(onload){if(runDependencies>0){dependenciesFulfilled=onload}else{onload()}}};var loadError=()=>{onerror?.()};if(ENVIRONMENT_IS_NODE){readAsync(url,data=>{eval(data);loadDone()},loadError,false);return}var script=document.createElement("script");script.onload=loadDone;script.onerror=loadError;script.src=url;document.body.appendChild(script)};Module["_emscripten_async_load_script"]=_emscripten_async_load_script;_emscripten_async_load_script.sig="vppp";function _emscripten_get_main_loop_timing(mode,value){mode>>>=0;value>>>=0;if(mode)HEAP32[mode>>>2>>>0]=Browser.mainLoop.timingMode;if(value)HEAP32[value>>>2>>>0]=Browser.mainLoop.timingValue}Module["_emscripten_get_main_loop_timing"]=_emscripten_get_main_loop_timing;_emscripten_get_main_loop_timing.sig="vpp";function _emscripten_set_main_loop(func,fps,simulateInfiniteLoop){func>>>=0;var browserIterationFunc=getWasmTableEntry(func);setMainLoop(browserIterationFunc,fps,simulateInfiniteLoop)}Module["_emscripten_set_main_loop"]=_emscripten_set_main_loop;_emscripten_set_main_loop.sig="vpii";var _emscripten_set_main_loop_arg=function(func,arg,fps,simulateInfiniteLoop){func>>>=0;arg>>>=0;var browserIterationFunc=()=>getWasmTableEntry(func)(arg);setMainLoop(browserIterationFunc,fps,simulateInfiniteLoop,arg)};Module["_emscripten_set_main_loop_arg"]=_emscripten_set_main_loop_arg;_emscripten_set_main_loop_arg.sig="vppii";var _emscripten_cancel_main_loop=()=>{Browser.mainLoop.pause();Browser.mainLoop.func=null};Module["_emscripten_cancel_main_loop"]=_emscripten_cancel_main_loop;_emscripten_cancel_main_loop.sig="v";var _emscripten_pause_main_loop=()=>{Browser.mainLoop.pause()};Module["_emscripten_pause_main_loop"]=_emscripten_pause_main_loop;_emscripten_pause_main_loop.sig="v";var _emscripten_resume_main_loop=()=>{Browser.mainLoop.resume()};Module["_emscripten_resume_main_loop"]=_emscripten_resume_main_loop;_emscripten_resume_main_loop.sig="v";var __emscripten_push_main_loop_blocker=function(func,arg,name){func>>>=0;arg>>>=0;name>>>=0;Browser.mainLoop.queue.push({func:()=>{getWasmTableEntry(func)(arg)},name:UTF8ToString(name),counted:true});Browser.mainLoop.updateStatus()};Module["__emscripten_push_main_loop_blocker"]=__emscripten_push_main_loop_blocker;__emscripten_push_main_loop_blocker.sig="vppp";var __emscripten_push_uncounted_main_loop_blocker=function(func,arg,name){func>>>=0;arg>>>=0;name>>>=0;Browser.mainLoop.queue.push({func:()=>{getWasmTableEntry(func)(arg)},name:UTF8ToString(name),counted:false});Browser.mainLoop.updateStatus()};Module["__emscripten_push_uncounted_main_loop_blocker"]=__emscripten_push_uncounted_main_loop_blocker;__emscripten_push_uncounted_main_loop_blocker.sig="vppp";var _emscripten_set_main_loop_expected_blockers=num=>{Browser.mainLoop.expectedBlockers=num;Browser.mainLoop.remainingBlockers=num;Browser.mainLoop.updateStatus()};Module["_emscripten_set_main_loop_expected_blockers"]=_emscripten_set_main_loop_expected_blockers;_emscripten_set_main_loop_expected_blockers.sig="vi";function _emscripten_async_call(func,arg,millis){func>>>=0;arg>>>=0;function wrapper(){getWasmTableEntry(func)(arg)}if(millis>=0||ENVIRONMENT_IS_NODE){safeSetTimeout(wrapper,millis)}else{Browser.safeRequestAnimationFrame(wrapper)}}Module["_emscripten_async_call"]=_emscripten_async_call;_emscripten_async_call.sig="vppi";function _emscripten_get_window_title(){var buflen=256;if(!_emscripten_get_window_title.buffer){_emscripten_get_window_title.buffer=_malloc(buflen)}stringToUTF8(document.title,_emscripten_get_window_title.buffer,buflen);return _emscripten_get_window_title.buffer}Module["_emscripten_get_window_title"]=_emscripten_get_window_title;_emscripten_get_window_title.sig="p";function _emscripten_set_window_title(title){title>>>=0;return document.title=UTF8ToString(title)}Module["_emscripten_set_window_title"]=_emscripten_set_window_title;_emscripten_set_window_title.sig="vp";function _emscripten_get_screen_size(width,height){width>>>=0;height>>>=0;HEAP32[width>>>2>>>0]=screen.width;HEAP32[height>>>2>>>0]=screen.height}Module["_emscripten_get_screen_size"]=_emscripten_get_screen_size;_emscripten_get_screen_size.sig="vpp";var _emscripten_hide_mouse=()=>{var styleSheet=document.styleSheets[0];var rules=styleSheet.cssRules;for(var i=0;i{Browser.setCanvasSize(width,height)};Module["_emscripten_set_canvas_size"]=_emscripten_set_canvas_size;_emscripten_set_canvas_size.sig="vii";function _emscripten_get_canvas_size(width,height,isFullscreen){width>>>=0;height>>>=0;isFullscreen>>>=0;var canvas=Module["canvas"];HEAP32[width>>>2>>>0]=canvas.width;HEAP32[height>>>2>>>0]=canvas.height;HEAP32[isFullscreen>>>2>>>0]=Browser.isFullscreen?1:0}Module["_emscripten_get_canvas_size"]=_emscripten_get_canvas_size;_emscripten_get_canvas_size.sig="vppp";function _emscripten_create_worker(url){url>>>=0;url=UTF8ToString(url);var id=Browser.workers.length;var info={worker:new Worker(url),callbacks:[],awaited:0,buffer:0,bufferSize:0};info.worker.onmessage=function info_worker_onmessage(msg){if(ABORT)return;var info=Browser.workers[id];if(!info)return;var callbackId=msg.data["callbackId"];var callbackInfo=info.callbacks[callbackId];if(!callbackInfo)return;if(msg.data["finalResponse"]){info.awaited--;info.callbacks[callbackId]=null}var data=msg.data["data"];if(data){if(!data.byteLength)data=new Uint8Array(data);if(!info.buffer||info.bufferSize>>0);callbackInfo.func(info.buffer,data.length,callbackInfo.arg)}else{callbackInfo.func(0,0,callbackInfo.arg)}};Browser.workers.push(info);return id}Module["_emscripten_create_worker"]=_emscripten_create_worker;_emscripten_create_worker.sig="ip";var _emscripten_destroy_worker=id=>{var info=Browser.workers[id];info.worker.terminate();if(info.buffer)_free(info.buffer);Browser.workers[id]=null};Module["_emscripten_destroy_worker"]=_emscripten_destroy_worker;_emscripten_destroy_worker.sig="vi";function _emscripten_call_worker(id,funcName,data,size,callback,arg){funcName>>>=0;data>>>=0;callback>>>=0;arg>>>=0;funcName=UTF8ToString(funcName);var info=Browser.workers[id];var callbackId=-1;if(callback){callbackId=info.callbacks.length;info.callbacks.push({func:getWasmTableEntry(callback),arg:arg});info.awaited++}var transferObject={"funcName":funcName,"callbackId":callbackId,"data":data?new Uint8Array(HEAPU8.subarray(data>>>0,data+size>>>0)):0};if(data){info.worker.postMessage(transferObject,[transferObject.data.buffer])}else{info.worker.postMessage(transferObject)}}Module["_emscripten_call_worker"]=_emscripten_call_worker;_emscripten_call_worker.sig="vippipp";var _emscripten_get_worker_queue_size=id=>{var info=Browser.workers[id];if(!info)return-1;return info.awaited};Module["_emscripten_get_worker_queue_size"]=_emscripten_get_worker_queue_size;_emscripten_get_worker_queue_size.sig="ii";var getPreloadedImageData=(path,w,h)=>{path=PATH_FS.resolve(path);var canvas=preloadedImages[path];if(!canvas)return 0;var ctx=canvas.getContext("2d");var image=ctx.getImageData(0,0,canvas.width,canvas.height);var buf=_malloc(canvas.width*canvas.height*4);HEAPU8.set(image.data,buf>>>0);HEAP32[w>>>2>>>0]=canvas.width;HEAP32[h>>>2>>>0]=canvas.height;return buf};Module["getPreloadedImageData"]=getPreloadedImageData;function _emscripten_get_preloaded_image_data(path,w,h){path>>>=0;w>>>=0;h>>>=0;return getPreloadedImageData(UTF8ToString(path),w,h)}Module["_emscripten_get_preloaded_image_data"]=_emscripten_get_preloaded_image_data;_emscripten_get_preloaded_image_data.sig="pppp";var getPreloadedImageData__data=["$PATH_FS","malloc"];Module["getPreloadedImageData__data"]=getPreloadedImageData__data;function _emscripten_get_preloaded_image_data_from_FILE(file,w,h){file>>>=0;w>>>=0;h>>>=0;var fd=_fileno(file);var stream=FS.getStream(fd);if(stream){return getPreloadedImageData(stream.path,w,h)}return 0}Module["_emscripten_get_preloaded_image_data_from_FILE"]=_emscripten_get_preloaded_image_data_from_FILE;_emscripten_get_preloaded_image_data_from_FILE.sig="pppp";var wget={wgetRequests:{},nextWgetRequestHandle:0,getNextWgetRequestHandle(){var handle=wget.nextWgetRequestHandle;wget.nextWgetRequestHandle++;return handle}};Module["wget"]=wget;var FS_mkdirTree=(path,mode)=>FS.mkdirTree(path,mode);Module["FS_mkdirTree"]=FS_mkdirTree;var _emscripten_async_wget=function(url,file,onload,onerror){url>>>=0;file>>>=0;onload>>>=0;onerror>>>=0;var _url=UTF8ToString(url);var _file=UTF8ToString(file);_file=PATH_FS.resolve(_file);function doCallback(callback){if(callback){callUserCallback(()=>{var sp=stackSave();getWasmTableEntry(callback)(stringToUTF8OnStack(_file));stackRestore(sp)})}}var destinationDirectory=PATH.dirname(_file);FS_createPreloadedFile(destinationDirectory,PATH.basename(_file),_url,true,true,()=>doCallback(onload),()=>doCallback(onerror),false,false,()=>{try{FS_unlink(_file)}catch(e){}FS_mkdirTree(destinationDirectory)})};Module["_emscripten_async_wget"]=_emscripten_async_wget;_emscripten_async_wget.sig="vpppp";var _emscripten_async_wget_data=function(url,userdata,onload,onerror){url>>>=0;userdata>>>=0;onload>>>=0;onerror>>>=0;asyncLoad(UTF8ToString(url),byteArray=>{callUserCallback(()=>{var buffer=_malloc(byteArray.length);HEAPU8.set(byteArray,buffer>>>0);getWasmTableEntry(onload)(userdata,buffer,byteArray.length);_free(buffer)})},()=>{if(onerror){callUserCallback(()=>{getWasmTableEntry(onerror)(userdata)})}},true)};Module["_emscripten_async_wget_data"]=_emscripten_async_wget_data;_emscripten_async_wget_data.sig="vpppp";var _emscripten_async_wget2=function(url,file,request,param,userdata,onload,onerror,onprogress){url>>>=0;file>>>=0;request>>>=0;param>>>=0;userdata>>>=0;onload>>>=0;onerror>>>=0;onprogress>>>=0;var _url=UTF8ToString(url);var _file=UTF8ToString(file);_file=PATH_FS.resolve(_file);var _request=UTF8ToString(request);var _param=UTF8ToString(param);var index=_file.lastIndexOf("/");var http=new XMLHttpRequest;http.open(_request,_url,true);http.responseType="arraybuffer";var handle=wget.getNextWgetRequestHandle();var destinationDirectory=PATH.dirname(_file);http.onload=e=>{if(http.status>=200&&http.status<300){try{FS.unlink(_file)}catch(e){}FS.mkdirTree(destinationDirectory);FS.createDataFile(_file.substr(0,index),_file.substr(index+1),new Uint8Array(http.response),true,true,false);if(onload){var sp=stackSave();getWasmTableEntry(onload)(handle,userdata,stringToUTF8OnStack(_file));stackRestore(sp)}}else{if(onerror)getWasmTableEntry(onerror)(handle,userdata,http.status)}delete wget.wgetRequests[handle]};http.onerror=e=>{if(onerror)getWasmTableEntry(onerror)(handle,userdata,http.status);delete wget.wgetRequests[handle]};http.onprogress=e=>{if(e.lengthComputable||e.lengthComputable===undefined&&e.total!=0){var percentComplete=e.loaded/e.total*100;if(onprogress)getWasmTableEntry(onprogress)(handle,userdata,percentComplete)}};http.onabort=e=>{delete wget.wgetRequests[handle]};if(_request=="POST"){http.setRequestHeader("Content-type","application/x-www-form-urlencoded");http.send(_param)}else{http.send(null)}wget.wgetRequests[handle]=http;return handle};Module["_emscripten_async_wget2"]=_emscripten_async_wget2;_emscripten_async_wget2.sig="ipppppppp";function _emscripten_async_wget2_data(url,request,param,userdata,free,onload,onerror,onprogress){url>>>=0;request>>>=0;param>>>=0;userdata>>>=0;onload>>>=0;onerror>>>=0;onprogress>>>=0;var _url=UTF8ToString(url);var _request=UTF8ToString(request);var _param=UTF8ToString(param);var http=new XMLHttpRequest;http.open(_request,_url,true);http.responseType="arraybuffer";var handle=wget.getNextWgetRequestHandle();function onerrorjs(){if(onerror){var sp=stackSave();var statusText=0;if(http.statusText){statusText=stringToUTF8OnStack(http.statusText)}getWasmTableEntry(onerror)(handle,userdata,http.status,statusText);stackRestore(sp)}}http.onload=e=>{if(http.status>=200&&http.status<300||http.status===0&&_url.substr(0,4).toLowerCase()!="http"){var byteArray=new Uint8Array(http.response);var buffer=_malloc(byteArray.length);HEAPU8.set(byteArray,buffer>>>0);if(onload)getWasmTableEntry(onload)(handle,userdata,buffer,byteArray.length);if(free)_free(buffer)}else{onerrorjs()}delete wget.wgetRequests[handle]};http.onerror=e=>{onerrorjs();delete wget.wgetRequests[handle]};http.onprogress=e=>{if(onprogress)getWasmTableEntry(onprogress)(handle,userdata,e.loaded,e.lengthComputable||e.lengthComputable===undefined?e.total:0)};http.onabort=e=>{delete wget.wgetRequests[handle]};if(_request=="POST"){http.setRequestHeader("Content-type","application/x-www-form-urlencoded");http.send(_param)}else{http.send(null)}wget.wgetRequests[handle]=http;return handle}Module["_emscripten_async_wget2_data"]=_emscripten_async_wget2_data;_emscripten_async_wget2_data.sig="ippppippp";var _emscripten_async_wget2_abort=handle=>{var http=wget.wgetRequests[handle];http?.abort()};Module["_emscripten_async_wget2_abort"]=_emscripten_async_wget2_abort;_emscripten_async_wget2_abort.sig="vi";function __dlsym_catchup_js(handle,symbolIndex){handle>>>=0;var lib=LDSO.loadedLibsByHandle[handle];var symDict=lib.exports;var symName=Object.keys(symDict)[symbolIndex];var sym=symDict[symName];var result=addFunction(sym,sym.sig);return result}Module["__dlsym_catchup_js"]=__dlsym_catchup_js;__dlsym_catchup_js.sig="ppi";var _setNetworkCallback=(event,userData,callback)=>{function _callback(data){try{if(event==="error"){var sp=stackSave();var msg=stringToUTF8OnStack(data[2]);getWasmTableEntry(callback)(data[0],data[1],msg,userData);stackRestore(sp)}else{getWasmTableEntry(callback)(data,userData)}}catch(e){if(!(e instanceof ExitStatus)){if(e&&typeof e=="object"&&e.stack)err("exception thrown: "+[e,e.stack]);throw e}}}Module["websocket"]["on"](event,callback?_callback:null)};Module["_setNetworkCallback"]=_setNetworkCallback;function _emscripten_set_socket_error_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("error",userData,callback)}Module["_emscripten_set_socket_error_callback"]=_emscripten_set_socket_error_callback;_emscripten_set_socket_error_callback.sig="vpp";function _emscripten_set_socket_open_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("open",userData,callback)}Module["_emscripten_set_socket_open_callback"]=_emscripten_set_socket_open_callback;_emscripten_set_socket_open_callback.sig="vpp";function _emscripten_set_socket_listen_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("listen",userData,callback)}Module["_emscripten_set_socket_listen_callback"]=_emscripten_set_socket_listen_callback;_emscripten_set_socket_listen_callback.sig="vpp";function _emscripten_set_socket_connection_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("connection",userData,callback)}Module["_emscripten_set_socket_connection_callback"]=_emscripten_set_socket_connection_callback;_emscripten_set_socket_connection_callback.sig="vpp";function _emscripten_set_socket_message_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("message",userData,callback)}Module["_emscripten_set_socket_message_callback"]=_emscripten_set_socket_message_callback;_emscripten_set_socket_message_callback.sig="vpp";function _emscripten_set_socket_close_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("close",userData,callback)}Module["_emscripten_set_socket_close_callback"]=_emscripten_set_socket_close_callback;_emscripten_set_socket_close_callback.sig="vpp";var ALLOC_NORMAL=0;Module["ALLOC_NORMAL"]=ALLOC_NORMAL;var ALLOC_STACK=1;Module["ALLOC_STACK"]=ALLOC_STACK;var allocate=(slab,allocator)=>{var ret;if(allocator==ALLOC_STACK){ret=stackAlloc(slab.length)}else{ret=_malloc(slab.length)}if(!slab.subarray&&!slab.slice){slab=new Uint8Array(slab)}HEAPU8.set(slab,ret>>>0);return ret};Module["allocate"]=allocate;var writeStringToMemory=(string,buffer,dontAddNull)=>{warnOnce("writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!");var lastChar,end;if(dontAddNull){end=buffer+lengthBytesUTF8(string);lastChar=HEAP8[end>>>0]}stringToUTF8(string,buffer,Infinity);if(dontAddNull)HEAP8[end>>>0]=lastChar};Module["writeStringToMemory"]=writeStringToMemory;var writeAsciiToMemory=(str,buffer,dontAddNull)=>{for(var i=0;i>>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>>0]=0};Module["writeAsciiToMemory"]=writeAsciiToMemory;var allocateUTF8=stringToNewUTF8;Module["allocateUTF8"]=allocateUTF8;var allocateUTF8OnStack=stringToUTF8OnStack;Module["allocateUTF8OnStack"]=allocateUTF8OnStack;var setErrNo=value=>{HEAP32[___errno_location()>>>2>>>0]=value;return value};Module["setErrNo"]=setErrNo;var demangle=func=>{demangle.recursionGuard=(demangle.recursionGuard|0)+1;if(demangle.recursionGuard>1)return func;return withStackSave(()=>{try{var s=func;if(s.startsWith("__Z"))s=s.substr(1);var buf=stringToUTF8OnStack(s);var status=stackAlloc(4);var ret=___cxa_demangle(buf,0,0,status);if(HEAP32[status>>>2>>>0]===0&&ret){return UTF8ToString(ret)}}catch(e){}finally{_free(ret);if(demangle.recursionGuard<2)--demangle.recursionGuard}return func})};Module["demangle"]=demangle;function stackTrace(){var js=jsStackTrace();if(Module["extraStackTrace"])js+="\n"+Module["extraStackTrace"]();return js}Module["stackTrace"]=stackTrace;var _emscripten_is_main_browser_thread=()=>!ENVIRONMENT_IS_WORKER;Module["_emscripten_is_main_browser_thread"]=_emscripten_is_main_browser_thread;var webSockets=new HandleAllocator;Module["webSockets"]=webSockets;var WS={socketEvent:null,getSocket(socketId){if(!webSockets.has(socketId)){return 0}return webSockets.get(socketId)},getSocketEvent(socketId){this.socketEvent||=_malloc(524);HEAPU32[this.socketEvent>>>2>>>0]=socketId;return this.socketEvent}};Module["WS"]=WS;function _emscripten_websocket_get_ready_state(socketId,readyState){readyState>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}HEAP16[readyState>>>1>>>0]=socket.readyState;return 0}Module["_emscripten_websocket_get_ready_state"]=_emscripten_websocket_get_ready_state;_emscripten_websocket_get_ready_state.sig="iip";function _emscripten_websocket_get_buffered_amount(socketId,bufferedAmount){bufferedAmount>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}HEAPU32[bufferedAmount>>>2>>>0]=socket.bufferedAmount;return 0}Module["_emscripten_websocket_get_buffered_amount"]=_emscripten_websocket_get_buffered_amount;_emscripten_websocket_get_buffered_amount.sig="iip";function _emscripten_websocket_get_extensions(socketId,extensions,extensionsLength){extensions>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!extensions)return-5;stringToUTF8(socket.extensions,extensions,extensionsLength);return 0}Module["_emscripten_websocket_get_extensions"]=_emscripten_websocket_get_extensions;_emscripten_websocket_get_extensions.sig="iipi";function _emscripten_websocket_get_extensions_length(socketId,extensionsLength){extensionsLength>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!extensionsLength)return-5;HEAP32[extensionsLength>>>2>>>0]=lengthBytesUTF8(socket.extensions)+1;return 0}Module["_emscripten_websocket_get_extensions_length"]=_emscripten_websocket_get_extensions_length;_emscripten_websocket_get_extensions_length.sig="iip";function _emscripten_websocket_get_protocol(socketId,protocol,protocolLength){protocol>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!protocol)return-5;stringToUTF8(socket.protocol,protocol,protocolLength);return 0}Module["_emscripten_websocket_get_protocol"]=_emscripten_websocket_get_protocol;_emscripten_websocket_get_protocol.sig="iipi";function _emscripten_websocket_get_protocol_length(socketId,protocolLength){protocolLength>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!protocolLength)return-5;HEAP32[protocolLength>>>2>>>0]=lengthBytesUTF8(socket.protocol)+1;return 0}Module["_emscripten_websocket_get_protocol_length"]=_emscripten_websocket_get_protocol_length;_emscripten_websocket_get_protocol_length.sig="iip";function _emscripten_websocket_get_url(socketId,url,urlLength){url>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!url)return-5;stringToUTF8(socket.url,url,urlLength);return 0}Module["_emscripten_websocket_get_url"]=_emscripten_websocket_get_url;_emscripten_websocket_get_url.sig="iipi";function _emscripten_websocket_get_url_length(socketId,urlLength){urlLength>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!urlLength)return-5;HEAP32[urlLength>>>2>>>0]=lengthBytesUTF8(socket.url)+1;return 0}Module["_emscripten_websocket_get_url_length"]=_emscripten_websocket_get_url_length;_emscripten_websocket_get_url_length.sig="iip";function _emscripten_websocket_set_onopen_callback_on_thread(socketId,userData,callbackFunc,thread){userData>>>=0;callbackFunc>>>=0;thread>>>=0;var eventPtr=WS.getSocketEvent(socketId);var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onopen=function(e){getWasmTableEntry(callbackFunc)(0,eventPtr,userData)};return 0}Module["_emscripten_websocket_set_onopen_callback_on_thread"]=_emscripten_websocket_set_onopen_callback_on_thread;_emscripten_websocket_set_onopen_callback_on_thread.sig="iippp";function _emscripten_websocket_set_onerror_callback_on_thread(socketId,userData,callbackFunc,thread){userData>>>=0;callbackFunc>>>=0;thread>>>=0;var eventPtr=WS.getSocketEvent(socketId);var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onerror=function(e){getWasmTableEntry(callbackFunc)(0,eventPtr,userData)};return 0}Module["_emscripten_websocket_set_onerror_callback_on_thread"]=_emscripten_websocket_set_onerror_callback_on_thread;_emscripten_websocket_set_onerror_callback_on_thread.sig="iippp";function _emscripten_websocket_set_onclose_callback_on_thread(socketId,userData,callbackFunc,thread){userData>>>=0;callbackFunc>>>=0;thread>>>=0;var eventPtr=WS.getSocketEvent(socketId);var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onclose=function(e){HEAP32[eventPtr+4>>>2>>>0]=e.wasClean,HEAP16[eventPtr+4>>>1>>>0]=e.code,stringToUTF8(e.reason,eventPtr+10,512);getWasmTableEntry(callbackFunc)(0,eventPtr,userData)};return 0}Module["_emscripten_websocket_set_onclose_callback_on_thread"]=_emscripten_websocket_set_onclose_callback_on_thread;_emscripten_websocket_set_onclose_callback_on_thread.sig="iippp";function _emscripten_websocket_set_onmessage_callback_on_thread(socketId,userData,callbackFunc,thread){userData>>>=0;callbackFunc>>>=0;thread>>>=0;var eventPtr=WS.getSocketEvent(socketId);var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onmessage=function(e){var isText=typeof e.data=="string";if(isText){var buf=stringToNewUTF8(e.data);var len=lengthBytesUTF8(e.data)+1}else{var len=e.data.byteLength;var buf=_malloc(len);HEAP8.set(new Uint8Array(e.data),buf>>>0)}HEAPU32[eventPtr+4>>>2>>>0]=buf,HEAP32[eventPtr+8>>>2>>>0]=len,HEAP32[eventPtr+12>>>2>>>0]=isText,getWasmTableEntry(callbackFunc)(0,eventPtr,userData);_free(buf)};return 0}Module["_emscripten_websocket_set_onmessage_callback_on_thread"]=_emscripten_websocket_set_onmessage_callback_on_thread;_emscripten_websocket_set_onmessage_callback_on_thread.sig="iippp";function _emscripten_websocket_new(createAttributes){createAttributes>>>=0;if(typeof WebSocket=="undefined"){return-1}if(!createAttributes){return-5}var url=UTF8ToString(HEAPU32[createAttributes>>>2>>>0]);var protocols=HEAPU32[createAttributes+4>>>2>>>0];var socket=protocols?new WebSocket(url,UTF8ToString(protocols).split(",")):new WebSocket(url);socket.binaryType="arraybuffer";var socketId=webSockets.allocate(socket);return socketId}Module["_emscripten_websocket_new"]=_emscripten_websocket_new;_emscripten_websocket_new.sig="ip";function _emscripten_websocket_send_utf8_text(socketId,textData){textData>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}var str=UTF8ToString(textData);socket.send(str);return 0}Module["_emscripten_websocket_send_utf8_text"]=_emscripten_websocket_send_utf8_text;_emscripten_websocket_send_utf8_text.sig="iip";function _emscripten_websocket_send_binary(socketId,binaryData,dataLength){binaryData>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}socket.send(HEAPU8.subarray(binaryData>>>0,binaryData+dataLength>>>0));return 0}Module["_emscripten_websocket_send_binary"]=_emscripten_websocket_send_binary;_emscripten_websocket_send_binary.sig="iipi";function _emscripten_websocket_close(socketId,code,reason){reason>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}var reasonStr=reason?UTF8ToString(reason):undefined;if(reason)socket.close(code||undefined,UTF8ToString(reason));else if(code)socket.close(code);else socket.close();return 0}Module["_emscripten_websocket_close"]=_emscripten_websocket_close;_emscripten_websocket_close.sig="iiip";var _emscripten_websocket_delete=socketId=>{var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onopen=socket.onerror=socket.onclose=socket.onmessage=null;webSockets.free(socketId);return 0};Module["_emscripten_websocket_delete"]=_emscripten_websocket_delete;_emscripten_websocket_delete.sig="ii";var _emscripten_websocket_is_supported=()=>typeof WebSocket!="undefined";Module["_emscripten_websocket_is_supported"]=_emscripten_websocket_is_supported;_emscripten_websocket_is_supported.sig="i";var _emscripten_websocket_deinitialize=()=>{for(var i in WS.sockets){var socket=WS.sockets[i];if(socket){socket.close();_emscripten_websocket_delete(i)}}WS.sockets=[]};Module["_emscripten_websocket_deinitialize"]=_emscripten_websocket_deinitialize;_emscripten_websocket_deinitialize.sig="v";function _emscripten_webgl_enable_ANGLE_instanced_arrays(ctx){ctx>>>=0;return webgl_enable_ANGLE_instanced_arrays(GL.contexts[ctx].GLctx)}Module["_emscripten_webgl_enable_ANGLE_instanced_arrays"]=_emscripten_webgl_enable_ANGLE_instanced_arrays;_emscripten_webgl_enable_ANGLE_instanced_arrays.sig="ip";function _emscripten_webgl_enable_OES_vertex_array_object(ctx){ctx>>>=0;return webgl_enable_OES_vertex_array_object(GL.contexts[ctx].GLctx)}Module["_emscripten_webgl_enable_OES_vertex_array_object"]=_emscripten_webgl_enable_OES_vertex_array_object;_emscripten_webgl_enable_OES_vertex_array_object.sig="ip";function _emscripten_webgl_enable_WEBGL_draw_buffers(ctx){ctx>>>=0;return webgl_enable_WEBGL_draw_buffers(GL.contexts[ctx].GLctx)}Module["_emscripten_webgl_enable_WEBGL_draw_buffers"]=_emscripten_webgl_enable_WEBGL_draw_buffers;_emscripten_webgl_enable_WEBGL_draw_buffers.sig="ip";function _emscripten_webgl_enable_WEBGL_multi_draw(ctx){ctx>>>=0;return webgl_enable_WEBGL_multi_draw(GL.contexts[ctx].GLctx)}Module["_emscripten_webgl_enable_WEBGL_multi_draw"]=_emscripten_webgl_enable_WEBGL_multi_draw;_emscripten_webgl_enable_WEBGL_multi_draw.sig="ip";function _glVertexPointer(size,type,stride,ptr){ptr>>>=0;throw"Legacy GL function (glVertexPointer) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation."}Module["_glVertexPointer"]=_glVertexPointer;_glVertexPointer.sig="viiip";var _glMatrixMode=()=>{throw"Legacy GL function (glMatrixMode) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation."};Module["_glMatrixMode"]=_glMatrixMode;_glMatrixMode.sig="vi";var _glBegin=()=>{throw"Legacy GL function (glBegin) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation."};Module["_glBegin"]=_glBegin;_glBegin.sig="vi";var _glLoadIdentity=()=>{throw"Legacy GL function (glLoadIdentity) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation."};Module["_glLoadIdentity"]=_glLoadIdentity;_glLoadIdentity.sig="v";var _glVertexAttribDivisorNV=_glVertexAttribDivisor;Module["_glVertexAttribDivisorNV"]=_glVertexAttribDivisorNV;var _glDrawArraysInstancedNV=_glDrawArraysInstanced;Module["_glDrawArraysInstancedNV"]=_glDrawArraysInstancedNV;var _glDrawElementsInstancedNV=_glDrawElementsInstanced;Module["_glDrawElementsInstancedNV"]=_glDrawElementsInstancedNV;var _glVertexAttribDivisorEXT=_glVertexAttribDivisor;Module["_glVertexAttribDivisorEXT"]=_glVertexAttribDivisorEXT;var _glDrawArraysInstancedEXT=_glDrawArraysInstanced;Module["_glDrawArraysInstancedEXT"]=_glDrawArraysInstancedEXT;var _glDrawElementsInstancedEXT=_glDrawElementsInstanced;Module["_glDrawElementsInstancedEXT"]=_glDrawElementsInstancedEXT;var _glVertexAttribDivisorARB=_glVertexAttribDivisor;Module["_glVertexAttribDivisorARB"]=_glVertexAttribDivisorARB;var _glDrawArraysInstancedARB=_glDrawArraysInstanced;Module["_glDrawArraysInstancedARB"]=_glDrawArraysInstancedARB;var _glDrawElementsInstancedARB=_glDrawElementsInstanced;Module["_glDrawElementsInstancedARB"]=_glDrawElementsInstancedARB;var _glDrawBuffersEXT=_glDrawBuffers;Module["_glDrawBuffersEXT"]=_glDrawBuffersEXT;function _glMultiDrawArraysWEBGL(mode,firsts,counts,drawcount){firsts>>>=0;counts>>>=0;GLctx.multiDrawWebgl["multiDrawArraysWEBGL"](mode,HEAP32,firsts>>>2,HEAP32,counts>>>2,drawcount)}Module["_glMultiDrawArraysWEBGL"]=_glMultiDrawArraysWEBGL;_glMultiDrawArraysWEBGL.sig="vippi";var _glMultiDrawArrays=_glMultiDrawArraysWEBGL;Module["_glMultiDrawArrays"]=_glMultiDrawArrays;_glMultiDrawArrays.sig="vippi";var _glMultiDrawArraysANGLE=_glMultiDrawArraysWEBGL;Module["_glMultiDrawArraysANGLE"]=_glMultiDrawArraysANGLE;function _glMultiDrawArraysInstancedWEBGL(mode,firsts,counts,instanceCounts,drawcount){firsts>>>=0;counts>>>=0;instanceCounts>>>=0;GLctx.multiDrawWebgl["multiDrawArraysInstancedWEBGL"](mode,HEAP32,firsts>>>2,HEAP32,counts>>>2,HEAP32,instanceCounts>>>2,drawcount)}Module["_glMultiDrawArraysInstancedWEBGL"]=_glMultiDrawArraysInstancedWEBGL;_glMultiDrawArraysInstancedWEBGL.sig="vipppi";var _glMultiDrawArraysInstancedANGLE=_glMultiDrawArraysInstancedWEBGL;Module["_glMultiDrawArraysInstancedANGLE"]=_glMultiDrawArraysInstancedANGLE;function _glMultiDrawElementsWEBGL(mode,counts,type,offsets,drawcount){counts>>>=0;offsets>>>=0;GLctx.multiDrawWebgl["multiDrawElementsWEBGL"](mode,HEAP32,counts>>>2,type,HEAP32,offsets>>>2,drawcount)}Module["_glMultiDrawElementsWEBGL"]=_glMultiDrawElementsWEBGL;_glMultiDrawElementsWEBGL.sig="vipipi";var _glMultiDrawElements=_glMultiDrawElementsWEBGL;Module["_glMultiDrawElements"]=_glMultiDrawElements;_glMultiDrawElements.sig="vipipi";var _glMultiDrawElementsANGLE=_glMultiDrawElementsWEBGL;Module["_glMultiDrawElementsANGLE"]=_glMultiDrawElementsANGLE;function _glMultiDrawElementsInstancedWEBGL(mode,counts,type,offsets,instanceCounts,drawcount){counts>>>=0;offsets>>>=0;instanceCounts>>>=0;GLctx.multiDrawWebgl["multiDrawElementsInstancedWEBGL"](mode,HEAP32,counts>>>2,type,HEAP32,offsets>>>2,HEAP32,instanceCounts>>>2,drawcount)}Module["_glMultiDrawElementsInstancedWEBGL"]=_glMultiDrawElementsInstancedWEBGL;_glMultiDrawElementsInstancedWEBGL.sig="vipippi";var _glMultiDrawElementsInstancedANGLE=_glMultiDrawElementsInstancedWEBGL;Module["_glMultiDrawElementsInstancedANGLE"]=_glMultiDrawElementsInstancedANGLE;var _glClearDepth=x0=>GLctx.clearDepth(x0);Module["_glClearDepth"]=_glClearDepth;_glClearDepth.sig="vd";var _glDepthRange=(x0,x1)=>GLctx.depthRange(x0,x1);Module["_glDepthRange"]=_glDepthRange;_glDepthRange.sig="vdd";var _emscripten_glGenVertexArrays=_glGenVertexArrays;Module["_emscripten_glGenVertexArrays"]=_emscripten_glGenVertexArrays;_emscripten_glGenVertexArrays.sig="vip";var _emscripten_glDeleteVertexArrays=_glDeleteVertexArrays;Module["_emscripten_glDeleteVertexArrays"]=_emscripten_glDeleteVertexArrays;_emscripten_glDeleteVertexArrays.sig="vip";var _emscripten_glBindVertexArray=_glBindVertexArray;Module["_emscripten_glBindVertexArray"]=_emscripten_glBindVertexArray;_emscripten_glBindVertexArray.sig="vi";var _emscripten_glIsVertexArray=_glIsVertexArray;Module["_emscripten_glIsVertexArray"]=_emscripten_glIsVertexArray;_emscripten_glIsVertexArray.sig="ii";var _emscripten_glVertexPointer=_glVertexPointer;Module["_emscripten_glVertexPointer"]=_emscripten_glVertexPointer;_emscripten_glVertexPointer.sig="viiip";var _emscripten_glMatrixMode=_glMatrixMode;Module["_emscripten_glMatrixMode"]=_emscripten_glMatrixMode;_emscripten_glMatrixMode.sig="vi";var _emscripten_glBegin=_glBegin;Module["_emscripten_glBegin"]=_emscripten_glBegin;_emscripten_glBegin.sig="vi";var _emscripten_glLoadIdentity=_glLoadIdentity;Module["_emscripten_glLoadIdentity"]=_emscripten_glLoadIdentity;_emscripten_glLoadIdentity.sig="v";var _emscripten_glVertexAttribDivisor=_glVertexAttribDivisor;Module["_emscripten_glVertexAttribDivisor"]=_emscripten_glVertexAttribDivisor;_emscripten_glVertexAttribDivisor.sig="vii";var _emscripten_glDrawArraysInstanced=_glDrawArraysInstanced;Module["_emscripten_glDrawArraysInstanced"]=_emscripten_glDrawArraysInstanced;_emscripten_glDrawArraysInstanced.sig="viiii";var _emscripten_glDrawElementsInstanced=_glDrawElementsInstanced;Module["_emscripten_glDrawElementsInstanced"]=_emscripten_glDrawElementsInstanced;_emscripten_glDrawElementsInstanced.sig="viiipi";var _emscripten_glVertexAttribDivisorNV=_glVertexAttribDivisorNV;Module["_emscripten_glVertexAttribDivisorNV"]=_emscripten_glVertexAttribDivisorNV;var _emscripten_glDrawArraysInstancedNV=_glDrawArraysInstancedNV;Module["_emscripten_glDrawArraysInstancedNV"]=_emscripten_glDrawArraysInstancedNV;var _emscripten_glDrawElementsInstancedNV=_glDrawElementsInstancedNV;Module["_emscripten_glDrawElementsInstancedNV"]=_emscripten_glDrawElementsInstancedNV;var _emscripten_glVertexAttribDivisorEXT=_glVertexAttribDivisorEXT;Module["_emscripten_glVertexAttribDivisorEXT"]=_emscripten_glVertexAttribDivisorEXT;var _emscripten_glDrawArraysInstancedEXT=_glDrawArraysInstancedEXT;Module["_emscripten_glDrawArraysInstancedEXT"]=_emscripten_glDrawArraysInstancedEXT;var _emscripten_glDrawElementsInstancedEXT=_glDrawElementsInstancedEXT;Module["_emscripten_glDrawElementsInstancedEXT"]=_emscripten_glDrawElementsInstancedEXT;var _emscripten_glVertexAttribDivisorARB=_glVertexAttribDivisorARB;Module["_emscripten_glVertexAttribDivisorARB"]=_emscripten_glVertexAttribDivisorARB;var _emscripten_glDrawArraysInstancedARB=_glDrawArraysInstancedARB;Module["_emscripten_glDrawArraysInstancedARB"]=_emscripten_glDrawArraysInstancedARB;var _emscripten_glDrawElementsInstancedARB=_glDrawElementsInstancedARB;Module["_emscripten_glDrawElementsInstancedARB"]=_emscripten_glDrawElementsInstancedARB;var _emscripten_glDrawBuffers=_glDrawBuffers;Module["_emscripten_glDrawBuffers"]=_emscripten_glDrawBuffers;_emscripten_glDrawBuffers.sig="vip";var _emscripten_glDrawBuffersEXT=_glDrawBuffersEXT;Module["_emscripten_glDrawBuffersEXT"]=_emscripten_glDrawBuffersEXT;var _emscripten_glMultiDrawArrays=_glMultiDrawArrays;Module["_emscripten_glMultiDrawArrays"]=_emscripten_glMultiDrawArrays;_emscripten_glMultiDrawArrays.sig="vippi";var _emscripten_glMultiDrawArraysANGLE=_glMultiDrawArraysANGLE;Module["_emscripten_glMultiDrawArraysANGLE"]=_emscripten_glMultiDrawArraysANGLE;var _emscripten_glMultiDrawArraysWEBGL=_glMultiDrawArraysWEBGL;Module["_emscripten_glMultiDrawArraysWEBGL"]=_emscripten_glMultiDrawArraysWEBGL;var _emscripten_glMultiDrawArraysInstancedANGLE=_glMultiDrawArraysInstancedANGLE;Module["_emscripten_glMultiDrawArraysInstancedANGLE"]=_emscripten_glMultiDrawArraysInstancedANGLE;var _emscripten_glMultiDrawArraysInstancedWEBGL=_glMultiDrawArraysInstancedWEBGL;Module["_emscripten_glMultiDrawArraysInstancedWEBGL"]=_emscripten_glMultiDrawArraysInstancedWEBGL;var _emscripten_glMultiDrawElements=_glMultiDrawElements;Module["_emscripten_glMultiDrawElements"]=_emscripten_glMultiDrawElements;_emscripten_glMultiDrawElements.sig="vipipi";var _emscripten_glMultiDrawElementsANGLE=_glMultiDrawElementsANGLE;Module["_emscripten_glMultiDrawElementsANGLE"]=_emscripten_glMultiDrawElementsANGLE;var _emscripten_glMultiDrawElementsWEBGL=_glMultiDrawElementsWEBGL;Module["_emscripten_glMultiDrawElementsWEBGL"]=_emscripten_glMultiDrawElementsWEBGL;var _emscripten_glMultiDrawElementsInstancedANGLE=_glMultiDrawElementsInstancedANGLE;Module["_emscripten_glMultiDrawElementsInstancedANGLE"]=_emscripten_glMultiDrawElementsInstancedANGLE;var _emscripten_glMultiDrawElementsInstancedWEBGL=_glMultiDrawElementsInstancedWEBGL;Module["_emscripten_glMultiDrawElementsInstancedWEBGL"]=_emscripten_glMultiDrawElementsInstancedWEBGL;var _emscripten_glClearDepth=_glClearDepth;Module["_emscripten_glClearDepth"]=_emscripten_glClearDepth;_emscripten_glClearDepth.sig="vd";var _emscripten_glDepthRange=_glDepthRange;Module["_emscripten_glDepthRange"]=_emscripten_glDepthRange;_emscripten_glDepthRange.sig="vdd";var writeGLArray=(arr,dst,dstLength,heapType)=>{var len=arr.length;var writeLength=dstLength>>2;for(var i=0;i>>0]=arr[i]}return len};Module["writeGLArray"]=writeGLArray;var webglPowerPreferences=["default","low-power","high-performance"];Module["webglPowerPreferences"]=webglPowerPreferences;function _emscripten_webgl_do_create_context(target,attributes){target>>>=0;attributes>>>=0;var a=attributes>>>2;var powerPreference=HEAP32[a+(24>>2)>>>0];var contextAttributes={"alpha":!!HEAP32[a+(0>>2)>>>0],"depth":!!HEAP32[a+(4>>2)>>>0],"stencil":!!HEAP32[a+(8>>2)>>>0],"antialias":!!HEAP32[a+(12>>2)>>>0],"premultipliedAlpha":!!HEAP32[a+(16>>2)>>>0],"preserveDrawingBuffer":!!HEAP32[a+(20>>2)>>>0],"powerPreference":webglPowerPreferences[powerPreference],"failIfMajorPerformanceCaveat":!!HEAP32[a+(28>>2)>>>0],majorVersion:HEAP32[a+(32>>2)>>>0],minorVersion:HEAP32[a+(36>>2)>>>0],enableExtensionsByDefault:HEAP32[a+(40>>2)>>>0],explicitSwapControl:HEAP32[a+(44>>2)>>>0],proxyContextToMainThread:HEAP32[a+(48>>2)>>>0],renderViaOffscreenBackBuffer:HEAP32[a+(52>>2)>>>0]};var canvas=findCanvasEventTarget(target);if(!canvas){return 0}if(contextAttributes.explicitSwapControl){return 0}var contextHandle=GL.createContext(canvas,contextAttributes);return contextHandle}Module["_emscripten_webgl_do_create_context"]=_emscripten_webgl_do_create_context;_emscripten_webgl_do_create_context.sig="ppp";var _emscripten_webgl_create_context=_emscripten_webgl_do_create_context;Module["_emscripten_webgl_create_context"]=_emscripten_webgl_create_context;_emscripten_webgl_create_context.sig="ppp";function _emscripten_webgl_do_get_current_context(){return GL.currentContext?GL.currentContext.handle:0}Module["_emscripten_webgl_do_get_current_context"]=_emscripten_webgl_do_get_current_context;_emscripten_webgl_do_get_current_context.sig="p";var _emscripten_webgl_get_current_context=_emscripten_webgl_do_get_current_context;Module["_emscripten_webgl_get_current_context"]=_emscripten_webgl_get_current_context;_emscripten_webgl_get_current_context.sig="p";var _emscripten_webgl_do_commit_frame=()=>{if(!GL.currentContext||!GL.currentContext.GLctx){return-3}if(!GL.currentContext.attributes.explicitSwapControl){return-3}return 0};Module["_emscripten_webgl_do_commit_frame"]=_emscripten_webgl_do_commit_frame;_emscripten_webgl_do_commit_frame.sig="i";var _emscripten_webgl_commit_frame=_emscripten_webgl_do_commit_frame;Module["_emscripten_webgl_commit_frame"]=_emscripten_webgl_commit_frame;_emscripten_webgl_commit_frame.sig="i";function _emscripten_webgl_make_context_current(contextHandle){contextHandle>>>=0;var success=GL.makeContextCurrent(contextHandle);return success?0:-5}Module["_emscripten_webgl_make_context_current"]=_emscripten_webgl_make_context_current;_emscripten_webgl_make_context_current.sig="ip";function _emscripten_webgl_get_drawing_buffer_size(contextHandle,width,height){contextHandle>>>=0;width>>>=0;height>>>=0;var GLContext=GL.getContext(contextHandle);if(!GLContext||!GLContext.GLctx||!width||!height){return-5}HEAP32[width>>>2>>>0]=GLContext.GLctx.drawingBufferWidth;HEAP32[height>>>2>>>0]=GLContext.GLctx.drawingBufferHeight;return 0}Module["_emscripten_webgl_get_drawing_buffer_size"]=_emscripten_webgl_get_drawing_buffer_size;_emscripten_webgl_get_drawing_buffer_size.sig="ippp";function _emscripten_webgl_get_context_attributes(c,a){c>>>=0;a>>>=0;if(!a)return-5;c=GL.contexts[c];if(!c)return-3;var t=c.GLctx;if(!t)return-3;t=t.getContextAttributes();HEAP32[a>>>2>>>0]=t.alpha;HEAP32[a+4>>>2>>>0]=t.depth;HEAP32[a+8>>>2>>>0]=t.stencil;HEAP32[a+12>>>2>>>0]=t.antialias;HEAP32[a+16>>>2>>>0]=t.premultipliedAlpha;HEAP32[a+20>>>2>>>0]=t.preserveDrawingBuffer;var power=t["powerPreference"]&&webglPowerPreferences.indexOf(t["powerPreference"]);HEAP32[a+24>>>2>>>0]=power;HEAP32[a+28>>>2>>>0]=t.failIfMajorPerformanceCaveat;HEAP32[a+32>>>2>>>0]=c.version;HEAP32[a+36>>>2>>>0]=0;HEAP32[a+40>>>2>>>0]=c.attributes.enableExtensionsByDefault;return 0}Module["_emscripten_webgl_get_context_attributes"]=_emscripten_webgl_get_context_attributes;_emscripten_webgl_get_context_attributes.sig="ipp";function _emscripten_webgl_destroy_context(contextHandle){contextHandle>>>=0;if(GL.currentContext==contextHandle)GL.currentContext=0;GL.deleteContext(contextHandle)}Module["_emscripten_webgl_destroy_context"]=_emscripten_webgl_destroy_context;_emscripten_webgl_destroy_context.sig="ip";function _emscripten_webgl_enable_extension(contextHandle,extension){contextHandle>>>=0;extension>>>=0;var context=GL.getContext(contextHandle);var extString=UTF8ToString(extension);if(extString.startsWith("GL_"))extString=extString.substr(3);if(extString=="ANGLE_instanced_arrays")webgl_enable_ANGLE_instanced_arrays(GLctx);if(extString=="OES_vertex_array_object")webgl_enable_OES_vertex_array_object(GLctx);if(extString=="WEBGL_draw_buffers")webgl_enable_WEBGL_draw_buffers(GLctx);if(extString=="WEBGL_multi_draw")webgl_enable_WEBGL_multi_draw(GLctx);var ext=context.GLctx.getExtension(extString);return!!ext}Module["_emscripten_webgl_enable_extension"]=_emscripten_webgl_enable_extension;_emscripten_webgl_enable_extension.sig="ipp";var _emscripten_supports_offscreencanvas=()=>0;Module["_emscripten_supports_offscreencanvas"]=_emscripten_supports_offscreencanvas;_emscripten_supports_offscreencanvas.sig="i";var registerWebGlEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{var webGlEventHandlerFunc=(e=event)=>{if(getWasmTableEntry(callbackfunc)(eventTypeId,0,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:webGlEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerWebGlEventCallback"]=registerWebGlEventCallback;function _emscripten_set_webglcontextlost_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;registerWebGlEventCallback(target,userData,useCapture,callbackfunc,31,"webglcontextlost",targetThread);return 0}Module["_emscripten_set_webglcontextlost_callback_on_thread"]=_emscripten_set_webglcontextlost_callback_on_thread;_emscripten_set_webglcontextlost_callback_on_thread.sig="ippipp";function _emscripten_set_webglcontextrestored_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;registerWebGlEventCallback(target,userData,useCapture,callbackfunc,32,"webglcontextrestored",targetThread);return 0}Module["_emscripten_set_webglcontextrestored_callback_on_thread"]=_emscripten_set_webglcontextrestored_callback_on_thread;_emscripten_set_webglcontextrestored_callback_on_thread.sig="ippipp";function _emscripten_is_webgl_context_lost(contextHandle){contextHandle>>>=0;return!GL.contexts[contextHandle]||GL.contexts[contextHandle].GLctx.isContextLost()}Module["_emscripten_is_webgl_context_lost"]=_emscripten_is_webgl_context_lost;_emscripten_is_webgl_context_lost.sig="ip";function _emscripten_webgl_get_supported_extensions(){return stringToNewUTF8(GLctx.getSupportedExtensions().join(" "))}Module["_emscripten_webgl_get_supported_extensions"]=_emscripten_webgl_get_supported_extensions;_emscripten_webgl_get_supported_extensions.sig="p";var _emscripten_webgl_get_program_parameter_d=(program,param)=>GLctx.getProgramParameter(GL.programs[program],param);Module["_emscripten_webgl_get_program_parameter_d"]=_emscripten_webgl_get_program_parameter_d;_emscripten_webgl_get_program_parameter_d.sig="dii";function _emscripten_webgl_get_program_info_log_utf8(program){return stringToNewUTF8(GLctx.getProgramInfoLog(GL.programs[program]))}Module["_emscripten_webgl_get_program_info_log_utf8"]=_emscripten_webgl_get_program_info_log_utf8;_emscripten_webgl_get_program_info_log_utf8.sig="pi";var _emscripten_webgl_get_shader_parameter_d=(shader,param)=>GLctx.getShaderParameter(GL.shaders[shader],param);Module["_emscripten_webgl_get_shader_parameter_d"]=_emscripten_webgl_get_shader_parameter_d;_emscripten_webgl_get_shader_parameter_d.sig="dii";function _emscripten_webgl_get_shader_info_log_utf8(shader){return stringToNewUTF8(GLctx.getShaderInfoLog(GL.shaders[shader]))}Module["_emscripten_webgl_get_shader_info_log_utf8"]=_emscripten_webgl_get_shader_info_log_utf8;_emscripten_webgl_get_shader_info_log_utf8.sig="pi";function _emscripten_webgl_get_shader_source_utf8(shader){return stringToNewUTF8(GLctx.getShaderSource(GL.shaders[shader]))}Module["_emscripten_webgl_get_shader_source_utf8"]=_emscripten_webgl_get_shader_source_utf8;_emscripten_webgl_get_shader_source_utf8.sig="pi";var _emscripten_webgl_get_vertex_attrib_d=(index,param)=>GLctx.getVertexAttrib(index,param);Module["_emscripten_webgl_get_vertex_attrib_d"]=_emscripten_webgl_get_vertex_attrib_d;_emscripten_webgl_get_vertex_attrib_d.sig="dii";var _emscripten_webgl_get_vertex_attrib_o=(index,param)=>{var obj=GLctx.getVertexAttrib(index,param);return obj?.name};Module["_emscripten_webgl_get_vertex_attrib_o"]=_emscripten_webgl_get_vertex_attrib_o;_emscripten_webgl_get_vertex_attrib_o.sig="iii";function _emscripten_webgl_get_vertex_attrib_v(index,param,dst,dstLength,dstType){dst>>>=0;return writeGLArray(GLctx.getVertexAttrib(index,param),dst,dstLength,dstType)}Module["_emscripten_webgl_get_vertex_attrib_v"]=_emscripten_webgl_get_vertex_attrib_v;_emscripten_webgl_get_vertex_attrib_v.sig="iiipii";var _emscripten_webgl_get_uniform_d=(program,location)=>GLctx.getUniform(GL.programs[program],webglGetUniformLocation(location));Module["_emscripten_webgl_get_uniform_d"]=_emscripten_webgl_get_uniform_d;_emscripten_webgl_get_uniform_d.sig="dii";function _emscripten_webgl_get_uniform_v(program,location,dst,dstLength,dstType){dst>>>=0;return writeGLArray(GLctx.getUniform(GL.programs[program],webglGetUniformLocation(location)),dst,dstLength,dstType)}Module["_emscripten_webgl_get_uniform_v"]=_emscripten_webgl_get_uniform_v;_emscripten_webgl_get_uniform_v.sig="iiipii";function _emscripten_webgl_get_parameter_v(param,dst,dstLength,dstType){dst>>>=0;return writeGLArray(GLctx.getParameter(param),dst,dstLength,dstType)}Module["_emscripten_webgl_get_parameter_v"]=_emscripten_webgl_get_parameter_v;_emscripten_webgl_get_parameter_v.sig="iipii";var _emscripten_webgl_get_parameter_d=param=>GLctx.getParameter(param);Module["_emscripten_webgl_get_parameter_d"]=_emscripten_webgl_get_parameter_d;_emscripten_webgl_get_parameter_d.sig="di";var _emscripten_webgl_get_parameter_o=param=>{var obj=GLctx.getParameter(param);return obj?.name};Module["_emscripten_webgl_get_parameter_o"]=_emscripten_webgl_get_parameter_o;_emscripten_webgl_get_parameter_o.sig="ii";function _emscripten_webgl_get_parameter_utf8(param){return stringToNewUTF8(GLctx.getParameter(param))}Module["_emscripten_webgl_get_parameter_utf8"]=_emscripten_webgl_get_parameter_utf8;_emscripten_webgl_get_parameter_utf8.sig="pi";function _emscripten_webgl_get_parameter_i64v(param,dst){dst>>>=0;return writeI53ToI64(dst,GLctx.getParameter(param))}Module["_emscripten_webgl_get_parameter_i64v"]=_emscripten_webgl_get_parameter_i64v;_emscripten_webgl_get_parameter_i64v.sig="vip";var EGL={errorCode:12288,defaultDisplayInitialized:false,currentContext:0,currentReadSurface:0,currentDrawSurface:0,contextAttributes:{alpha:false,depth:false,stencil:false,antialias:false},stringCache:{},setErrorCode(code){EGL.errorCode=code},chooseConfig(display,attribList,config,config_size,numConfigs){if(display!=62e3){EGL.setErrorCode(12296);return 0}if(attribList){for(;;){var param=HEAP32[attribList>>>2>>>0];if(param==12321){var alphaSize=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.alpha=alphaSize>0}else if(param==12325){var depthSize=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.depth=depthSize>0}else if(param==12326){var stencilSize=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.stencil=stencilSize>0}else if(param==12337){var samples=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.antialias=samples>0}else if(param==12338){var samples=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.antialias=samples==1}else if(param==12544){var requestedPriority=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.lowLatency=requestedPriority!=12547}else if(param==12344){break}attribList+=8}}if((!config||!config_size)&&!numConfigs){EGL.setErrorCode(12300);return 0}if(numConfigs){HEAP32[numConfigs>>>2>>>0]=1}if(config&&config_size>0){HEAPU32[config>>>2>>>0]=62002}EGL.setErrorCode(12288);return 1}};Module["EGL"]=EGL;function _eglGetDisplay(nativeDisplayType){nativeDisplayType>>>=0;EGL.setErrorCode(12288);if(nativeDisplayType!=0&&nativeDisplayType!=1){return 0}return 62e3}Module["_eglGetDisplay"]=_eglGetDisplay;_eglGetDisplay.sig="pp";function _eglInitialize(display,majorVersion,minorVersion){display>>>=0;majorVersion>>>=0;minorVersion>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(majorVersion){HEAP32[majorVersion>>>2>>>0]=1}if(minorVersion){HEAP32[minorVersion>>>2>>>0]=4}EGL.defaultDisplayInitialized=true;EGL.setErrorCode(12288);return 1}Module["_eglInitialize"]=_eglInitialize;_eglInitialize.sig="ippp";function _eglTerminate(display){display>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}EGL.currentContext=0;EGL.currentReadSurface=0;EGL.currentDrawSurface=0;EGL.defaultDisplayInitialized=false;EGL.setErrorCode(12288);return 1}Module["_eglTerminate"]=_eglTerminate;_eglTerminate.sig="ip";function _eglGetConfigs(display,configs,config_size,numConfigs){display>>>=0;configs>>>=0;numConfigs>>>=0;return EGL.chooseConfig(display,0,configs,config_size,numConfigs)}Module["_eglGetConfigs"]=_eglGetConfigs;_eglGetConfigs.sig="ippip";function _eglChooseConfig(display,attrib_list,configs,config_size,numConfigs){display>>>=0;attrib_list>>>=0;configs>>>=0;numConfigs>>>=0;return EGL.chooseConfig(display,attrib_list,configs,config_size,numConfigs)}Module["_eglChooseConfig"]=_eglChooseConfig;_eglChooseConfig.sig="ipppip";function _eglGetConfigAttrib(display,config,attribute,value){display>>>=0;config>>>=0;value>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(config!=62002){EGL.setErrorCode(12293);return 0}if(!value){EGL.setErrorCode(12300);return 0}EGL.setErrorCode(12288);switch(attribute){case 12320:HEAP32[value>>>2>>>0]=EGL.contextAttributes.alpha?32:24;return 1;case 12321:HEAP32[value>>>2>>>0]=EGL.contextAttributes.alpha?8:0;return 1;case 12322:HEAP32[value>>>2>>>0]=8;return 1;case 12323:HEAP32[value>>>2>>>0]=8;return 1;case 12324:HEAP32[value>>>2>>>0]=8;return 1;case 12325:HEAP32[value>>>2>>>0]=EGL.contextAttributes.depth?24:0;return 1;case 12326:HEAP32[value>>>2>>>0]=EGL.contextAttributes.stencil?8:0;return 1;case 12327:HEAP32[value>>>2>>>0]=12344;return 1;case 12328:HEAP32[value>>>2>>>0]=62002;return 1;case 12329:HEAP32[value>>>2>>>0]=0;return 1;case 12330:HEAP32[value>>>2>>>0]=4096;return 1;case 12331:HEAP32[value>>>2>>>0]=16777216;return 1;case 12332:HEAP32[value>>>2>>>0]=4096;return 1;case 12333:HEAP32[value>>>2>>>0]=0;return 1;case 12334:HEAP32[value>>>2>>>0]=0;return 1;case 12335:HEAP32[value>>>2>>>0]=12344;return 1;case 12337:HEAP32[value>>>2>>>0]=EGL.contextAttributes.antialias?4:0;return 1;case 12338:HEAP32[value>>>2>>>0]=EGL.contextAttributes.antialias?1:0;return 1;case 12339:HEAP32[value>>>2>>>0]=4;return 1;case 12340:HEAP32[value>>>2>>>0]=12344;return 1;case 12341:case 12342:case 12343:HEAP32[value>>>2>>>0]=-1;return 1;case 12345:case 12346:HEAP32[value>>>2>>>0]=0;return 1;case 12347:HEAP32[value>>>2>>>0]=0;return 1;case 12348:HEAP32[value>>>2>>>0]=1;return 1;case 12349:case 12350:HEAP32[value>>>2>>>0]=0;return 1;case 12351:HEAP32[value>>>2>>>0]=12430;return 1;case 12352:HEAP32[value>>>2>>>0]=4;return 1;case 12354:HEAP32[value>>>2>>>0]=0;return 1;default:EGL.setErrorCode(12292);return 0}}Module["_eglGetConfigAttrib"]=_eglGetConfigAttrib;_eglGetConfigAttrib.sig="ippip";function _eglCreateWindowSurface(display,config,win,attrib_list){display>>>=0;config>>>=0;attrib_list>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(config!=62002){EGL.setErrorCode(12293);return 0}EGL.setErrorCode(12288);return 62006}Module["_eglCreateWindowSurface"]=_eglCreateWindowSurface;_eglCreateWindowSurface.sig="pppip";function _eglDestroySurface(display,surface){display>>>=0;surface>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(surface!=62006){EGL.setErrorCode(12301);return 1}if(EGL.currentReadSurface==surface){EGL.currentReadSurface=0}if(EGL.currentDrawSurface==surface){EGL.currentDrawSurface=0}EGL.setErrorCode(12288);return 1}Module["_eglDestroySurface"]=_eglDestroySurface;_eglDestroySurface.sig="ipp";function _eglCreateContext(display,config,hmm,contextAttribs){display>>>=0;config>>>=0;hmm>>>=0;contextAttribs>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}var glesContextVersion=1;for(;;){var param=HEAP32[contextAttribs>>>2>>>0];if(param==12440){glesContextVersion=HEAP32[contextAttribs+4>>>2>>>0]}else if(param==12344){break}else{EGL.setErrorCode(12292);return 0}contextAttribs+=8}if(glesContextVersion!=2){EGL.setErrorCode(12293);return 0}EGL.contextAttributes.majorVersion=glesContextVersion-1;EGL.contextAttributes.minorVersion=0;EGL.context=GL.createContext(Module["canvas"],EGL.contextAttributes);if(EGL.context!=0){EGL.setErrorCode(12288);GL.makeContextCurrent(EGL.context);Module.useWebGL=true;Browser.moduleContextCreatedCallbacks.forEach(function(callback){callback()});GL.makeContextCurrent(null);return 62004}else{EGL.setErrorCode(12297);return 0}}Module["_eglCreateContext"]=_eglCreateContext;_eglCreateContext.sig="ppppp";function _eglDestroyContext(display,context){display>>>=0;context>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(context!=62004){EGL.setErrorCode(12294);return 0}GL.deleteContext(EGL.context);EGL.setErrorCode(12288);if(EGL.currentContext==context){EGL.currentContext=0}return 1}Module["_eglDestroyContext"]=_eglDestroyContext;_eglDestroyContext.sig="ipp";function _eglQuerySurface(display,surface,attribute,value){display>>>=0;surface>>>=0;value>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(surface!=62006){EGL.setErrorCode(12301);return 0}if(!value){EGL.setErrorCode(12300);return 0}EGL.setErrorCode(12288);switch(attribute){case 12328:HEAP32[value>>>2>>>0]=62002;return 1;case 12376:return 1;case 12375:HEAP32[value>>>2>>>0]=Module["canvas"].width;return 1;case 12374:HEAP32[value>>>2>>>0]=Module["canvas"].height;return 1;case 12432:HEAP32[value>>>2>>>0]=-1;return 1;case 12433:HEAP32[value>>>2>>>0]=-1;return 1;case 12434:HEAP32[value>>>2>>>0]=-1;return 1;case 12422:HEAP32[value>>>2>>>0]=12420;return 1;case 12441:HEAP32[value>>>2>>>0]=12442;return 1;case 12435:HEAP32[value>>>2>>>0]=12437;return 1;case 12416:case 12417:case 12418:case 12419:return 1;default:EGL.setErrorCode(12292);return 0}}Module["_eglQuerySurface"]=_eglQuerySurface;_eglQuerySurface.sig="ippip";function _eglQueryContext(display,context,attribute,value){display>>>=0;context>>>=0;value>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(context!=62004){EGL.setErrorCode(12294);return 0}if(!value){EGL.setErrorCode(12300);return 0}EGL.setErrorCode(12288);switch(attribute){case 12328:HEAP32[value>>>2>>>0]=62002;return 1;case 12439:HEAP32[value>>>2>>>0]=12448;return 1;case 12440:HEAP32[value>>>2>>>0]=EGL.contextAttributes.majorVersion+1;return 1;case 12422:HEAP32[value>>>2>>>0]=12420;return 1;default:EGL.setErrorCode(12292);return 0}}Module["_eglQueryContext"]=_eglQueryContext;_eglQueryContext.sig="ippip";var _eglGetError=()=>EGL.errorCode;Module["_eglGetError"]=_eglGetError;_eglGetError.sig="i";function _eglQueryString(display,name){display>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}EGL.setErrorCode(12288);if(EGL.stringCache[name])return EGL.stringCache[name];var ret;switch(name){case 12371:ret=stringToNewUTF8("Emscripten");break;case 12372:ret=stringToNewUTF8("1.4 Emscripten EGL");break;case 12373:ret=stringToNewUTF8("");break;case 12429:ret=stringToNewUTF8("OpenGL_ES");break;default:EGL.setErrorCode(12300);return 0}EGL.stringCache[name]=ret;return ret}Module["_eglQueryString"]=_eglQueryString;_eglQueryString.sig="ppi";var _eglBindAPI=api=>{if(api==12448){EGL.setErrorCode(12288);return 1}EGL.setErrorCode(12300);return 0};Module["_eglBindAPI"]=_eglBindAPI;_eglBindAPI.sig="ii";var _eglQueryAPI=()=>{EGL.setErrorCode(12288);return 12448};Module["_eglQueryAPI"]=_eglQueryAPI;_eglQueryAPI.sig="i";var _eglWaitClient=()=>{EGL.setErrorCode(12288);return 1};Module["_eglWaitClient"]=_eglWaitClient;_eglWaitClient.sig="i";var _eglWaitNative=nativeEngineId=>{EGL.setErrorCode(12288);return 1};Module["_eglWaitNative"]=_eglWaitNative;_eglWaitNative.sig="ii";var _eglWaitGL=_eglWaitClient;Module["_eglWaitGL"]=_eglWaitGL;_eglWaitGL.sig="i";function _eglSwapInterval(display,interval){display>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(interval==0)_emscripten_set_main_loop_timing(0,0);else _emscripten_set_main_loop_timing(1,interval);EGL.setErrorCode(12288);return 1}Module["_eglSwapInterval"]=_eglSwapInterval;_eglSwapInterval.sig="ipi";function _eglMakeCurrent(display,draw,read,context){display>>>=0;draw>>>=0;read>>>=0;context>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(context!=0&&context!=62004){EGL.setErrorCode(12294);return 0}if(read!=0&&read!=62006||draw!=0&&draw!=62006){EGL.setErrorCode(12301);return 0}GL.makeContextCurrent(context?EGL.context:null);EGL.currentContext=context;EGL.currentDrawSurface=draw;EGL.currentReadSurface=read;EGL.setErrorCode(12288);return 1}Module["_eglMakeCurrent"]=_eglMakeCurrent;_eglMakeCurrent.sig="ipppp";function _eglGetCurrentContext(){return EGL.currentContext}Module["_eglGetCurrentContext"]=_eglGetCurrentContext;_eglGetCurrentContext.sig="p";function _eglGetCurrentSurface(readdraw){if(readdraw==12378){return EGL.currentReadSurface}else if(readdraw==12377){return EGL.currentDrawSurface}else{EGL.setErrorCode(12300);return 0}}Module["_eglGetCurrentSurface"]=_eglGetCurrentSurface;_eglGetCurrentSurface.sig="pi";function _eglGetCurrentDisplay(){return EGL.currentContext?62e3:0}Module["_eglGetCurrentDisplay"]=_eglGetCurrentDisplay;_eglGetCurrentDisplay.sig="p";function _eglSwapBuffers(dpy,surface){dpy>>>=0;surface>>>=0;if(!EGL.defaultDisplayInitialized){EGL.setErrorCode(12289)}else if(!Module.ctx){EGL.setErrorCode(12290)}else if(Module.ctx.isContextLost()){EGL.setErrorCode(12302)}else{EGL.setErrorCode(12288);return 1}return 0}Module["_eglSwapBuffers"]=_eglSwapBuffers;_eglSwapBuffers.sig="ipp";var _eglReleaseThread=()=>{EGL.currentContext=0;EGL.currentReadSurface=0;EGL.currentDrawSurface=0;EGL.setErrorCode(12288);return 1};Module["_eglReleaseThread"]=_eglReleaseThread;_eglReleaseThread.sig="i";var _SDL_GetTicks=()=>Date.now()-SDL.startTime|0;Module["_SDL_GetTicks"]=_SDL_GetTicks;_SDL_GetTicks.sig="i";function _SDL_LockSurface(surf){surf>>>=0;var surfData=SDL.surfaces[surf];surfData.locked++;if(surfData.locked>1)return 0;if(!surfData.buffer){surfData.buffer=_malloc(surfData.width*surfData.height*4);HEAPU32[surf+20>>>2>>>0]=surfData.buffer}HEAPU32[surf+20>>>2>>>0]=surfData.buffer;if(surf==SDL.screen&&Module.screenIsReadOnly&&surfData.image)return 0;if(SDL.defaults.discardOnLock){if(!surfData.image){surfData.image=surfData.ctx.createImageData(surfData.width,surfData.height)}if(!SDL.defaults.opaqueFrontBuffer)return}else{surfData.image=surfData.ctx.getImageData(0,0,surfData.width,surfData.height)}if(surf==SDL.screen&&SDL.defaults.opaqueFrontBuffer){var data=surfData.image.data;var num=data.length;for(var i=0;i>>0)}}return 0}Module["_SDL_LockSurface"]=_SDL_LockSurface;_SDL_LockSurface.sig="ip";var SDL={defaults:{width:320,height:200,copyOnLock:true,discardOnLock:false,opaqueFrontBuffer:true},version:null,surfaces:{},canvasPool:[],events:[],fonts:[null],audios:[null],rwops:[null],music:{audio:null,volume:1},mixerFrequency:22050,mixerFormat:32784,mixerNumChannels:2,mixerChunkSize:1024,channelMinimumNumber:0,GL:false,glAttributes:{0:3,1:3,2:2,3:0,4:0,5:1,6:16,7:0,8:0,9:0,10:0,11:0,12:0,13:0,14:0,15:1,16:0,17:0,18:0},keyboardState:null,keyboardMap:{},canRequestFullscreen:false,isRequestingFullscreen:false,textInput:false,unicode:false,ttfContext:null,audio:null,startTime:null,initFlags:0,buttonState:0,modState:0,DOMButtons:[0,0,0],DOMEventToSDLEvent:{},TOUCH_DEFAULT_ID:0,eventHandler:null,eventHandlerContext:null,eventHandlerTemp:0,keyCodes:{16:1249,17:1248,18:1250,20:1081,33:1099,34:1102,35:1101,36:1098,37:1104,38:1106,39:1103,40:1105,44:316,45:1097,46:127,91:1251,93:1125,96:1122,97:1113,98:1114,99:1115,100:1116,101:1117,102:1118,103:1119,104:1120,105:1121,106:1109,107:1111,109:1110,110:1123,111:1108,112:1082,113:1083,114:1084,115:1085,116:1086,117:1087,118:1088,119:1089,120:1090,121:1091,122:1092,123:1093,124:1128,125:1129,126:1130,127:1131,128:1132,129:1133,130:1134,131:1135,132:1136,133:1137,134:1138,135:1139,144:1107,160:94,161:33,162:34,163:35,164:36,165:37,166:38,167:95,168:40,169:41,170:42,171:43,172:124,173:45,174:123,175:125,176:126,181:127,182:129,183:128,188:44,190:46,191:47,192:96,219:91,220:92,221:93,222:39,224:1251},scanCodes:{8:42,9:43,13:40,27:41,32:44,35:204,39:53,44:54,46:55,47:56,48:39,49:30,50:31,51:32,52:33,53:34,54:35,55:36,56:37,57:38,58:203,59:51,61:46,91:47,92:49,93:48,96:52,97:4,98:5,99:6,100:7,101:8,102:9,103:10,104:11,105:12,106:13,107:14,108:15,109:16,110:17,111:18,112:19,113:20,114:21,115:22,116:23,117:24,118:25,119:26,120:27,121:28,122:29,127:76,305:224,308:226,316:70},loadRect(rect){return{x:HEAP32[rect+0>>>2>>>0],y:HEAP32[rect+4>>>2>>>0],w:HEAP32[rect+8>>>2>>>0],h:HEAP32[rect+12>>>2>>>0]}},updateRect(rect,r){HEAP32[rect>>>2>>>0]=r.x;HEAP32[rect+4>>>2>>>0]=r.y;HEAP32[rect+8>>>2>>>0]=r.w;HEAP32[rect+12>>>2>>>0]=r.h},intersectionOfRects(first,second){var leftX=Math.max(first.x,second.x);var leftY=Math.max(first.y,second.y);var rightX=Math.min(first.x+first.w,second.x+second.w);var rightY=Math.min(first.y+first.h,second.y+second.h);return{x:leftX,y:leftY,w:Math.max(leftX,rightX)-leftX,h:Math.max(leftY,rightY)-leftY}},checkPixelFormat(fmt){},loadColorToCSSRGB(color){var rgba=HEAP32[color>>>2>>>0];return"rgb("+(rgba&255)+","+(rgba>>8&255)+","+(rgba>>16&255)+")"},loadColorToCSSRGBA(color){var rgba=HEAP32[color>>>2>>>0];return"rgba("+(rgba&255)+","+(rgba>>8&255)+","+(rgba>>16&255)+","+(rgba>>24&255)/255+")"},translateColorToCSSRGBA:rgba=>"rgba("+(rgba&255)+","+(rgba>>8&255)+","+(rgba>>16&255)+","+(rgba>>>24)/255+")",translateRGBAToCSSRGBA:(r,g,b,a)=>"rgba("+(r&255)+","+(g&255)+","+(b&255)+","+(a&255)/255+")",translateRGBAToColor:(r,g,b,a)=>r|g<<8|b<<16|a<<24,makeSurface(width,height,flags,usePageCanvas,source,rmask,gmask,bmask,amask){var is_SDL_HWSURFACE=flags&1;var is_SDL_HWPALETTE=flags&2097152;var is_SDL_OPENGL=flags&67108864;var surf=_malloc(60);var pixelFormat=_malloc(44);var bpp=is_SDL_HWPALETTE?1:4;var buffer=0;if(!is_SDL_HWSURFACE&&!is_SDL_OPENGL){buffer=_malloc(width*height*4)}HEAP32[surf>>>2>>>0]=flags;HEAPU32[surf+4>>>2>>>0]=pixelFormat;HEAP32[surf+8>>>2>>>0]=width;HEAP32[surf+12>>>2>>>0]=height;HEAP32[surf+16>>>2>>>0]=width*bpp;HEAPU32[surf+20>>>2>>>0]=buffer;HEAP32[surf+36>>>2>>>0]=0;HEAP32[surf+40>>>2>>>0]=0;HEAP32[surf+44>>>2>>>0]=Module["canvas"].width;HEAP32[surf+48>>>2>>>0]=Module["canvas"].height;HEAP32[surf+56>>>2>>>0]=1;HEAP32[pixelFormat>>>2>>>0]=-2042224636;HEAP32[pixelFormat+4>>>2>>>0]=0;HEAP8[pixelFormat+8>>>0]=bpp*8;HEAP8[pixelFormat+9>>>0]=bpp;HEAP32[pixelFormat+12>>>2>>>0]=rmask||255;HEAP32[pixelFormat+16>>>2>>>0]=gmask||65280;HEAP32[pixelFormat+20>>>2>>>0]=bmask||16711680;HEAP32[pixelFormat+24>>>2>>>0]=amask||4278190080;SDL.GL=SDL.GL||is_SDL_OPENGL;var canvas;if(!usePageCanvas){if(SDL.canvasPool.length>0){canvas=SDL.canvasPool.pop()}else{canvas=document.createElement("canvas")}canvas.width=width;canvas.height=height}else{canvas=Module["canvas"]}var webGLContextAttributes={antialias:SDL.glAttributes[13]!=0&&SDL.glAttributes[14]>1,depth:SDL.glAttributes[6]>0,stencil:SDL.glAttributes[7]>0,alpha:SDL.glAttributes[3]>0};var ctx=Browser.createContext(canvas,is_SDL_OPENGL,usePageCanvas,webGLContextAttributes);SDL.surfaces[surf]={width:width,height:height,canvas:canvas,ctx:ctx,surf:surf,buffer:buffer,pixelFormat:pixelFormat,alpha:255,flags:flags,locked:0,usePageCanvas:usePageCanvas,source:source,isFlagSet:flag=>flags&flag};return surf},copyIndexedColorData(surfData,rX,rY,rW,rH){if(!surfData.colors){return}var fullWidth=Module["canvas"].width;var fullHeight=Module["canvas"].height;var startX=rX||0;var startY=rY||0;var endX=(rW||fullWidth-startX)+startX;var endY=(rH||fullHeight-startY)+startY;var buffer=surfData.buffer;if(!surfData.image.data32){surfData.image.data32=new Uint32Array(surfData.image.data.buffer)}var data32=surfData.image.data32;var colors32=surfData.colors32;for(var y=startY;y>>0]]}}},freeSurface(surf){var refcountPointer=surf+56;var refcount=HEAP32[refcountPointer>>>2>>>0];if(refcount>1){HEAP32[refcountPointer>>>2>>>0]=refcount-1;return}var info=SDL.surfaces[surf];if(!info.usePageCanvas&&info.canvas)SDL.canvasPool.push(info.canvas);if(info.buffer)_free(info.buffer);_free(info.pixelFormat);_free(surf);SDL.surfaces[surf]=null;if(surf===SDL.screen){SDL.screen=null}},blitSurface(src,srcrect,dst,dstrect,scale){var srcData=SDL.surfaces[src];var dstData=SDL.surfaces[dst];var sr,dr;if(srcrect){sr=SDL.loadRect(srcrect)}else{sr={x:0,y:0,w:srcData.width,h:srcData.height}}if(dstrect){dr=SDL.loadRect(dstrect)}else{dr={x:0,y:0,w:srcData.width,h:srcData.height}}if(dstData.clipRect){var widthScale=!scale||sr.w===0?1:sr.w/dr.w;var heightScale=!scale||sr.h===0?1:sr.h/dr.h;dr=SDL.intersectionOfRects(dstData.clipRect,dr);sr.w=dr.w*widthScale;sr.h=dr.h*heightScale;if(dstrect){SDL.updateRect(dstrect,dr)}}var blitw,blith;if(scale){blitw=dr.w;blith=dr.h}else{blitw=sr.w;blith=sr.h}if(sr.w===0||sr.h===0||blitw===0||blith===0){return 0}var oldAlpha=dstData.ctx.globalAlpha;dstData.ctx.globalAlpha=srcData.alpha/255;dstData.ctx.drawImage(srcData.canvas,sr.x,sr.y,sr.w,sr.h,dr.x,dr.y,blitw,blith);dstData.ctx.globalAlpha=oldAlpha;if(dst!=SDL.screen){warnOnce("WARNING: copying canvas data to memory for compatibility");_SDL_LockSurface(dst);dstData.locked--}return 0},downFingers:{},savedKeydown:null,receiveEvent(event){function unpressAllPressedKeys(){for(var code in SDL.keyboardMap){SDL.events.push({type:"keyup",keyCode:SDL.keyboardMap[code]})}}switch(event.type){case"touchstart":case"touchmove":{event.preventDefault();var touches=[];if(event.type==="touchstart"){for(var i=0;i0?Math.max(delta,1):Math.min(delta,-1);var button=delta>0?3:4;SDL.events.push({type:"mousedown",button:button,pageX:event.pageX,pageY:event.pageY});SDL.events.push({type:"mouseup",button:button,pageX:event.pageX,pageY:event.pageY});SDL.events.push({type:"wheel",deltaX:0,deltaY:delta});event.preventDefault();break;case"mousemove":if(SDL.DOMButtons[0]===1){SDL.events.push({type:"touchmove",touch:{identifier:0,deviceID:-1,pageX:event.pageX,pageY:event.pageY}})}if(Browser.pointerLock){if("mozMovementX"in event){event["movementX"]=event["mozMovementX"];event["movementY"]=event["mozMovementY"]}if(event["movementX"]==0&&event["movementY"]==0){event.preventDefault();return}}case"keydown":case"keyup":case"keypress":case"mousedown":case"mouseup":if(event.type!=="keydown"||!SDL.unicode&&!SDL.textInput||(event.keyCode===8||event.keyCode===9)){event.preventDefault()}if(event.type=="mousedown"){SDL.DOMButtons[event.button]=1;SDL.events.push({type:"touchstart",touch:{identifier:0,deviceID:-1,pageX:event.pageX,pageY:event.pageY}})}else if(event.type=="mouseup"){if(!SDL.DOMButtons[event.button]){return}SDL.events.push({type:"touchend",touch:{identifier:0,deviceID:-1,pageX:event.pageX,pageY:event.pageY}});SDL.DOMButtons[event.button]=0}if(event.type==="keydown"||event.type==="mousedown"){SDL.canRequestFullscreen=true}else if(event.type==="keyup"||event.type==="mouseup"){if(SDL.isRequestingFullscreen){Module["requestFullscreen"](true,true);SDL.isRequestingFullscreen=false}SDL.canRequestFullscreen=false}if(event.type==="keypress"&&SDL.savedKeydown){SDL.savedKeydown.keypressCharCode=event.charCode;SDL.savedKeydown=null}else if(event.type==="keydown"){SDL.savedKeydown=event}if(event.type!=="keypress"||SDL.textInput){SDL.events.push(event)}break;case"mouseout":for(var i=0;i<3;i++){if(SDL.DOMButtons[i]){SDL.events.push({type:"mouseup",button:i,pageX:event.pageX,pageY:event.pageY});SDL.DOMButtons[i]=0}}event.preventDefault();break;case"focus":SDL.events.push(event);event.preventDefault();break;case"blur":SDL.events.push(event);unpressAllPressedKeys();event.preventDefault();break;case"visibilitychange":SDL.events.push({type:"visibilitychange",visible:!document.hidden});unpressAllPressedKeys();event.preventDefault();break;case"unload":if(Browser.mainLoop.runner){SDL.events.push(event);Browser.mainLoop.runner()}return;case"resize":SDL.events.push(event);if(event.preventDefault){event.preventDefault()}break}if(SDL.events.length>=1e4){err("SDL event queue full, dropping events");SDL.events=SDL.events.slice(0,1e4)}SDL.flushEventsToHandler();return},lookupKeyCodeForEvent(event){var code=event.keyCode;if(code>=65&&code<=90){code+=32}else{code=SDL.keyCodes[event.keyCode]||event.keyCode;if(event.location===2&&code>=(224|1<<10)&&code<=(227|1<<10)){code+=4}}return code},handleEvent(event){if(event.handled)return;event.handled=true;switch(event.type){case"touchstart":case"touchend":case"touchmove":{Browser.calculateMouseEvent(event);break}case"keydown":case"keyup":{var down=event.type==="keydown";var code=SDL.lookupKeyCodeForEvent(event);HEAP8[SDL.keyboardState+code>>>0]=down;SDL.modState=(HEAP8[SDL.keyboardState+1248>>>0]?64:0)|(HEAP8[SDL.keyboardState+1249>>>0]?1:0)|(HEAP8[SDL.keyboardState+1250>>>0]?256:0)|(HEAP8[SDL.keyboardState+1252>>>0]?128:0)|(HEAP8[SDL.keyboardState+1253>>>0]?2:0)|(HEAP8[SDL.keyboardState+1254>>>0]?512:0);if(down){SDL.keyboardMap[code]=event.keyCode}else{delete SDL.keyboardMap[code]}break}case"mousedown":case"mouseup":if(event.type=="mousedown"){SDL.buttonState|=1<0){if(SDL.makeCEvent(SDL.events.shift(),ptr)!==false)return 1}return 0}return SDL.events.length>0},makeCEvent(event,ptr){if(typeof event=="number"){_memcpy(ptr,event,28);_free(event);return}SDL.handleEvent(event);switch(event.type){case"keydown":case"keyup":{var down=event.type==="keydown";var key=SDL.lookupKeyCodeForEvent(event);var scan;if(key>=1024){scan=key-1024}else{scan=SDL.scanCodes[key]||key}HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP8[ptr+8>>>0]=down?1:0;HEAP8[ptr+9>>>0]=0;HEAP32[ptr+12>>>2>>>0]=scan;HEAP32[ptr+16>>>2>>>0]=key;HEAP16[ptr+20>>>1>>>0]=SDL.modState;HEAP32[ptr+24>>>2>>>0]=event.keypressCharCode||key;break}case"keypress":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];var cStr=intArrayFromString(String.fromCharCode(event.charCode));for(var i=0;i>>0]=cStr[i]}break}case"mousedown":case"mouseup":case"mousemove":{if(event.type!="mousemove"){var down=event.type==="mousedown";HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=0;HEAP32[ptr+8>>>2>>>0]=0;HEAP32[ptr+12>>>2>>>0]=0;HEAP8[ptr+16>>>0]=event.button+1;HEAP8[ptr+17>>>0]=down?1:0;HEAP32[ptr+20>>>2>>>0]=Browser.mouseX;HEAP32[ptr+24>>>2>>>0]=Browser.mouseY}else{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=0;HEAP32[ptr+8>>>2>>>0]=0;HEAP32[ptr+12>>>2>>>0]=0;HEAP32[ptr+16>>>2>>>0]=SDL.buttonState;HEAP32[ptr+20>>>2>>>0]=Browser.mouseX;HEAP32[ptr+24>>>2>>>0]=Browser.mouseY;HEAP32[ptr+28>>>2>>>0]=Browser.mouseMovementX;HEAP32[ptr+32>>>2>>>0]=Browser.mouseMovementY}break}case"wheel":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+16>>>2>>>0]=event.deltaX;HEAP32[ptr+20>>>2>>>0]=event.deltaY;break}case"touchstart":case"touchend":case"touchmove":{var touch=event.touch;if(!Browser.touches[touch.identifier])break;var w=Module["canvas"].width;var h=Module["canvas"].height;var x=Browser.touches[touch.identifier].x/w;var y=Browser.touches[touch.identifier].y/h;var lx=Browser.lastTouches[touch.identifier].x/w;var ly=Browser.lastTouches[touch.identifier].y/h;var dx=x-lx;var dy=y-ly;if(touch["deviceID"]===undefined)touch.deviceID=SDL.TOUCH_DEFAULT_ID;if(dx===0&&dy===0&&event.type==="touchmove")return false;HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=_SDL_GetTicks();HEAP64[ptr+8>>>3]=BigInt(touch.deviceID);HEAP64[ptr+16>>>3]=BigInt(touch.identifier);HEAPF32[ptr+24>>>2>>>0]=x;HEAPF32[ptr+28>>>2>>>0]=y;HEAPF32[ptr+32>>>2>>>0]=dx;HEAPF32[ptr+36>>>2>>>0]=dy;if(touch.force!==undefined){HEAPF32[ptr+40>>>2>>>0]=touch.force}else{HEAPF32[ptr+40>>>2>>>0]=event.type=="touchend"?0:1}break}case"unload":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];break}case"resize":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=event.w;HEAP32[ptr+8>>>2>>>0]=event.h;break}case"joystick_button_up":case"joystick_button_down":{var state=event.type==="joystick_button_up"?0:1;HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP8[ptr+4>>>0]=event.index;HEAP8[ptr+5>>>0]=event.button;HEAP8[ptr+6>>>0]=state;break}case"joystick_axis_motion":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP8[ptr+4>>>0]=event.index;HEAP8[ptr+5>>>0]=event.axis;HEAP32[ptr+8>>>2>>>0]=SDL.joystickAxisValueConversion(event.value);break}case"focus":{var SDL_WINDOWEVENT_FOCUS_GAINED=12;HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=0;HEAP8[ptr+8>>>0]=SDL_WINDOWEVENT_FOCUS_GAINED;break}case"blur":{var SDL_WINDOWEVENT_FOCUS_LOST=13;HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=0;HEAP8[ptr+8>>>0]=SDL_WINDOWEVENT_FOCUS_LOST;break}case"visibilitychange":{var SDL_WINDOWEVENT_SHOWN=1;var SDL_WINDOWEVENT_HIDDEN=2;var visibilityEventID=event.visible?SDL_WINDOWEVENT_SHOWN:SDL_WINDOWEVENT_HIDDEN;HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=0;HEAP8[ptr+8>>>0]=visibilityEventID;break}default:throw"Unhandled SDL event: "+event.type}},makeFontString(height,fontName){if(fontName.charAt(0)!="'"&&fontName.charAt(0)!='"'){fontName='"'+fontName+'"'}return height+"px "+fontName+", serif"},estimateTextWidth(fontData,text){var h=fontData.size;var fontString=SDL.makeFontString(h,fontData.name);var tempCtx=SDL.ttfContext;tempCtx.font=fontString;var ret=tempCtx.measureText(text).width|0;return ret},allocateChannels(num){if(SDL.numChannels&&SDL.numChannels>=num&&num!=0)return;SDL.numChannels=num;SDL.channels=[];for(var i=0;i{if(!audio.paused)SDL.playWebAudio(audio)});return}audio.webAudioNode=SDL.audioContext["createBufferSource"]();audio.webAudioNode["buffer"]=webAudio.decodedBuffer;audio.webAudioNode["loop"]=audio.loop;audio.webAudioNode["onended"]=audio["onended"];audio.webAudioPannerNode=SDL.audioContext["createPanner"]();audio.webAudioPannerNode["setPosition"](0,0,-.5);audio.webAudioPannerNode["panningModel"]="equalpower";audio.webAudioGainNode=SDL.audioContext["createGain"]();audio.webAudioGainNode["gain"]["value"]=audio.volume;audio.webAudioNode["connect"](audio.webAudioPannerNode);audio.webAudioPannerNode["connect"](audio.webAudioGainNode);audio.webAudioGainNode["connect"](SDL.audioContext["destination"]);audio.webAudioNode["start"](0,audio.currentPosition);audio.startTime=SDL.audioContext["currentTime"]-audio.currentPosition}catch(e){err(`playWebAudio failed: ${e}`)}},pauseWebAudio(audio){if(!audio)return;if(audio.webAudioNode){try{audio.currentPosition=(SDL.audioContext["currentTime"]-audio.startTime)%audio.resource.webAudio.decodedBuffer.duration;audio.webAudioNode["onended"]=undefined;audio.webAudioNode.stop(0);audio.webAudioNode=undefined}catch(e){err(`pauseWebAudio failed: ${e}`)}}audio.paused=true},openAudioContext(){if(!SDL.audioContext){if(typeof AudioContext!="undefined")SDL.audioContext=new AudioContext;else if(typeof webkitAudioContext!="undefined")SDL.audioContext=new webkitAudioContext}},webAudioAvailable:()=>!!SDL.audioContext,fillWebAudioBufferFromHeap(heapPtr,sizeSamplesPerChannel,dstAudioBuffer){var audio=SDL.audio;var numChannels=audio.channels;for(var c=0;c>>1>>>0]/32768}}else if(audio.format==8){for(var j=0;j>>0];channelData[j]=(v>=0?v-128:v+128)/128}}else if(audio.format==33056){for(var j=0;j>>2>>>0]}}else{throw"Invalid SDL audio format "+audio.format+"!"}}},joystickEventState:1,lastJoystickState:{},joystickNamePool:{},recordJoystickState(joystick,state){var buttons=new Array(state.buttons.length);for(var i=0;i0},queryJoysticks(){for(var joystick in SDL.lastJoystickState){var state=SDL.getGamepad(joystick-1);var prevState=SDL.lastJoystickState[joystick];if(typeof state=="undefined")return;if(state===null)return;if(typeof state.timestamp!="number"||state.timestamp!=prevState.timestamp||!state.timestamp){var i;for(i=0;ideviceIndex&&deviceIndex>=0){return gamepads[deviceIndex]}return null}};Module["SDL"]=SDL;function _SDL_Linked_Version(){if(SDL.version===null){SDL.version=_malloc(3);HEAP8[SDL.version+0>>>0]=1;HEAP8[SDL.version+1>>>0]=3;HEAP8[SDL.version+2>>>0]=0}return SDL.version}Module["_SDL_Linked_Version"]=_SDL_Linked_Version;_SDL_Linked_Version.sig="p";var _SDL_Init=initFlags=>{SDL.startTime=Date.now();SDL.initFlags=initFlags;if(!Module["doNotCaptureKeyboard"]){var keyboardListeningElement=Module["keyboardListeningElement"]||document;keyboardListeningElement.addEventListener("keydown",SDL.receiveEvent);keyboardListeningElement.addEventListener("keyup",SDL.receiveEvent);keyboardListeningElement.addEventListener("keypress",SDL.receiveEvent);window.addEventListener("focus",SDL.receiveEvent);window.addEventListener("blur",SDL.receiveEvent);document.addEventListener("visibilitychange",SDL.receiveEvent)}window.addEventListener("unload",SDL.receiveEvent);SDL.keyboardState=_malloc(65536);zeroMemory(SDL.keyboardState,65536);SDL.DOMEventToSDLEvent["keydown"]=768;SDL.DOMEventToSDLEvent["keyup"]=769;SDL.DOMEventToSDLEvent["keypress"]=771;SDL.DOMEventToSDLEvent["mousedown"]=1025;SDL.DOMEventToSDLEvent["mouseup"]=1026;SDL.DOMEventToSDLEvent["mousemove"]=1024;SDL.DOMEventToSDLEvent["wheel"]=1027;SDL.DOMEventToSDLEvent["touchstart"]=1792;SDL.DOMEventToSDLEvent["touchend"]=1793;SDL.DOMEventToSDLEvent["touchmove"]=1794;SDL.DOMEventToSDLEvent["unload"]=256;SDL.DOMEventToSDLEvent["resize"]=28673;SDL.DOMEventToSDLEvent["visibilitychange"]=512;SDL.DOMEventToSDLEvent["focus"]=512;SDL.DOMEventToSDLEvent["blur"]=512;SDL.DOMEventToSDLEvent["joystick_axis_motion"]=1536;SDL.DOMEventToSDLEvent["joystick_button_down"]=1539;SDL.DOMEventToSDLEvent["joystick_button_up"]=1540;return 0};Module["_SDL_Init"]=_SDL_Init;_SDL_Init.sig="ii";var _SDL_WasInit=flags=>{if(SDL.startTime===null){_SDL_Init(0)}return 1};Module["_SDL_WasInit"]=_SDL_WasInit;_SDL_WasInit.sig="ii";function _SDL_GetVideoInfo(){var ret=_malloc(20);zeroMemory(ret,3);HEAP32[ret+12>>>2>>>0]=Module["canvas"].width;HEAP32[ret+16>>>2>>>0]=Module["canvas"].height;return ret}Module["_SDL_GetVideoInfo"]=_SDL_GetVideoInfo;_SDL_GetVideoInfo.sig="p";function _SDL_ListModes(format,flags){format>>>=0;return-1}Module["_SDL_ListModes"]=_SDL_ListModes;_SDL_ListModes.sig="ppi";var _SDL_VideoModeOK=(width,height,depth,flags)=>depth;Module["_SDL_VideoModeOK"]=_SDL_VideoModeOK;_SDL_VideoModeOK.sig="iiiii";function _SDL_VideoDriverName(buf,max_size){buf>>>=0;if(SDL.startTime===null){return 0}var driverName=[101,109,115,99,114,105,112,116,101,110,95,115,100,108,95,100,114,105,118,101,114];var index=0;var size=driverName.length;if(max_size<=size){size=max_size-1}while(index>>0]=value;index++}HEAP8[buf+index>>>0]=0;return buf}Module["_SDL_VideoDriverName"]=_SDL_VideoDriverName;_SDL_VideoDriverName.sig="ppi";var _SDL_AudioDriverName=_SDL_VideoDriverName;Module["_SDL_AudioDriverName"]=_SDL_AudioDriverName;_SDL_AudioDriverName.sig="ppi";var _SDL_SetVideoMode=function(width,height,depth,flags){["touchstart","touchend","touchmove","mousedown","mouseup","mousemove","mousewheel","wheel","mouseout","DOMMouseScroll"].forEach(e=>Module["canvas"].addEventListener(e,SDL.receiveEvent,true));var canvas=Module["canvas"];if(width==0&&height==0){width=canvas.width;height=canvas.height}if(!SDL.addedResizeListener){SDL.addedResizeListener=true;Browser.resizeListeners.push((w,h)=>{if(!SDL.settingVideoMode){SDL.receiveEvent({type:"resize",w:w,h:h})}})}SDL.settingVideoMode=true;Browser.setCanvasSize(width,height);SDL.settingVideoMode=false;if(SDL.screen){SDL.freeSurface(SDL.screen);assert(!SDL.screen)}if(SDL.GL)flags=flags|67108864;SDL.screen=SDL.makeSurface(width,height,flags,true,"screen");return SDL.screen};Module["_SDL_SetVideoMode"]=_SDL_SetVideoMode;_SDL_SetVideoMode.sig="piiii";function _SDL_GetVideoSurface(){return SDL.screen}Module["_SDL_GetVideoSurface"]=_SDL_GetVideoSurface;_SDL_GetVideoSurface.sig="p";var _SDL_AudioQuit=()=>{for(var i=0;iout("SDL_VideoQuit called (and ignored)");Module["_SDL_VideoQuit"]=_SDL_VideoQuit;_SDL_VideoQuit.sig="v";var _SDL_QuitSubSystem=flags=>out("SDL_QuitSubSystem called (and ignored)");Module["_SDL_QuitSubSystem"]=_SDL_QuitSubSystem;_SDL_QuitSubSystem.sig="vi";var _SDL_Quit=()=>{_SDL_AudioQuit();out("SDL_Quit called (and ignored)")};Module["_SDL_Quit"]=_SDL_Quit;_SDL_Quit.sig="v";function _SDL_UnlockSurface(surf){surf>>>=0;assert(!SDL.GL);var surfData=SDL.surfaces[surf];if(!surfData.locked||--surfData.locked>0){return}if(surfData.isFlagSet(2097152)){SDL.copyIndexedColorData(surfData)}else if(!surfData.colors){var data=surfData.image.data;var buffer=surfData.buffer;assert(buffer%4==0,"Invalid buffer offset: "+buffer);var src=buffer>>>2;var dst=0;var isScreen=surf==SDL.screen;var num;if(typeof CanvasPixelArray!="undefined"&&data instanceof CanvasPixelArray){num=data.length;while(dst>>0];data[dst]=val&255;data[dst+1]=val>>8&255;data[dst+2]=val>>16&255;data[dst+3]=isScreen?255:val>>24&255;src++;dst+=4}}else{var data32=new Uint32Array(data.buffer);if(isScreen&&SDL.defaults.opaqueFrontBuffer){num=data32.length;data32.set(HEAP32.subarray(src>>>0,src+num>>>0));var data8=new Uint8Array(data.buffer);var i=3;var j=i+4*num;if(num%8==0){while(i>>0,src+data32.length>>>0))}}}else{var width=Module["canvas"].width;var height=Module["canvas"].height;var s=surfData.buffer;var data=surfData.image.data;var colors=surfData.colors;for(var y=0;y>>0]*4;var start=base+x*4;data[start]=colors[val];data[start+1]=colors[val+1];data[start+2]=colors[val+2]}s+=width*3}}surfData.ctx.putImageData(surfData.image,0,0)}Module["_SDL_UnlockSurface"]=_SDL_UnlockSurface;_SDL_UnlockSurface.sig="vp";function _SDL_Flip(surf){surf>>>=0}Module["_SDL_Flip"]=_SDL_Flip;_SDL_Flip.sig="ip";function _SDL_UpdateRect(surf,x,y,w,h){surf>>>=0}Module["_SDL_UpdateRect"]=_SDL_UpdateRect;_SDL_UpdateRect.sig="vpiiii";function _SDL_UpdateRects(surf,numrects,rects){surf>>>=0;rects>>>=0}Module["_SDL_UpdateRects"]=_SDL_UpdateRects;_SDL_UpdateRects.sig="vpip";var _SDL_Delay=delay=>{if(!ENVIRONMENT_IS_WORKER)abort("SDL_Delay called on the main thread! Potential infinite loop, quitting. (consider building with async support like ASYNCIFY)");var now=Date.now();while(Date.now()-now>>=0;icon>>>=0;if(title){_emscripten_set_window_title(title)}icon&&=UTF8ToString(icon)}Module["_SDL_WM_SetCaption"]=_SDL_WM_SetCaption;_SDL_WM_SetCaption.sig="vpp";var _SDL_EnableKeyRepeat=(delay,interval)=>{};Module["_SDL_EnableKeyRepeat"]=_SDL_EnableKeyRepeat;_SDL_EnableKeyRepeat.sig="iii";function _SDL_GetKeyboardState(numKeys){numKeys>>>=0;if(numKeys){HEAP32[numKeys>>>2>>>0]=65536}return SDL.keyboardState}Module["_SDL_GetKeyboardState"]=_SDL_GetKeyboardState;_SDL_GetKeyboardState.sig="pp";var _SDL_GetKeyState=()=>_SDL_GetKeyboardState(0);Module["_SDL_GetKeyState"]=_SDL_GetKeyState;function _SDL_GetKeyName(key){SDL.keyName||=stringToNewUTF8("unknown key");return SDL.keyName}Module["_SDL_GetKeyName"]=_SDL_GetKeyName;_SDL_GetKeyName.sig="pi";var _SDL_GetModState=()=>SDL.modState;Module["_SDL_GetModState"]=_SDL_GetModState;_SDL_GetModState.sig="i";function _SDL_GetMouseState(x,y){x>>>=0;y>>>=0;if(x)HEAP32[x>>>2>>>0]=Browser.mouseX;if(y)HEAP32[y>>>2>>>0]=Browser.mouseY;return SDL.buttonState}Module["_SDL_GetMouseState"]=_SDL_GetMouseState;_SDL_GetMouseState.sig="ipp";var _SDL_WarpMouse=(x,y)=>{};Module["_SDL_WarpMouse"]=_SDL_WarpMouse;_SDL_WarpMouse.sig="vii";var _SDL_ShowCursor=toggle=>{switch(toggle){case 0:if(Browser.isFullscreen){Module["canvas"].requestPointerLock();return 0}return 1;case 1:Module["canvas"].exitPointerLock();return 1;case-1:return!Browser.pointerLock;default:err(`SDL_ShowCursor called with unknown toggle parameter value: ${toggle}`);break}};Module["_SDL_ShowCursor"]=_SDL_ShowCursor;_SDL_ShowCursor.sig="ii";function _SDL_GetError(){SDL.errorMessage||=stringToNewUTF8("unknown SDL-emscripten error");return SDL.errorMessage}Module["_SDL_GetError"]=_SDL_GetError;_SDL_GetError.sig="p";function _SDL_SetError(fmt,varargs){fmt>>>=0;varargs>>>=0}Module["_SDL_SetError"]=_SDL_SetError;_SDL_SetError.sig="vpp";function _SDL_CreateRGBSurface(flags,width,height,depth,rmask,gmask,bmask,amask){return SDL.makeSurface(width,height,flags,false,"CreateRGBSurface",rmask,gmask,bmask,amask)}Module["_SDL_CreateRGBSurface"]=_SDL_CreateRGBSurface;_SDL_CreateRGBSurface.sig="piiiiiiii";function _SDL_CreateRGBSurfaceFrom(pixels,width,height,depth,pitch,rmask,gmask,bmask,amask){pixels>>>=0;var surf=SDL.makeSurface(width,height,0,false,"CreateRGBSurfaceFrom",rmask,gmask,bmask,amask);if(depth!==32){err("TODO: Partially unimplemented SDL_CreateRGBSurfaceFrom called!");return surf}var data=SDL.surfaces[surf];var image=data.ctx.createImageData(width,height);var pitchOfDst=width*4;for(var row=0;row>>0]}}data.ctx.putImageData(image,0,0);return surf}Module["_SDL_CreateRGBSurfaceFrom"]=_SDL_CreateRGBSurfaceFrom;_SDL_CreateRGBSurfaceFrom.sig="ppiiiiiiii";function _SDL_ConvertSurface(surf,format,flags){surf>>>=0;format>>>=0;if(format){SDL.checkPixelFormat(format)}var oldData=SDL.surfaces[surf];var ret=SDL.makeSurface(oldData.width,oldData.height,oldData.flags,false,"copy:"+oldData.source);var newData=SDL.surfaces[ret];newData.ctx.globalCompositeOperation="copy";newData.ctx.drawImage(oldData.canvas,0,0);newData.ctx.globalCompositeOperation=oldData.ctx.globalCompositeOperation;return ret}Module["_SDL_ConvertSurface"]=_SDL_ConvertSurface;_SDL_ConvertSurface.sig="pppi";function _SDL_DisplayFormatAlpha(surf){surf>>>=0;return _SDL_ConvertSurface(surf,0,0)}Module["_SDL_DisplayFormatAlpha"]=_SDL_DisplayFormatAlpha;_SDL_DisplayFormatAlpha.sig="pp";function _SDL_FreeSurface(surf){surf>>>=0;if(surf)SDL.freeSurface(surf)}Module["_SDL_FreeSurface"]=_SDL_FreeSurface;_SDL_FreeSurface.sig="vp";function _SDL_UpperBlit(src,srcrect,dst,dstrect){src>>>=0;srcrect>>>=0;dst>>>=0;dstrect>>>=0;return SDL.blitSurface(src,srcrect,dst,dstrect,false)}Module["_SDL_UpperBlit"]=_SDL_UpperBlit;_SDL_UpperBlit.sig="ipppp";function _SDL_UpperBlitScaled(src,srcrect,dst,dstrect){src>>>=0;srcrect>>>=0;dst>>>=0;dstrect>>>=0;return SDL.blitSurface(src,srcrect,dst,dstrect,true)}Module["_SDL_UpperBlitScaled"]=_SDL_UpperBlitScaled;_SDL_UpperBlitScaled.sig="ipppp";var _SDL_LowerBlit=_SDL_UpperBlit;Module["_SDL_LowerBlit"]=_SDL_LowerBlit;_SDL_LowerBlit.sig="ipppp";var _SDL_LowerBlitScaled=_SDL_UpperBlitScaled;Module["_SDL_LowerBlitScaled"]=_SDL_LowerBlitScaled;_SDL_LowerBlitScaled.sig="ipppp";function _SDL_GetClipRect(surf,rect){surf>>>=0;rect>>>=0;assert(rect);var surfData=SDL.surfaces[surf];var r=surfData.clipRect||{x:0,y:0,w:surfData.width,h:surfData.height};SDL.updateRect(rect,r)}Module["_SDL_GetClipRect"]=_SDL_GetClipRect;_SDL_GetClipRect.sig="vpp";function _SDL_SetClipRect(surf,rect){surf>>>=0;rect>>>=0;var surfData=SDL.surfaces[surf];if(rect){surfData.clipRect=SDL.intersectionOfRects({x:0,y:0,w:surfData.width,h:surfData.height},SDL.loadRect(rect))}else{delete surfData.clipRect}}Module["_SDL_SetClipRect"]=_SDL_SetClipRect;_SDL_SetClipRect.sig="ipp";function _SDL_FillRect(surf,rect,color){surf>>>=0;rect>>>=0;var surfData=SDL.surfaces[surf];assert(!surfData.locked);if(surfData.isFlagSet(2097152)){color=surfData.colors32[color]}var r=rect?SDL.loadRect(rect):{x:0,y:0,w:surfData.width,h:surfData.height};if(surfData.clipRect){r=SDL.intersectionOfRects(surfData.clipRect,r);if(rect){SDL.updateRect(rect,r)}}surfData.ctx.save();surfData.ctx.fillStyle=SDL.translateColorToCSSRGBA(color);surfData.ctx.fillRect(r.x,r.y,r.w,r.h);surfData.ctx.restore();return 0}Module["_SDL_FillRect"]=_SDL_FillRect;_SDL_FillRect.sig="ippi";function _zoomSurface(src,x,y,smooth){src>>>=0;var srcData=SDL.surfaces[src];var w=srcData.width*x;var h=srcData.height*y;var ret=SDL.makeSurface(Math.abs(w),Math.abs(h),srcData.flags,false,"zoomSurface");var dstData=SDL.surfaces[ret];if(x>=0&&y>=0)dstData.ctx.drawImage(srcData.canvas,0,0,w,h);else{dstData.ctx.save();dstData.ctx.scale(x<0?-1:1,y<0?-1:1);dstData.ctx.drawImage(srcData.canvas,w<0?w:0,h<0?h:0,Math.abs(w),Math.abs(h));dstData.ctx.restore()}return ret}Module["_zoomSurface"]=_zoomSurface;_zoomSurface.sig="ppddi";function _rotozoomSurface(src,angle,zoom,smooth){src>>>=0;if(angle%360===0){return _zoomSurface(src,zoom,zoom,smooth)}var srcData=SDL.surfaces[src];var w=srcData.width*zoom;var h=srcData.height*zoom;var diagonal=Math.ceil(Math.sqrt(Math.pow(w,2)+Math.pow(h,2)));var ret=SDL.makeSurface(diagonal,diagonal,srcData.flags,false,"rotozoomSurface");var dstData=SDL.surfaces[ret];dstData.ctx.translate(diagonal/2,diagonal/2);dstData.ctx.rotate(-angle*Math.PI/180);dstData.ctx.drawImage(srcData.canvas,-w/2,-h/2,w,h);return ret}Module["_rotozoomSurface"]=_rotozoomSurface;_rotozoomSurface.sig="ppddi";function _SDL_SetAlpha(surf,flag,alpha){surf>>>=0;var surfData=SDL.surfaces[surf];surfData.alpha=alpha;if(!(flag&65536)){surfData.alpha=255}}Module["_SDL_SetAlpha"]=_SDL_SetAlpha;_SDL_SetAlpha.sig="ipii";function _SDL_SetColorKey(surf,flag,key){surf>>>=0;warnOnce("SDL_SetColorKey is a no-op for performance reasons");return 0}Module["_SDL_SetColorKey"]=_SDL_SetColorKey;_SDL_SetColorKey.sig="ipii";function _SDL_PollEvent(ptr){ptr>>>=0;return SDL.pollEvent(ptr)}Module["_SDL_PollEvent"]=_SDL_PollEvent;_SDL_PollEvent.sig="ip";function _SDL_PushEvent(ptr){ptr>>>=0;var copy=_malloc(28);_memcpy(copy,ptr,28);SDL.events.push(copy);return 0}Module["_SDL_PushEvent"]=_SDL_PushEvent;_SDL_PushEvent.sig="ip";function _SDL_PeepEvents(events,requestedEventCount,action,from,to){events>>>=0;switch(action){case 2:{assert(requestedEventCount==1);var index=0;var retrievedEventCount=0;while(indexSDL.events.forEach(SDL.handleEvent);Module["_SDL_PumpEvents"]=_SDL_PumpEvents;_SDL_PumpEvents.sig="v";function _emscripten_SDL_SetEventHandler(handler,userdata){handler>>>=0;userdata>>>=0;SDL.eventHandler=handler;SDL.eventHandlerContext=userdata;if(!SDL.eventHandlerTemp)SDL.eventHandlerTemp=_malloc(28)}Module["_emscripten_SDL_SetEventHandler"]=_emscripten_SDL_SetEventHandler;_emscripten_SDL_SetEventHandler.sig="vpp";function _SDL_SetColors(surf,colors,firstColor,nColors){surf>>>=0;colors>>>=0;var surfData=SDL.surfaces[surf];if(!surfData.colors){var buffer=new ArrayBuffer(256*4);surfData.colors=new Uint8Array(buffer);surfData.colors32=new Uint32Array(buffer)}for(var i=0;i>>0];surfData.colors[index+1]=HEAPU8[colors+(i*4+1)>>>0];surfData.colors[index+2]=HEAPU8[colors+(i*4+2)>>>0];surfData.colors[index+3]=255}return 1}Module["_SDL_SetColors"]=_SDL_SetColors;_SDL_SetColors.sig="ippii";function _SDL_SetPalette(surf,flags,colors,firstColor,nColors){surf>>>=0;colors>>>=0;return _SDL_SetColors(surf,colors,firstColor,nColors)}Module["_SDL_SetPalette"]=_SDL_SetPalette;_SDL_SetPalette.sig="ipipii";function _SDL_MapRGB(fmt,r,g,b){fmt>>>=0;SDL.checkPixelFormat(fmt);return r&255|(g&255)<<8|(b&255)<<16|4278190080}Module["_SDL_MapRGB"]=_SDL_MapRGB;_SDL_MapRGB.sig="ipiii";function _SDL_MapRGBA(fmt,r,g,b,a){fmt>>>=0;SDL.checkPixelFormat(fmt);return r&255|(g&255)<<8|(b&255)<<16|(a&255)<<24}Module["_SDL_MapRGBA"]=_SDL_MapRGBA;_SDL_MapRGBA.sig="ipiiii";function _SDL_GetRGB(pixel,fmt,r,g,b){fmt>>>=0;r>>>=0;g>>>=0;b>>>=0;SDL.checkPixelFormat(fmt);if(r){HEAP8[r>>>0]=pixel&255}if(g){HEAP8[g>>>0]=pixel>>8&255}if(b){HEAP8[b>>>0]=pixel>>16&255}}Module["_SDL_GetRGB"]=_SDL_GetRGB;_SDL_GetRGB.sig="vipppp";function _SDL_GetRGBA(pixel,fmt,r,g,b,a){fmt>>>=0;r>>>=0;g>>>=0;b>>>=0;a>>>=0;SDL.checkPixelFormat(fmt);if(r){HEAP8[r>>>0]=pixel&255}if(g){HEAP8[g>>>0]=pixel>>8&255}if(b){HEAP8[b>>>0]=pixel>>16&255}if(a){HEAP8[a>>>0]=pixel>>24&255}}Module["_SDL_GetRGBA"]=_SDL_GetRGBA;_SDL_GetRGBA.sig="vippppp";var _SDL_GetAppState=()=>{var state=0;if(Browser.pointerLock){state|=1}if(document.hasFocus()){state|=2}state|=4;return state};Module["_SDL_GetAppState"]=_SDL_GetAppState;_SDL_GetAppState.sig="i";var _SDL_WM_GrabInput=()=>{};Module["_SDL_WM_GrabInput"]=_SDL_WM_GrabInput;_SDL_WM_GrabInput.sig="ii";function _SDL_WM_ToggleFullScreen(surf){surf>>>=0;if(Browser.exitFullscreen()){return 1}if(!SDL.canRequestFullscreen){return 0}SDL.isRequestingFullscreen=true;return 1}Module["_SDL_WM_ToggleFullScreen"]=_SDL_WM_ToggleFullScreen;_SDL_WM_ToggleFullScreen.sig="ip";var _IMG_Init=flags=>flags;Module["_IMG_Init"]=_IMG_Init;_IMG_Init.sig="ii";function _SDL_FreeRW(rwopsID){rwopsID>>>=0;SDL.rwops[rwopsID]=null;while(SDL.rwops.length>0&&SDL.rwops[SDL.rwops.length-1]===null){SDL.rwops.pop()}}Module["_SDL_FreeRW"]=_SDL_FreeRW;_SDL_FreeRW.sig="vp";var _IMG_Load_RW=function(rwopsID,freeSrc){rwopsID>>>=0;var sp=stackSave();try{var cleanup=()=>{stackRestore(sp);if(rwops&&freeSrc)_SDL_FreeRW(rwopsID)};var addCleanup=func=>{var old=cleanup;cleanup=()=>{old();func()}};var callStbImage=(func,params)=>{var x=stackAlloc(4);var y=stackAlloc(4);var comp=stackAlloc(4);var data=Module["_"+func](...params,x,y,comp,0);if(!data)return null;addCleanup(()=>Module["_stbi_image_free"](data));return{rawData:true,data:data,width:HEAP32[x>>>2>>>0],height:HEAP32[y>>>2>>>0],size:HEAP32[x>>>2>>>0]*HEAP32[y>>>2>>>0]*HEAP32[comp>>>2>>>0],bpp:HEAP32[comp>>>2>>>0]}};var rwops=SDL.rwops[rwopsID];if(rwops===undefined){return 0}var raw;var filename=rwops.filename;if(filename===undefined){warnOnce("Only file names that have been preloaded are supported for IMG_Load_RW. Consider using STB_IMAGE=1 if you want synchronous image decoding (see settings.js), or package files with --use-preload-plugins");return 0}if(!raw){filename=PATH_FS.resolve(filename);raw=preloadedImages[filename];if(!raw){if(raw===null)err("Trying to reuse preloaded image, but freePreloadedMediaOnUse is set!");warnOnce("Cannot find preloaded image "+filename);warnOnce("Cannot find preloaded image "+filename+". Consider using STB_IMAGE=1 if you want synchronous image decoding (see settings.js), or package files with --use-preload-plugins");return 0}else if(Module["freePreloadedMediaOnUse"]){preloadedImages[filename]=null}}var surf=SDL.makeSurface(raw.width,raw.height,0,false,"load:"+filename);var surfData=SDL.surfaces[surf];surfData.ctx.globalCompositeOperation="copy";if(!raw.rawData){surfData.ctx.drawImage(raw,0,0,raw.width,raw.height,0,0,raw.width,raw.height)}else{var imageData=surfData.ctx.getImageData(0,0,surfData.width,surfData.height);if(raw.bpp==4){imageData.data.set(HEAPU8.subarray(raw.data>>>0,raw.data+raw.size>>>0))}else if(raw.bpp==3){var pixels=raw.size/3;var data=imageData.data;var sourcePtr=raw.data;var destPtr=0;for(var i=0;i>>0];data[destPtr++]=HEAPU8[sourcePtr++>>>0];data[destPtr++]=HEAPU8[sourcePtr++>>>0];data[destPtr++]=255}}else if(raw.bpp==2){var pixels=raw.size;var data=imageData.data;var sourcePtr=raw.data;var destPtr=0;for(var i=0;i>>0];var alpha=HEAPU8[sourcePtr++>>>0];data[destPtr++]=gray;data[destPtr++]=gray;data[destPtr++]=gray;data[destPtr++]=alpha}}else if(raw.bpp==1){var pixels=raw.size;var data=imageData.data;var sourcePtr=raw.data;var destPtr=0;for(var i=0;i>>0];data[destPtr++]=value;data[destPtr++]=value;data[destPtr++]=value;data[destPtr++]=255}}else{err(`cannot handle bpp ${raw.bpp}`);return 0}surfData.ctx.putImageData(imageData,0,0)}surfData.ctx.globalCompositeOperation="source-over";_SDL_LockSurface(surf);surfData.locked--;if(SDL.GL){surfData.canvas=surfData.ctx=null}return surf}finally{cleanup()}};Module["_IMG_Load_RW"]=_IMG_Load_RW;_IMG_Load_RW.sig="ppi";var _SDL_LoadBMP_RW=_IMG_Load_RW;Module["_SDL_LoadBMP_RW"]=_SDL_LoadBMP_RW;_SDL_LoadBMP_RW.sig="ppi";function _SDL_RWFromFile(_name,mode){_name>>>=0;mode>>>=0;var id=SDL.rwops.length;var filename=UTF8ToString(_name);SDL.rwops.push({filename:filename,mimetype:Browser.getMimetype(filename)});return id}Module["_SDL_RWFromFile"]=_SDL_RWFromFile;_SDL_RWFromFile.sig="ppp";function _IMG_Load(filename){filename>>>=0;var rwops=_SDL_RWFromFile(filename,0);var result=_IMG_Load_RW(rwops,1);return result}Module["_IMG_Load"]=_IMG_Load;_IMG_Load.sig="pp";var _IMG_Quit=()=>out("IMG_Quit called (and ignored)");Module["_IMG_Quit"]=_IMG_Quit;_IMG_Quit.sig="v";function _SDL_OpenAudio(desired,obtained){desired>>>=0;obtained>>>=0;try{SDL.audio={freq:HEAPU32[desired>>>2>>>0],format:HEAPU16[desired+4>>>1>>>0],channels:HEAPU8[desired+6>>>0],samples:HEAPU16[desired+8>>>1>>>0],callback:HEAPU32[desired+16>>>2>>>0],userdata:HEAPU32[desired+20>>>2>>>0],paused:true,timer:null};if(SDL.audio.format==8){SDL.audio.silence=128}else if(SDL.audio.format==32784){SDL.audio.silence=0}else if(SDL.audio.format==33056){SDL.audio.silence=0}else{throw"Invalid SDL audio format "+SDL.audio.format+"!"}if(SDL.audio.freq<=0){throw"Unsupported sound frequency "+SDL.audio.freq+"!"}else if(SDL.audio.freq<=22050){SDL.audio.freq=22050}else if(SDL.audio.freq<=32e3){SDL.audio.freq=32e3}else if(SDL.audio.freq<=44100){SDL.audio.freq=44100}else if(SDL.audio.freq<=48e3){SDL.audio.freq=48e3}else if(SDL.audio.freq<=96e3){SDL.audio.freq=96e3}else{throw`Unsupported sound frequency ${SDL.audio.freq}!`}if(SDL.audio.channels==0){SDL.audio.channels=1}else if(SDL.audio.channels<0||SDL.audio.channels>32){throw`Unsupported number of audio channels for SDL audio: ${SDL.audio.channels}!`}else if(SDL.audio.channels!=1&&SDL.audio.channels!=2){out(`Warning: Using untested number of audio channels ${SDL.audio.channels}`)}if(SDL.audio.samples<128||SDL.audio.samples>524288){throw`Unsupported audio callback buffer size ${SDL.audio.samples}!`}else if((SDL.audio.samples&SDL.audio.samples-1)!=0){throw`Audio callback buffer size ${SDL.audio.samples} must be a power-of-two!`}var totalSamples=SDL.audio.samples*SDL.audio.channels;if(SDL.audio.format==8){SDL.audio.bytesPerSample=1}else if(SDL.audio.format==32784){SDL.audio.bytesPerSample=2}else if(SDL.audio.format==33056){SDL.audio.bytesPerSample=4}else{throw`Invalid SDL audio format ${SDL.audio.format}!`}SDL.audio.bufferSize=totalSamples*SDL.audio.bytesPerSample;SDL.audio.bufferDurationSecs=SDL.audio.bufferSize/SDL.audio.bytesPerSample/SDL.audio.channels/SDL.audio.freq;SDL.audio.bufferingDelay=50/1e3;SDL.audio.buffer=_malloc(SDL.audio.bufferSize);SDL.audio.numSimultaneouslyQueuedBuffers=Module["SDL_numSimultaneouslyQueuedBuffers"]||5;SDL.audio.queueNewAudioData=()=>{if(!SDL.audio)return;for(var i=0;i=SDL.audio.bufferingDelay+SDL.audio.bufferDurationSecs*SDL.audio.numSimultaneouslyQueuedBuffers)return;getWasmTableEntry(SDL.audio.callback)(SDL.audio.userdata,SDL.audio.buffer,SDL.audio.bufferSize);SDL.audio.pushAudio(SDL.audio.buffer,SDL.audio.bufferSize)}};SDL.audio.caller=()=>{if(!SDL.audio)return;--SDL.audio.numAudioTimersPending;SDL.audio.queueNewAudioData();var secsUntilNextPlayStart=SDL.audio.nextPlayTime-SDL.audioContext["currentTime"];var preemptBufferFeedSecs=SDL.audio.bufferDurationSecs/2;if(SDL.audio.numAudioTimersPending{try{if(SDL.audio.paused)return;var sizeSamples=sizeBytes/SDL.audio.bytesPerSample;var sizeSamplesPerChannel=sizeSamples/SDL.audio.channels;if(sizeSamplesPerChannel!=SDL.audio.samples){throw"Received mismatching audio buffer size!"}var source=SDL.audioContext["createBufferSource"]();var soundBuffer=SDL.audioContext["createBuffer"](SDL.audio.channels,sizeSamplesPerChannel,SDL.audio.freq);source["connect"](SDL.audioContext["destination"]);SDL.fillWebAudioBufferFromHeap(ptr,sizeSamplesPerChannel,soundBuffer);source["buffer"]=soundBuffer;var curtime=SDL.audioContext["currentTime"];var playtime=Math.max(curtime+SDL.audio.bufferingDelay,SDL.audio.nextPlayTime);if(typeof source["start"]!="undefined"){source["start"](playtime)}else if(typeof source["noteOn"]!="undefined"){source["noteOn"](playtime)}SDL.audio.nextPlayTime=playtime+SDL.audio.bufferDurationSecs}catch(e){err(`Web Audio API error playing back audio: ${e.toString()}`)}};if(obtained){HEAP32[obtained>>>2>>>0]=SDL.audio.freq;HEAP16[obtained+4>>>1>>>0]=SDL.audio.format;HEAP8[obtained+6>>>0]=SDL.audio.channels;HEAP8[obtained+7>>>0]=SDL.audio.silence;HEAP16[obtained+8>>>1>>>0]=SDL.audio.samples;HEAPU32[obtained+16>>>2>>>0]=SDL.audio.callback;HEAPU32[obtained+20>>>2>>>0]=SDL.audio.userdata}SDL.allocateChannels(32)}catch(e){err(`Initializing SDL audio threw an exception: "${e.toString()}"! Continuing without audio`);SDL.audio=null;SDL.allocateChannels(0);if(obtained){HEAP32[obtained>>>2>>>0]=0;HEAP16[obtained+4>>>1>>>0]=0;HEAP8[obtained+6>>>0]=0;HEAP8[obtained+7>>>0]=0;HEAP16[obtained+8>>>1>>>0]=0;HEAPU32[obtained+16>>>2>>>0]=0;HEAPU32[obtained+20>>>2>>>0]=0}}if(!SDL.audio){return-1}return 0}Module["_SDL_OpenAudio"]=_SDL_OpenAudio;_SDL_OpenAudio.sig="ipp";var _SDL_PauseAudio=pauseOn=>{if(!SDL.audio){return}if(pauseOn){if(SDL.audio.timer!==undefined){clearTimeout(SDL.audio.timer);SDL.audio.numAudioTimersPending=0;SDL.audio.timer=undefined}}else if(!SDL.audio.timer){SDL.audio.numAudioTimersPending=1;SDL.audio.timer=safeSetTimeout(SDL.audio.caller,1)}SDL.audio.paused=pauseOn};Module["_SDL_PauseAudio"]=_SDL_PauseAudio;_SDL_PauseAudio.sig="vi";var _SDL_CloseAudio=()=>{if(SDL.audio){if(SDL.audio.callbackRemover){SDL.audio.callbackRemover();SDL.audio.callbackRemover=null}_SDL_PauseAudio(1);_free(SDL.audio.buffer);SDL.audio=null;SDL.allocateChannels(0)}};Module["_SDL_CloseAudio"]=_SDL_CloseAudio;_SDL_CloseAudio.sig="v";var _SDL_LockAudio=()=>{};Module["_SDL_LockAudio"]=_SDL_LockAudio;_SDL_LockAudio.sig="v";var _SDL_UnlockAudio=()=>{};Module["_SDL_UnlockAudio"]=_SDL_UnlockAudio;_SDL_UnlockAudio.sig="v";function _SDL_CreateMutex(){return 0}Module["_SDL_CreateMutex"]=_SDL_CreateMutex;_SDL_CreateMutex.sig="p";function _SDL_mutexP(mutex){mutex>>>=0;return 0}Module["_SDL_mutexP"]=_SDL_mutexP;_SDL_mutexP.sig="ip";function _SDL_mutexV(mutex){mutex>>>=0;return 0}Module["_SDL_mutexV"]=_SDL_mutexV;_SDL_mutexV.sig="ip";function _SDL_DestroyMutex(mutex){mutex>>>=0}Module["_SDL_DestroyMutex"]=_SDL_DestroyMutex;_SDL_DestroyMutex.sig="vp";function _SDL_CreateCond(){return 0}Module["_SDL_CreateCond"]=_SDL_CreateCond;_SDL_CreateCond.sig="p";function _SDL_CondSignal(cond){cond>>>=0}Module["_SDL_CondSignal"]=_SDL_CondSignal;_SDL_CondSignal.sig="ip";function _SDL_CondWait(cond,mutex){cond>>>=0;mutex>>>=0}Module["_SDL_CondWait"]=_SDL_CondWait;_SDL_CondWait.sig="ipp";function _SDL_DestroyCond(cond){cond>>>=0}Module["_SDL_DestroyCond"]=_SDL_DestroyCond;_SDL_DestroyCond.sig="vp";var _SDL_StartTextInput=()=>{SDL.textInput=true};Module["_SDL_StartTextInput"]=_SDL_StartTextInput;_SDL_StartTextInput.sig="v";var _SDL_StopTextInput=()=>{SDL.textInput=false};Module["_SDL_StopTextInput"]=_SDL_StopTextInput;_SDL_StopTextInput.sig="v";var _Mix_Init=flags=>{if(!flags)return 0;return 8};Module["_Mix_Init"]=_Mix_Init;_Mix_Init.sig="ii";var _Mix_Quit=()=>{};Module["_Mix_Quit"]=_Mix_Quit;_Mix_Quit.sig="v";var _Mix_OpenAudio=(frequency,format,channels,chunksize)=>{SDL.openAudioContext();autoResumeAudioContext(SDL.audioContext);SDL.allocateChannels(32);SDL.mixerFrequency=frequency;SDL.mixerFormat=format;SDL.mixerNumChannels=channels;SDL.mixerChunkSize=chunksize;return 0};Module["_Mix_OpenAudio"]=_Mix_OpenAudio;_Mix_OpenAudio.sig="iiiii";var _Mix_CloseAudio=_SDL_CloseAudio;Module["_Mix_CloseAudio"]=_Mix_CloseAudio;_Mix_CloseAudio.sig="v";var _Mix_AllocateChannels=num=>{SDL.allocateChannels(num);return num};Module["_Mix_AllocateChannels"]=_Mix_AllocateChannels;_Mix_AllocateChannels.sig="ii";function _Mix_ChannelFinished(func){func>>>=0;SDL.channelFinished=func}Module["_Mix_ChannelFinished"]=_Mix_ChannelFinished;_Mix_ChannelFinished.sig="vp";var _Mix_Volume=(channel,volume)=>{if(channel==-1){for(var i=0;i{left/=255;right/=255;SDL.setPannerPosition(SDL.channels[channel],right-left,0,.1);return 1};Module["_Mix_SetPanning"]=_Mix_SetPanning;_Mix_SetPanning.sig="iiii";function _Mix_LoadWAV_RW(rwopsID,freesrc){rwopsID>>>=0;var rwops=SDL.rwops[rwopsID];if(rwops===undefined)return 0;var filename="";var audio;var webAudio;var bytes;if(rwops.filename!==undefined){filename=PATH_FS.resolve(rwops.filename);var raw=preloadedAudios[filename];if(!raw){if(raw===null)err("Trying to reuse preloaded audio, but freePreloadedMediaOnUse is set!");if(!Module.noAudioDecoding)warnOnce("Cannot find preloaded audio "+filename);try{bytes=FS.readFile(filename)}catch(e){err(`Couldn't find file for: ${filename}`);return 0}}if(Module["freePreloadedMediaOnUse"]){preloadedAudios[filename]=null}audio=raw}else if(rwops.bytes!==undefined){if(SDL.webAudioAvailable())bytes=HEAPU8.buffer.slice(rwops.bytes,rwops.bytes+rwops.count);else bytes=HEAPU8.subarray(rwops.bytes>>>0,rwops.bytes+rwops.count>>>0)}else{return 0}var arrayBuffer=bytes?bytes.buffer||bytes:bytes;var canPlayWithWebAudio=Module["SDL_canPlayWithWebAudio"]===undefined||Module["SDL_canPlayWithWebAudio"](filename,arrayBuffer);if(bytes!==undefined&&SDL.webAudioAvailable()&&canPlayWithWebAudio){audio=undefined;webAudio={};webAudio.onDecodeComplete=[];var onDecodeComplete=data=>{webAudio.decodedBuffer=data;webAudio.onDecodeComplete.forEach(e=>e());webAudio.onDecodeComplete=undefined};SDL.audioContext["decodeAudioData"](arrayBuffer,onDecodeComplete)}else if(audio===undefined&&bytes){var blob=new Blob([bytes],{type:rwops.mimetype});var url=URL.createObjectURL(blob);audio=new Audio;audio.src=url;audio.mozAudioChannelType="content"}var id=SDL.audios.length;SDL.audios.push({source:filename,audio:audio,webAudio:webAudio});return id}Module["_Mix_LoadWAV_RW"]=_Mix_LoadWAV_RW;_Mix_LoadWAV_RW.sig="ppi";function _Mix_LoadWAV(filename){filename>>>=0;var rwops=_SDL_RWFromFile(filename,0);var result=_Mix_LoadWAV_RW(rwops,0);_SDL_FreeRW(rwops);return result}Module["_Mix_LoadWAV"]=_Mix_LoadWAV;_Mix_LoadWAV.sig="pp";function _Mix_QuickLoad_RAW(mem,len){mem>>>=0;var audio;var webAudio;var numSamples=len>>1;var buffer=new Float32Array(numSamples);for(var i=0;i>>1>>>0]/32768}if(SDL.webAudioAvailable()){webAudio={};webAudio.decodedBuffer=buffer}else{audio=new Audio;audio.mozAudioChannelType="content";audio.numChannels=SDL.mixerNumChannels;audio.frequency=SDL.mixerFrequency}var id=SDL.audios.length;SDL.audios.push({source:"",audio:audio,webAudio:webAudio,buffer:buffer});return id}Module["_Mix_QuickLoad_RAW"]=_Mix_QuickLoad_RAW;_Mix_QuickLoad_RAW.sig="ppi";function _Mix_FreeChunk(id){id>>>=0;SDL.audios[id]=null}Module["_Mix_FreeChunk"]=_Mix_FreeChunk;_Mix_FreeChunk.sig="vp";var _Mix_ReserveChannels=num=>{SDL.channelMinimumNumber=num};Module["_Mix_ReserveChannels"]=_Mix_ReserveChannels;_Mix_ReserveChannels.sig="ii";function _Mix_PlayChannelTimed(channel,id,loops,ticks){id>>>=0;assert(ticks==-1);var info=SDL.audios[id];if(!info)return-1;if(!info.audio&&!info.webAudio)return-1;if(channel==-1){for(var i=SDL.channelMinimumNumber;i0;Module["_Mix_FadingChannel"]=_Mix_FadingChannel;_Mix_FadingChannel.sig="ii";var _Mix_HaltChannel=channel=>{function halt(channel){var info=SDL.channels[channel];if(info.audio){info.audio.pause();info.audio=null}if(SDL.channelFinished){getWasmTableEntry(SDL.channelFinished)(channel)}}if(channel!=-1){halt(channel)}else{for(var i=0;i{var audio=SDL.music.audio;if(audio){audio.src=audio.src;audio.currentPosition=0;audio.pause()}SDL.music.audio=null;if(SDL.hookMusicFinished){getWasmTableEntry(SDL.hookMusicFinished)()}return 0};Module["_Mix_HaltMusic"]=_Mix_HaltMusic;_Mix_HaltMusic.sig="i";function _Mix_HookMusicFinished(func){func>>>=0;SDL.hookMusicFinished=func;if(SDL.music.audio){SDL.music.audio["onended"]=_Mix_HaltMusic}}Module["_Mix_HookMusicFinished"]=_Mix_HookMusicFinished;_Mix_HookMusicFinished.sig="vp";var _Mix_VolumeMusic=volume=>SDL.setGetVolume(SDL.music,volume);Module["_Mix_VolumeMusic"]=_Mix_VolumeMusic;_Mix_VolumeMusic.sig="ii";function _Mix_LoadMUS_RW(filename){filename>>>=0;return _Mix_LoadWAV_RW(filename,0)}Module["_Mix_LoadMUS_RW"]=_Mix_LoadMUS_RW;_Mix_LoadMUS_RW.sig="pp";function _Mix_LoadMUS(filename){filename>>>=0;var rwops=_SDL_RWFromFile(filename,0);var result=_Mix_LoadMUS_RW(rwops);_SDL_FreeRW(rwops);return result}Module["_Mix_LoadMUS"]=_Mix_LoadMUS;_Mix_LoadMUS.sig="pp";var _Mix_FreeMusic=_Mix_FreeChunk;Module["_Mix_FreeMusic"]=_Mix_FreeMusic;_Mix_FreeMusic.sig="vp";function _Mix_PlayMusic(id,loops){id>>>=0;if(SDL.music.audio){if(!SDL.music.audio.paused)err(`Music is already playing. ${SDL.music.source}`);SDL.music.audio.pause()}var info=SDL.audios[id];var audio;if(info.webAudio){audio={};audio.resource=info;audio.paused=false;audio.currentPosition=0;audio.play=function(){SDL.playWebAudio(this)};audio.pause=function(){SDL.pauseWebAudio(this)}}else if(info.audio){audio=info.audio}audio["onended"]=function(){if(SDL.music.audio==this)_Mix_HaltMusic()};audio.loop=loops!=0&&loops!=1;audio.volume=SDL.music.volume;SDL.music.audio=audio;audio.play();return 0}Module["_Mix_PlayMusic"]=_Mix_PlayMusic;_Mix_PlayMusic.sig="ipi";var _Mix_PauseMusic=()=>{var audio=SDL.music.audio;audio?.pause()};Module["_Mix_PauseMusic"]=_Mix_PauseMusic;_Mix_PauseMusic.sig="v";var _Mix_ResumeMusic=()=>{var audio=SDL.music.audio;audio?.play()};Module["_Mix_ResumeMusic"]=_Mix_ResumeMusic;_Mix_ResumeMusic.sig="v";var _Mix_FadeInMusicPos=_Mix_PlayMusic;Module["_Mix_FadeInMusicPos"]=_Mix_FadeInMusicPos;_Mix_FadeInMusicPos.sig="ipiid";var _Mix_FadeOutMusic=_Mix_HaltMusic;Module["_Mix_FadeOutMusic"]=_Mix_FadeOutMusic;_Mix_FadeOutMusic.sig="ii";var _Mix_PlayingMusic=()=>SDL.music.audio&&!SDL.music.audio.paused?1:0;Module["_Mix_PlayingMusic"]=_Mix_PlayingMusic;_Mix_PlayingMusic.sig="i";var _Mix_Playing=channel=>{if(channel===-1){var count=0;for(var i=0;i{if(channel===-1){for(var i=0;i{if(channel===-1){var pausedCount=0;for(var i=0;iSDL.music.audio?.paused?1:0;Module["_Mix_PausedMusic"]=_Mix_PausedMusic;_Mix_PausedMusic.sig="i";var _Mix_Resume=channel=>{if(channel===-1){for(var i=0;i{try{var offscreenCanvas=new OffscreenCanvas(0,0);SDL.ttfContext=offscreenCanvas.getContext("2d");if(typeof SDL.ttfContext.measureText!="function"){throw"bad context"}}catch(ex){var canvas=document.createElement("canvas");SDL.ttfContext=canvas.getContext("2d")}return 0};Module["_TTF_Init"]=_TTF_Init;_TTF_Init.sig="i";function _TTF_OpenFont(name,size){name>>>=0;name=PATH.normalize(UTF8ToString(name));var id=SDL.fonts.length;SDL.fonts.push({name:name,size:size});return id}Module["_TTF_OpenFont"]=_TTF_OpenFont;_TTF_OpenFont.sig="ppi";function _TTF_CloseFont(font){font>>>=0;SDL.fonts[font]=null}Module["_TTF_CloseFont"]=_TTF_CloseFont;_TTF_CloseFont.sig="vp";function _TTF_RenderText_Solid(font,text,color){font>>>=0;text>>>=0;color>>>=0;text=UTF8ToString(text)||" ";var fontData=SDL.fonts[font];var w=SDL.estimateTextWidth(fontData,text);var h=fontData.size;color=SDL.loadColorToCSSRGB(color);var fontString=SDL.makeFontString(h,fontData.name);var surf=SDL.makeSurface(w,h,0,false,"text:"+text);var surfData=SDL.surfaces[surf];surfData.ctx.save();surfData.ctx.fillStyle=color;surfData.ctx.font=fontString;surfData.ctx.textBaseline="bottom";surfData.ctx.fillText(text,0,h|0);surfData.ctx.restore();return surf}Module["_TTF_RenderText_Solid"]=_TTF_RenderText_Solid;_TTF_RenderText_Solid.sig="pppp";var _TTF_RenderText_Blended=_TTF_RenderText_Solid;Module["_TTF_RenderText_Blended"]=_TTF_RenderText_Blended;_TTF_RenderText_Blended.sig="pppp";var _TTF_RenderText_Shaded=_TTF_RenderText_Solid;Module["_TTF_RenderText_Shaded"]=_TTF_RenderText_Shaded;_TTF_RenderText_Shaded.sig="ppppp";var _TTF_RenderUTF8_Solid=_TTF_RenderText_Solid;Module["_TTF_RenderUTF8_Solid"]=_TTF_RenderUTF8_Solid;_TTF_RenderUTF8_Solid.sig="pppp";function _TTF_SizeText(font,text,w,h){font>>>=0;text>>>=0;w>>>=0;h>>>=0;var fontData=SDL.fonts[font];if(w){HEAP32[w>>>2>>>0]=SDL.estimateTextWidth(fontData,UTF8ToString(text))}if(h){HEAP32[h>>>2>>>0]=fontData.size}return 0}Module["_TTF_SizeText"]=_TTF_SizeText;_TTF_SizeText.sig="ipppp";var _TTF_SizeUTF8=_TTF_SizeText;Module["_TTF_SizeUTF8"]=_TTF_SizeUTF8;_TTF_SizeUTF8.sig="ipppp";function _TTF_GlyphMetrics(font,ch,minx,maxx,miny,maxy,advance){font>>>=0;minx>>>=0;maxx>>>=0;miny>>>=0;maxy>>>=0;advance>>>=0;var fontData=SDL.fonts[font];var width=SDL.estimateTextWidth(fontData,String.fromCharCode(ch));if(advance){HEAP32[advance>>>2>>>0]=width}if(minx){HEAP32[minx>>>2>>>0]=0}if(maxx){HEAP32[maxx>>>2>>>0]=width}if(miny){HEAP32[miny>>>2>>>0]=0}if(maxy){HEAP32[maxy>>>2>>>0]=fontData.size}}Module["_TTF_GlyphMetrics"]=_TTF_GlyphMetrics;_TTF_GlyphMetrics.sig="ipippppp";function _TTF_FontAscent(font){font>>>=0;var fontData=SDL.fonts[font];return fontData.size*.98|0}Module["_TTF_FontAscent"]=_TTF_FontAscent;_TTF_FontAscent.sig="ip";function _TTF_FontDescent(font){font>>>=0;var fontData=SDL.fonts[font];return fontData.size*.02|0}Module["_TTF_FontDescent"]=_TTF_FontDescent;_TTF_FontDescent.sig="ip";function _TTF_FontHeight(font){font>>>=0;var fontData=SDL.fonts[font];return fontData.size}Module["_TTF_FontHeight"]=_TTF_FontHeight;_TTF_FontHeight.sig="ip";var _TTF_FontLineSkip=_TTF_FontHeight;Module["_TTF_FontLineSkip"]=_TTF_FontLineSkip;_TTF_FontLineSkip.sig="ip";var _TTF_Quit=()=>out("TTF_Quit called (and ignored)");Module["_TTF_Quit"]=_TTF_Quit;_TTF_Quit.sig="v";var SDL_gfx={drawRectangle:(surf,x1,y1,x2,y2,action,cssColor)=>{x1=x1<<16>>16;y1=y1<<16>>16;x2=x2<<16>>16;y2=y2<<16>>16;var surfData=SDL.surfaces[surf];assert(!surfData.locked);var x=x1{x1=x1<<16>>16;y1=y1<<16>>16;x2=x2<<16>>16;y2=y2<<16>>16;var surfData=SDL.surfaces[surf];assert(!surfData.locked);surfData.ctx.save();surfData.ctx.strokeStyle=cssColor;surfData.ctx.beginPath();surfData.ctx.moveTo(x1,y1);surfData.ctx.lineTo(x2,y2);surfData.ctx.stroke();surfData.ctx.restore()},drawEllipse:(surf,x,y,rx,ry,action,cssColor)=>{x=x<<16>>16;y=y<<16>>16;rx=rx<<16>>16;ry=ry<<16>>16;var surfData=SDL.surfaces[surf];assert(!surfData.locked);surfData.ctx.save();surfData.ctx.beginPath();surfData.ctx.translate(x,y);surfData.ctx.scale(rx,ry);surfData.ctx.arc(0,0,1,0,2*Math.PI);surfData.ctx.restore();surfData.ctx.save();surfData.ctx[action+"Style"]=cssColor;surfData.ctx[action]();surfData.ctx.restore()},translateColorToCSSRGBA:rgba=>`rgba(${rgba>>>24},${rgba>>16&255},${rgba>>8&255},${rgba&255})`};Module["SDL_gfx"]=SDL_gfx;function _boxColor(surf,x1,y1,x2,y2,color){surf>>>=0;return SDL_gfx.drawRectangle(surf,x1,y1,x2,y2,"fill",SDL_gfx.translateColorToCSSRGBA(color))}Module["_boxColor"]=_boxColor;_boxColor.sig="ipiiiii";function _boxRGBA(surf,x1,y1,x2,y2,r,g,b,a){surf>>>=0;return SDL_gfx.drawRectangle(surf,x1,y1,x2,y2,"fill",SDL.translateRGBAToCSSRGBA(r,g,b,a))}Module["_boxRGBA"]=_boxRGBA;_boxRGBA.sig="ipiiiiiiii";function _rectangleColor(surf,x1,y1,x2,y2,color){surf>>>=0;return SDL_gfx.drawRectangle(surf,x1,y1,x2,y2,"stroke",SDL_gfx.translateColorToCSSRGBA(color))}Module["_rectangleColor"]=_rectangleColor;_rectangleColor.sig="ipiiiii";function _rectangleRGBA(surf,x1,y1,x2,y2,r,g,b,a){surf>>>=0;return SDL_gfx.drawRectangle(surf,x1,y1,x2,y2,"stroke",SDL.translateRGBAToCSSRGBA(r,g,b,a))}Module["_rectangleRGBA"]=_rectangleRGBA;_rectangleRGBA.sig="ipiiiiiiii";function _ellipseColor(surf,x,y,rx,ry,color){surf>>>=0;return SDL_gfx.drawEllipse(surf,x,y,rx,ry,"stroke",SDL_gfx.translateColorToCSSRGBA(color))}Module["_ellipseColor"]=_ellipseColor;_ellipseColor.sig="ipiiiii";function _ellipseRGBA(surf,x,y,rx,ry,r,g,b,a){surf>>>=0;return SDL_gfx.drawEllipse(surf,x,y,rx,ry,"stroke",SDL.translateRGBAToCSSRGBA(r,g,b,a))}Module["_ellipseRGBA"]=_ellipseRGBA;_ellipseRGBA.sig="ipiiiiiiii";function _filledEllipseColor(surf,x,y,rx,ry,color){surf>>>=0;return SDL_gfx.drawEllipse(surf,x,y,rx,ry,"fill",SDL_gfx.translateColorToCSSRGBA(color))}Module["_filledEllipseColor"]=_filledEllipseColor;_filledEllipseColor.sig="ipiiiii";function _filledEllipseRGBA(surf,x,y,rx,ry,r,g,b,a){surf>>>=0;return SDL_gfx.drawEllipse(surf,x,y,rx,ry,"fill",SDL.translateRGBAToCSSRGBA(r,g,b,a))}Module["_filledEllipseRGBA"]=_filledEllipseRGBA;_filledEllipseRGBA.sig="ipiiiiiiii";function _lineColor(surf,x1,y1,x2,y2,color){surf>>>=0;return SDL_gfx.drawLine(surf,x1,y1,x2,y2,SDL_gfx.translateColorToCSSRGBA(color))}Module["_lineColor"]=_lineColor;_lineColor.sig="ipiiiii";function _lineRGBA(surf,x1,y1,x2,y2,r,g,b,a){surf>>>=0;return SDL_gfx.drawLine(surf,x1,y1,x2,y2,SDL.translateRGBAToCSSRGBA(r,g,b,a))}Module["_lineRGBA"]=_lineRGBA;_lineRGBA.sig="ipiiiiiiii";function _pixelRGBA(surf,x1,y1,r,g,b,a){surf>>>=0;return _boxRGBA(surf,x1,y1,x1,y1,r,g,b,a)}Module["_pixelRGBA"]=_pixelRGBA;_pixelRGBA.sig="ipiiiiii";var _SDL_GL_SetAttribute=(attr,value)=>{if(!(attr in SDL.glAttributes)){abort("Unknown SDL GL attribute ("+attr+"). Please check if your SDL version is supported.")}SDL.glAttributes[attr]=value};Module["_SDL_GL_SetAttribute"]=_SDL_GL_SetAttribute;_SDL_GL_SetAttribute.sig="iii";function _SDL_GL_GetAttribute(attr,value){value>>>=0;if(!(attr in SDL.glAttributes)){abort("Unknown SDL GL attribute ("+attr+"). Please check if your SDL version is supported.")}if(value)HEAP32[value>>>2>>>0]=SDL.glAttributes[attr];return 0}Module["_SDL_GL_GetAttribute"]=_SDL_GL_GetAttribute;_SDL_GL_GetAttribute.sig="iip";var _SDL_GL_SwapBuffers=()=>{Browser.doSwapBuffers?.()};Module["_SDL_GL_SwapBuffers"]=_SDL_GL_SwapBuffers;_SDL_GL_SwapBuffers.sig="v";function _SDL_GL_ExtensionSupported(extension){extension>>>=0;return Module.ctx.getExtension(extension)|0}Module["_SDL_GL_ExtensionSupported"]=_SDL_GL_ExtensionSupported;_SDL_GL_ExtensionSupported.sig="ip";function _SDL_DestroyWindow(window){window>>>=0}Module["_SDL_DestroyWindow"]=_SDL_DestroyWindow;_SDL_DestroyWindow.sig="vp";function _SDL_DestroyRenderer(renderer){renderer>>>=0}Module["_SDL_DestroyRenderer"]=_SDL_DestroyRenderer;_SDL_DestroyRenderer.sig="vp";function _SDL_GetWindowFlags(window){window>>>=0;if(Browser.isFullscreen){return 1}return 0}Module["_SDL_GetWindowFlags"]=_SDL_GetWindowFlags;_SDL_GetWindowFlags.sig="ip";function _SDL_GL_SwapWindow(window){window>>>=0}Module["_SDL_GL_SwapWindow"]=_SDL_GL_SwapWindow;_SDL_GL_SwapWindow.sig="vp";function _SDL_GL_MakeCurrent(window,context){window>>>=0;context>>>=0}Module["_SDL_GL_MakeCurrent"]=_SDL_GL_MakeCurrent;_SDL_GL_MakeCurrent.sig="ipp";function _SDL_GL_DeleteContext(context){context>>>=0}Module["_SDL_GL_DeleteContext"]=_SDL_GL_DeleteContext;_SDL_GL_DeleteContext.sig="vp";var _SDL_GL_GetSwapInterval=()=>{if(Browser.mainLoop.timingMode==1)return Browser.mainLoop.timingValue;else return 0};Module["_SDL_GL_GetSwapInterval"]=_SDL_GL_GetSwapInterval;_SDL_GL_GetSwapInterval.sig="i";var _SDL_GL_SetSwapInterval=state=>{_emscripten_set_main_loop_timing(1,state)};Module["_SDL_GL_SetSwapInterval"]=_SDL_GL_SetSwapInterval;_SDL_GL_SetSwapInterval.sig="ii";function _SDL_SetWindowTitle(window,title){window>>>=0;title>>>=0;if(title)document.title=UTF8ToString(title)}Module["_SDL_SetWindowTitle"]=_SDL_SetWindowTitle;_SDL_SetWindowTitle.sig="vpp";function _SDL_GetWindowSize(window,width,height){window>>>=0;width>>>=0;height>>>=0;var w=Module["canvas"].width;var h=Module["canvas"].height;if(width)HEAP32[width>>>2>>>0]=w;if(height)HEAP32[height>>>2>>>0]=h}Module["_SDL_GetWindowSize"]=_SDL_GetWindowSize;_SDL_GetWindowSize.sig="vppp";function _SDL_LogSetOutputFunction(callback,userdata){callback>>>=0;userdata>>>=0}Module["_SDL_LogSetOutputFunction"]=_SDL_LogSetOutputFunction;_SDL_LogSetOutputFunction.sig="vpp";function _SDL_SetWindowFullscreen(window,fullscreen){window>>>=0;if(Browser.isFullscreen){Module["canvas"].exitFullscreen();return 1}return 0}Module["_SDL_SetWindowFullscreen"]=_SDL_SetWindowFullscreen;_SDL_SetWindowFullscreen.sig="ipi";var _SDL_ClearError=()=>{};Module["_SDL_ClearError"]=_SDL_ClearError;_SDL_ClearError.sig="v";var _SDL_SetGamma=(r,g,b)=>-1;Module["_SDL_SetGamma"]=_SDL_SetGamma;_SDL_SetGamma.sig="ifff";function _SDL_SetGammaRamp(redTable,greenTable,blueTable){redTable>>>=0;greenTable>>>=0;blueTable>>>=0;return-1}Module["_SDL_SetGammaRamp"]=_SDL_SetGammaRamp;_SDL_SetGammaRamp.sig="ippp";var _SDL_NumJoysticks=()=>{var count=0;var gamepads=SDL.getGamepads();for(var i=0;iSDL.lastJoystickState.hasOwnProperty(deviceIndex+1)?1:0;Module["_SDL_JoystickOpened"]=_SDL_JoystickOpened;_SDL_JoystickOpened.sig="ii";function _SDL_JoystickIndex(joystick){joystick>>>=0;return joystick-1}Module["_SDL_JoystickIndex"]=_SDL_JoystickIndex;_SDL_JoystickIndex.sig="ip";function _SDL_JoystickNumAxes(joystick){joystick>>>=0;var gamepad=SDL.getGamepad(joystick-1);if(gamepad){return gamepad.axes.length}return 0}Module["_SDL_JoystickNumAxes"]=_SDL_JoystickNumAxes;_SDL_JoystickNumAxes.sig="ip";function _SDL_JoystickNumBalls(joystick){joystick>>>=0;return 0}Module["_SDL_JoystickNumBalls"]=_SDL_JoystickNumBalls;_SDL_JoystickNumBalls.sig="ip";function _SDL_JoystickNumHats(joystick){joystick>>>=0;return 0}Module["_SDL_JoystickNumHats"]=_SDL_JoystickNumHats;_SDL_JoystickNumHats.sig="ip";function _SDL_JoystickNumButtons(joystick){joystick>>>=0;var gamepad=SDL.getGamepad(joystick-1);if(gamepad){return gamepad.buttons.length}return 0}Module["_SDL_JoystickNumButtons"]=_SDL_JoystickNumButtons;_SDL_JoystickNumButtons.sig="ip";var _SDL_JoystickUpdate=()=>SDL.queryJoysticks();Module["_SDL_JoystickUpdate"]=_SDL_JoystickUpdate;_SDL_JoystickUpdate.sig="v";var _SDL_JoystickEventState=state=>{if(state<0){return SDL.joystickEventState}return SDL.joystickEventState=state};Module["_SDL_JoystickEventState"]=_SDL_JoystickEventState;_SDL_JoystickEventState.sig="ii";function _SDL_JoystickGetAxis(joystick,axis){joystick>>>=0;var gamepad=SDL.getGamepad(joystick-1);if(gamepad&&gamepad.axes.length>axis){return SDL.joystickAxisValueConversion(gamepad.axes[axis])}return 0}Module["_SDL_JoystickGetAxis"]=_SDL_JoystickGetAxis;_SDL_JoystickGetAxis.sig="ipi";function _SDL_JoystickGetHat(joystick,hat){joystick>>>=0;return 0}Module["_SDL_JoystickGetHat"]=_SDL_JoystickGetHat;_SDL_JoystickGetHat.sig="ipi";function _SDL_JoystickGetBall(joystick,ball,dxptr,dyptr){joystick>>>=0;dxptr>>>=0;dyptr>>>=0;return-1}Module["_SDL_JoystickGetBall"]=_SDL_JoystickGetBall;_SDL_JoystickGetBall.sig="ipipp";function _SDL_JoystickGetButton(joystick,button){joystick>>>=0;var gamepad=SDL.getGamepad(joystick-1);if(gamepad&&gamepad.buttons.length>button){return SDL.getJoystickButtonState(gamepad.buttons[button])?1:0}return 0}Module["_SDL_JoystickGetButton"]=_SDL_JoystickGetButton;_SDL_JoystickGetButton.sig="ipi";function _SDL_JoystickClose(joystick){joystick>>>=0;delete SDL.lastJoystickState[joystick]}Module["_SDL_JoystickClose"]=_SDL_JoystickClose;_SDL_JoystickClose.sig="vp";var _SDL_InitSubSystem=flags=>0;Module["_SDL_InitSubSystem"]=_SDL_InitSubSystem;_SDL_InitSubSystem.sig="ii";function _SDL_RWFromConstMem(mem,size){mem>>>=0;var id=SDL.rwops.length;SDL.rwops.push({bytes:mem,count:size});return id}Module["_SDL_RWFromConstMem"]=_SDL_RWFromConstMem;_SDL_RWFromConstMem.sig="ppi";var _SDL_RWFromMem=_SDL_RWFromConstMem;Module["_SDL_RWFromMem"]=_SDL_RWFromMem;_SDL_RWFromMem.sig="ppi";var _SDL_GetNumAudioDrivers=()=>1;Module["_SDL_GetNumAudioDrivers"]=_SDL_GetNumAudioDrivers;_SDL_GetNumAudioDrivers.sig="i";function _SDL_GetCurrentAudioDriver(){return stringToNewUTF8("Emscripten Audio")}Module["_SDL_GetCurrentAudioDriver"]=_SDL_GetCurrentAudioDriver;_SDL_GetCurrentAudioDriver.sig="p";var _SDL_GetScancodeFromKey=key=>SDL.scanCodes[key];Module["_SDL_GetScancodeFromKey"]=_SDL_GetScancodeFromKey;_SDL_GetScancodeFromKey.sig="ii";function _SDL_GetAudioDriver(index){return _SDL_GetCurrentAudioDriver()}Module["_SDL_GetAudioDriver"]=_SDL_GetAudioDriver;_SDL_GetAudioDriver.sig="pi";var _SDL_EnableUNICODE=on=>{var ret=SDL.unicode||0;SDL.unicode=on;return ret};Module["_SDL_EnableUNICODE"]=_SDL_EnableUNICODE;_SDL_EnableUNICODE.sig="ii";var _SDL_AddTimer=function(interval,callback,param){callback>>>=0;param>>>=0;return safeSetTimeout(()=>getWasmTableEntry(callback)(interval,param),interval)};Module["_SDL_AddTimer"]=_SDL_AddTimer;_SDL_AddTimer.sig="iipp";var _SDL_RemoveTimer=id=>{clearTimeout(id);return true};Module["_SDL_RemoveTimer"]=_SDL_RemoveTimer;_SDL_RemoveTimer.sig="ii";function _SDL_CreateThread(fs,data,pfnBeginThread,pfnEndThread){fs>>>=0;data>>>=0;throw"SDL threads cannot be supported in the web platform because they assume shared state. See emscripten_create_worker etc. for a message-passing concurrency model that does let you run code in another thread."}Module["_SDL_CreateThread"]=_SDL_CreateThread;_SDL_CreateThread.sig="ppp";function _SDL_WaitThread(thread,status){thread>>>=0;status>>>=0;throw"SDL_WaitThread"}Module["_SDL_WaitThread"]=_SDL_WaitThread;_SDL_WaitThread.sig="vpp";function _SDL_GetThreadID(thread){thread>>>=0;throw"SDL_GetThreadID"}Module["_SDL_GetThreadID"]=_SDL_GetThreadID;_SDL_GetThreadID.sig="pp";function _SDL_ThreadID(){return 0}Module["_SDL_ThreadID"]=_SDL_ThreadID;_SDL_ThreadID.sig="p";function _SDL_AllocRW(){throw"SDL_AllocRW: TODO"}Module["_SDL_AllocRW"]=_SDL_AllocRW;_SDL_AllocRW.sig="p";function _SDL_CondBroadcast(cond){cond>>>=0;throw"SDL_CondBroadcast: TODO"}Module["_SDL_CondBroadcast"]=_SDL_CondBroadcast;_SDL_CondBroadcast.sig="ip";function _SDL_CondWaitTimeout(cond,mutex,ms){cond>>>=0;mutex>>>=0;throw"SDL_CondWaitTimeout: TODO"}Module["_SDL_CondWaitTimeout"]=_SDL_CondWaitTimeout;_SDL_CondWaitTimeout.sig="ippi";var _SDL_WM_IconifyWindow=()=>{throw"SDL_WM_IconifyWindow TODO"};Module["_SDL_WM_IconifyWindow"]=_SDL_WM_IconifyWindow;_SDL_WM_IconifyWindow.sig="i";function _Mix_SetPostMix(func,arg){func>>>=0;arg>>>=0;return warnOnce("Mix_SetPostMix: TODO")}Module["_Mix_SetPostMix"]=_Mix_SetPostMix;_Mix_SetPostMix.sig="vpp";function _Mix_VolumeChunk(chunk,volume){chunk>>>=0;throw"Mix_VolumeChunk: TODO"}Module["_Mix_VolumeChunk"]=_Mix_VolumeChunk;_Mix_VolumeChunk.sig="ipi";var _Mix_SetPosition=(channel,angle,distance)=>{throw"Mix_SetPosition: TODO"};Module["_Mix_SetPosition"]=_Mix_SetPosition;_Mix_SetPosition.sig="iiii";function _Mix_QuerySpec(frequency,format,channels){frequency>>>=0;format>>>=0;channels>>>=0;throw"Mix_QuerySpec: TODO"}Module["_Mix_QuerySpec"]=_Mix_QuerySpec;_Mix_QuerySpec.sig="ippp";function _Mix_FadeInChannelTimed(channel,chunk,loop,ms,ticks){chunk>>>=0;throw"Mix_FadeInChannelTimed"}Module["_Mix_FadeInChannelTimed"]=_Mix_FadeInChannelTimed;_Mix_FadeInChannelTimed.sig="iipiii";var _Mix_FadeOutChannel=()=>{throw"Mix_FadeOutChannel"};Module["_Mix_FadeOutChannel"]=_Mix_FadeOutChannel;_Mix_FadeOutChannel.sig="iii";function _Mix_Linked_Version(){throw"Mix_Linked_Version: TODO"}Module["_Mix_Linked_Version"]=_Mix_Linked_Version;_Mix_Linked_Version.sig="p";function _SDL_SaveBMP_RW(surface,dst,freedst){surface>>>=0;dst>>>=0;throw"SDL_SaveBMP_RW: TODO"}Module["_SDL_SaveBMP_RW"]=_SDL_SaveBMP_RW;_SDL_SaveBMP_RW.sig="ippi";function _SDL_WM_SetIcon(icon,mask){icon>>>=0;mask>>>=0}Module["_SDL_WM_SetIcon"]=_SDL_WM_SetIcon;_SDL_WM_SetIcon.sig="vpp";var _SDL_HasRDTSC=()=>0;Module["_SDL_HasRDTSC"]=_SDL_HasRDTSC;_SDL_HasRDTSC.sig="i";var _SDL_HasMMX=()=>0;Module["_SDL_HasMMX"]=_SDL_HasMMX;_SDL_HasMMX.sig="i";var _SDL_HasMMXExt=()=>0;Module["_SDL_HasMMXExt"]=_SDL_HasMMXExt;_SDL_HasMMXExt.sig="i";var _SDL_Has3DNow=()=>0;Module["_SDL_Has3DNow"]=_SDL_Has3DNow;_SDL_Has3DNow.sig="i";var _SDL_Has3DNowExt=()=>0;Module["_SDL_Has3DNowExt"]=_SDL_Has3DNowExt;_SDL_Has3DNowExt.sig="i";var _SDL_HasSSE=()=>0;Module["_SDL_HasSSE"]=_SDL_HasSSE;_SDL_HasSSE.sig="i";var _SDL_HasSSE2=()=>0;Module["_SDL_HasSSE2"]=_SDL_HasSSE2;_SDL_HasSSE2.sig="i";var _SDL_HasAltiVec=()=>0;Module["_SDL_HasAltiVec"]=_SDL_HasAltiVec;_SDL_HasAltiVec.sig="i";if(!Module.createInvoke){Module.createInvoke=Module.createInvokeFunction}registerWasmPlugin();FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();Module["FS_createPath"]=FS.createPath;Module["FS_createDataFile"]=FS.createDataFile;Module["FS_createPreloadedFile"]=FS.createPreloadedFile;Module["FS_unlink"]=FS.unlink;Module["FS_createLazyFile"]=FS.createLazyFile;Module["FS_createDevice"]=FS.createDevice;if(ENVIRONMENT_IS_NODE){NODEFS.staticInit()}var GLctx;for(var i=0;i<32;++i)tempFixedLengthArray.push(new Array(i));var miniTempWebGLFloatBuffersStorage=new Float32Array(288);for(var i=0;i<288;++i){miniTempWebGLFloatBuffers[i]=miniTempWebGLFloatBuffersStorage.subarray(0,i)}var miniTempWebGLIntBuffersStorage=new Int32Array(288);for(var i=0;i<288;++i){miniTempWebGLIntBuffers[i]=miniTempWebGLIntBuffersStorage.subarray(0,i)}var emSetImmediate;var emClearImmediate;if(typeof setImmediate!="undefined"){emSetImmediate=setImmediateWrapped;emClearImmediate=clearImmediateWrapped}else if(typeof addEventListener=="function"){var __setImmediate_id_counter=0;var __setImmediate_queue=[];var __setImmediate_message_id="_si";var __setImmediate_cb=e=>{if(e.data===__setImmediate_message_id){e.stopPropagation();__setImmediate_queue.shift()();++__setImmediate_id_counter}};addEventListener("message",__setImmediate_cb,true);emSetImmediate=func=>{postMessage(__setImmediate_message_id,"*");return __setImmediate_id_counter+__setImmediate_queue.push(func)-1};emClearImmediate=id=>{var index=id-__setImmediate_id_counter;if(index>=0&&index<__setImmediate_queue.length)__setImmediate_queue[index]=()=>{}}}Module["requestFullscreen"]=Browser.requestFullscreen;Module["requestAnimationFrame"]=Browser.requestAnimationFrame;Module["setCanvasSize"]=Browser.setCanvasSize;Module["pauseMainLoop"]=Browser.mainLoop.pause;Module["resumeMainLoop"]=Browser.mainLoop.resume;Module["getUserMedia"]=Browser.getUserMedia;Module["createContext"]=Browser.createContext;var preloadedImages={};var preloadedAudios={};var wasmImports={IMG_Init:_IMG_Init,IMG_Load:_IMG_Load,IMG_Load_RW:_IMG_Load_RW,IMG_Quit:_IMG_Quit,JsArray_count_js:JsArray_count_js,JsArray_index_js:JsArray_index_js,JsArray_inplace_repeat_js:JsArray_inplace_repeat_js,JsArray_repeat_js:JsArray_repeat_js,JsArray_reverse_js:JsArray_reverse_js,JsArray_reversed_iterator:JsArray_reversed_iterator,JsBuffer_DecodeString_js:JsBuffer_DecodeString_js,JsBuffer_get_info:JsBuffer_get_info,JsDoubleProxy_unwrap_helper:JsDoubleProxy_unwrap_helper,JsException_new_helper:JsException_new_helper,JsMap_GetIter_js:JsMap_GetIter_js,JsMap_clear_js:JsMap_clear_js,JsModule_GetAll_js:JsModule_GetAll_js,JsObjMap_GetIter_js:JsObjMap_GetIter_js,JsObjMap_ass_subscript_js:JsObjMap_ass_subscript_js,JsObjMap_contains_js:JsObjMap_contains_js,JsObjMap_length_js:JsObjMap_length_js,JsObjMap_subscript_js:JsObjMap_subscript_js,JsProxy_Bool_js:JsProxy_Bool_js,JsProxy_DelAttr_js:JsProxy_DelAttr_js,JsProxy_Dir_js:JsProxy_Dir_js,JsProxy_GetAsyncIter_js:JsProxy_GetAsyncIter_js,JsProxy_GetAttr_js:JsProxy_GetAttr_js,JsProxy_GetIter_js:JsProxy_GetIter_js,JsProxy_SetAttr_js:JsProxy_SetAttr_js,JsProxy_compute_typeflags:JsProxy_compute_typeflags,JsProxy_subscript_js:JsProxy_subscript_js,JsvArray_Check:JsvArray_Check,JsvArray_Delete:JsvArray_Delete,JsvArray_Extend:JsvArray_Extend,JsvArray_Get:JsvArray_Get,JsvArray_Insert:JsvArray_Insert,JsvArray_New:JsvArray_New,JsvArray_Push:JsvArray_Push,JsvArray_Set:JsvArray_Set,JsvArray_ShallowCopy:JsvArray_ShallowCopy,JsvArray_slice:JsvArray_slice,JsvArray_slice_assign:JsvArray_slice_assign,JsvAsyncGenerator_Check:JsvAsyncGenerator_Check,JsvBuffer_assignFromPtr:JsvBuffer_assignFromPtr,JsvBuffer_assignToPtr:JsvBuffer_assignToPtr,JsvBuffer_intoFile:JsvBuffer_intoFile,JsvBuffer_readFromFile:JsvBuffer_readFromFile,JsvBuffer_writeToFile:JsvBuffer_writeToFile,JsvError_Throw:JsvError_Throw,JsvFunction_CallBound:JsvFunction_CallBound,JsvFunction_Call_OneArg:JsvFunction_Call_OneArg,JsvFunction_Check:JsvFunction_Check,JsvFunction_Construct:JsvFunction_Construct,JsvGenerator_Check:JsvGenerator_Check,JsvLiteralMap_New:JsvLiteralMap_New,JsvMap_New:JsvMap_New,JsvMap_Set:JsvMap_Set,JsvNoValue_Check:JsvNoValue_Check,JsvNum_fromDigits:JsvNum_fromDigits,JsvNum_fromDouble:JsvNum_fromDouble,JsvNum_fromInt:JsvNum_fromInt,JsvObject_CallMethod:JsvObject_CallMethod,JsvObject_CallMethod_NoArgs:JsvObject_CallMethod_NoArgs,JsvObject_CallMethod_OneArg:JsvObject_CallMethod_OneArg,JsvObject_CallMethod_TwoArgs:JsvObject_CallMethod_TwoArgs,JsvObject_Entries:JsvObject_Entries,JsvObject_Keys:JsvObject_Keys,JsvObject_New:JsvObject_New,JsvObject_SetAttr:JsvObject_SetAttr,JsvObject_Values:JsvObject_Values,JsvObject_toString:JsvObject_toString,JsvPromise_Check:JsvPromise_Check,JsvPromise_Resolve:JsvPromise_Resolve,JsvPromise_Syncify_handleError:JsvPromise_Syncify_handleError,JsvSet_Add:JsvSet_Add,JsvSet_New:JsvSet_New,JsvUTF8ToString:JsvUTF8ToString,Jsv_constructorName:Jsv_constructorName,Jsv_equal:Jsv_equal,Jsv_greater_than:Jsv_greater_than,Jsv_greater_than_equal:Jsv_greater_than_equal,Jsv_less_than:Jsv_less_than,Jsv_less_than_equal:Jsv_less_than_equal,Jsv_not_equal:Jsv_not_equal,Jsv_to_bool:Jsv_to_bool,Jsv_typeof:Jsv_typeof,Mix_AllocateChannels:_Mix_AllocateChannels,Mix_ChannelFinished:_Mix_ChannelFinished,Mix_CloseAudio:_Mix_CloseAudio,Mix_FadeInChannelTimed:_Mix_FadeInChannelTimed,Mix_FadeInMusicPos:_Mix_FadeInMusicPos,Mix_FadeOutChannel:_Mix_FadeOutChannel,Mix_FadeOutMusic:_Mix_FadeOutMusic,Mix_FadingChannel:_Mix_FadingChannel,Mix_FreeChunk:_Mix_FreeChunk,Mix_FreeMusic:_Mix_FreeMusic,Mix_HaltChannel:_Mix_HaltChannel,Mix_HaltMusic:_Mix_HaltMusic,Mix_HookMusicFinished:_Mix_HookMusicFinished,Mix_Init:_Mix_Init,Mix_Linked_Version:_Mix_Linked_Version,Mix_LoadMUS:_Mix_LoadMUS,Mix_LoadMUS_RW:_Mix_LoadMUS_RW,Mix_LoadWAV:_Mix_LoadWAV,Mix_LoadWAV_RW:_Mix_LoadWAV_RW,Mix_OpenAudio:_Mix_OpenAudio,Mix_Pause:_Mix_Pause,Mix_PauseMusic:_Mix_PauseMusic,Mix_Paused:_Mix_Paused,Mix_PausedMusic:_Mix_PausedMusic,Mix_PlayChannelTimed:_Mix_PlayChannelTimed,Mix_PlayMusic:_Mix_PlayMusic,Mix_Playing:_Mix_Playing,Mix_PlayingMusic:_Mix_PlayingMusic,Mix_QuerySpec:_Mix_QuerySpec,Mix_QuickLoad_RAW:_Mix_QuickLoad_RAW,Mix_Quit:_Mix_Quit,Mix_ReserveChannels:_Mix_ReserveChannels,Mix_Resume:_Mix_Resume,Mix_ResumeMusic:_Mix_ResumeMusic,Mix_SetPanning:_Mix_SetPanning,Mix_SetPosition:_Mix_SetPosition,Mix_SetPostMix:_Mix_SetPostMix,Mix_Volume:_Mix_Volume,Mix_VolumeChunk:_Mix_VolumeChunk,Mix_VolumeMusic:_Mix_VolumeMusic,SDL_AddTimer:_SDL_AddTimer,SDL_AllocRW:_SDL_AllocRW,SDL_AudioDriverName:_SDL_AudioDriverName,SDL_AudioQuit:_SDL_AudioQuit,SDL_ClearError:_SDL_ClearError,SDL_CloseAudio:_SDL_CloseAudio,SDL_CondBroadcast:_SDL_CondBroadcast,SDL_CondSignal:_SDL_CondSignal,SDL_CondWait:_SDL_CondWait,SDL_CondWaitTimeout:_SDL_CondWaitTimeout,SDL_ConvertSurface:_SDL_ConvertSurface,SDL_CreateCond:_SDL_CreateCond,SDL_CreateMutex:_SDL_CreateMutex,SDL_CreateRGBSurface:_SDL_CreateRGBSurface,SDL_CreateRGBSurfaceFrom:_SDL_CreateRGBSurfaceFrom,SDL_CreateThread:_SDL_CreateThread,SDL_Delay:_SDL_Delay,SDL_DestroyCond:_SDL_DestroyCond,SDL_DestroyMutex:_SDL_DestroyMutex,SDL_DestroyRenderer:_SDL_DestroyRenderer,SDL_DestroyWindow:_SDL_DestroyWindow,SDL_DisplayFormatAlpha:_SDL_DisplayFormatAlpha,SDL_EnableKeyRepeat:_SDL_EnableKeyRepeat,SDL_EnableUNICODE:_SDL_EnableUNICODE,SDL_FillRect:_SDL_FillRect,SDL_Flip:_SDL_Flip,SDL_FreeRW:_SDL_FreeRW,SDL_FreeSurface:_SDL_FreeSurface,SDL_GL_DeleteContext:_SDL_GL_DeleteContext,SDL_GL_ExtensionSupported:_SDL_GL_ExtensionSupported,SDL_GL_GetAttribute:_SDL_GL_GetAttribute,SDL_GL_GetSwapInterval:_SDL_GL_GetSwapInterval,SDL_GL_MakeCurrent:_SDL_GL_MakeCurrent,SDL_GL_SetAttribute:_SDL_GL_SetAttribute,SDL_GL_SetSwapInterval:_SDL_GL_SetSwapInterval,SDL_GL_SwapBuffers:_SDL_GL_SwapBuffers,SDL_GL_SwapWindow:_SDL_GL_SwapWindow,SDL_GetAppState:_SDL_GetAppState,SDL_GetAudioDriver:_SDL_GetAudioDriver,SDL_GetClipRect:_SDL_GetClipRect,SDL_GetCurrentAudioDriver:_SDL_GetCurrentAudioDriver,SDL_GetError:_SDL_GetError,SDL_GetKeyName:_SDL_GetKeyName,SDL_GetKeyState:_SDL_GetKeyState,SDL_GetKeyboardState:_SDL_GetKeyboardState,SDL_GetModState:_SDL_GetModState,SDL_GetMouseState:_SDL_GetMouseState,SDL_GetNumAudioDrivers:_SDL_GetNumAudioDrivers,SDL_GetRGB:_SDL_GetRGB,SDL_GetRGBA:_SDL_GetRGBA,SDL_GetScancodeFromKey:_SDL_GetScancodeFromKey,SDL_GetThreadID:_SDL_GetThreadID,SDL_GetTicks:_SDL_GetTicks,SDL_GetVideoInfo:_SDL_GetVideoInfo,SDL_GetVideoSurface:_SDL_GetVideoSurface,SDL_GetWindowFlags:_SDL_GetWindowFlags,SDL_GetWindowSize:_SDL_GetWindowSize,SDL_Has3DNow:_SDL_Has3DNow,SDL_Has3DNowExt:_SDL_Has3DNowExt,SDL_HasAltiVec:_SDL_HasAltiVec,SDL_HasMMX:_SDL_HasMMX,SDL_HasMMXExt:_SDL_HasMMXExt,SDL_HasRDTSC:_SDL_HasRDTSC,SDL_HasSSE:_SDL_HasSSE,SDL_HasSSE2:_SDL_HasSSE2,SDL_Init:_SDL_Init,SDL_InitSubSystem:_SDL_InitSubSystem,SDL_JoystickClose:_SDL_JoystickClose,SDL_JoystickEventState:_SDL_JoystickEventState,SDL_JoystickGetAxis:_SDL_JoystickGetAxis,SDL_JoystickGetBall:_SDL_JoystickGetBall,SDL_JoystickGetButton:_SDL_JoystickGetButton,SDL_JoystickGetHat:_SDL_JoystickGetHat,SDL_JoystickIndex:_SDL_JoystickIndex,SDL_JoystickName:_SDL_JoystickName,SDL_JoystickNumAxes:_SDL_JoystickNumAxes,SDL_JoystickNumBalls:_SDL_JoystickNumBalls,SDL_JoystickNumButtons:_SDL_JoystickNumButtons,SDL_JoystickNumHats:_SDL_JoystickNumHats,SDL_JoystickOpen:_SDL_JoystickOpen,SDL_JoystickOpened:_SDL_JoystickOpened,SDL_JoystickUpdate:_SDL_JoystickUpdate,SDL_Linked_Version:_SDL_Linked_Version,SDL_ListModes:_SDL_ListModes,SDL_LoadBMP_RW:_SDL_LoadBMP_RW,SDL_LockAudio:_SDL_LockAudio,SDL_LockSurface:_SDL_LockSurface,SDL_LogSetOutputFunction:_SDL_LogSetOutputFunction,SDL_LowerBlit:_SDL_LowerBlit,SDL_LowerBlitScaled:_SDL_LowerBlitScaled,SDL_MapRGB:_SDL_MapRGB,SDL_MapRGBA:_SDL_MapRGBA,SDL_NumJoysticks:_SDL_NumJoysticks,SDL_OpenAudio:_SDL_OpenAudio,SDL_PauseAudio:_SDL_PauseAudio,SDL_PeepEvents:_SDL_PeepEvents,SDL_PollEvent:_SDL_PollEvent,SDL_PumpEvents:_SDL_PumpEvents,SDL_PushEvent:_SDL_PushEvent,SDL_Quit:_SDL_Quit,SDL_QuitSubSystem:_SDL_QuitSubSystem,SDL_RWFromConstMem:_SDL_RWFromConstMem,SDL_RWFromFile:_SDL_RWFromFile,SDL_RWFromMem:_SDL_RWFromMem,SDL_RemoveTimer:_SDL_RemoveTimer,SDL_SaveBMP_RW:_SDL_SaveBMP_RW,SDL_SetAlpha:_SDL_SetAlpha,SDL_SetClipRect:_SDL_SetClipRect,SDL_SetColorKey:_SDL_SetColorKey,SDL_SetColors:_SDL_SetColors,SDL_SetError:_SDL_SetError,SDL_SetGamma:_SDL_SetGamma,SDL_SetGammaRamp:_SDL_SetGammaRamp,SDL_SetPalette:_SDL_SetPalette,SDL_SetVideoMode:_SDL_SetVideoMode,SDL_SetWindowFullscreen:_SDL_SetWindowFullscreen,SDL_SetWindowTitle:_SDL_SetWindowTitle,SDL_ShowCursor:_SDL_ShowCursor,SDL_StartTextInput:_SDL_StartTextInput,SDL_StopTextInput:_SDL_StopTextInput,SDL_ThreadID:_SDL_ThreadID,SDL_UnlockAudio:_SDL_UnlockAudio,SDL_UnlockSurface:_SDL_UnlockSurface,SDL_UpdateRect:_SDL_UpdateRect,SDL_UpdateRects:_SDL_UpdateRects,SDL_UpperBlit:_SDL_UpperBlit,SDL_UpperBlitScaled:_SDL_UpperBlitScaled,SDL_VideoDriverName:_SDL_VideoDriverName,SDL_VideoModeOK:_SDL_VideoModeOK,SDL_VideoQuit:_SDL_VideoQuit,SDL_WM_GrabInput:_SDL_WM_GrabInput,SDL_WM_IconifyWindow:_SDL_WM_IconifyWindow,SDL_WM_SetCaption:_SDL_WM_SetCaption,SDL_WM_SetIcon:_SDL_WM_SetIcon,SDL_WM_ToggleFullScreen:_SDL_WM_ToggleFullScreen,SDL_WaitThread:_SDL_WaitThread,SDL_WarpMouse:_SDL_WarpMouse,SDL_WasInit:_SDL_WasInit,SDL_mutexP:_SDL_mutexP,SDL_mutexV:_SDL_mutexV,TTF_CloseFont:_TTF_CloseFont,TTF_FontAscent:_TTF_FontAscent,TTF_FontDescent:_TTF_FontDescent,TTF_FontHeight:_TTF_FontHeight,TTF_FontLineSkip:_TTF_FontLineSkip,TTF_GlyphMetrics:_TTF_GlyphMetrics,TTF_Init:_TTF_Init,TTF_OpenFont:_TTF_OpenFont,TTF_Quit:_TTF_Quit,TTF_RenderText_Blended:_TTF_RenderText_Blended,TTF_RenderText_Shaded:_TTF_RenderText_Shaded,TTF_RenderText_Solid:_TTF_RenderText_Solid,TTF_RenderUTF8_Solid:_TTF_RenderUTF8_Solid,TTF_SizeText:_TTF_SizeText,TTF_SizeUTF8:_TTF_SizeUTF8,_JsArray_PostProcess_helper:_JsArray_PostProcess_helper,_JsArray_PushEntry_helper:_JsArray_PushEntry_helper,_PyEM_GetCountArgsPtr:_PyEM_GetCountArgsPtr,_PyEM_TrampolineCall_JS:_PyEM_TrampolineCall_JS,_PyImport_InitFunc_TrampolineCall:_PyImport_InitFunc_TrampolineCall,_Py_CheckEmscriptenSignals_Helper:_Py_CheckEmscriptenSignals_Helper,_Py_emscripten_runtime:_Py_emscripten_runtime,_Unwind_Backtrace:__Unwind_Backtrace,_Unwind_DeleteException:__Unwind_DeleteException,_Unwind_FindEnclosingFunction:__Unwind_FindEnclosingFunction,_Unwind_GetIPInfo:__Unwind_GetIPInfo,_Unwind_RaiseException:__Unwind_RaiseException,__asctime_r:___asctime_r,__assert_fail:___assert_fail,__call_sighandler:___call_sighandler,__cxa_begin_catch:___cxa_begin_catch,__cxa_call_unexpected:___cxa_call_unexpected,__cxa_current_primary_exception:___cxa_current_primary_exception,__cxa_end_catch:___cxa_end_catch,__cxa_find_matching_catch_2:___cxa_find_matching_catch_2,__cxa_find_matching_catch_3:___cxa_find_matching_catch_3,__cxa_find_matching_catch_4:___cxa_find_matching_catch_4,__cxa_get_exception_ptr:___cxa_get_exception_ptr,__cxa_rethrow:___cxa_rethrow,__cxa_rethrow_primary_exception:___cxa_rethrow_primary_exception,__cxa_throw:___cxa_throw,__cxa_uncaught_exceptions:___cxa_uncaught_exceptions,__global_base:___global_base,__heap_base:___heap_base,__hiwire_deduplicate_delete:__hiwire_deduplicate_delete,__hiwire_deduplicate_get:__hiwire_deduplicate_get,__hiwire_deduplicate_new:__hiwire_deduplicate_new,__hiwire_deduplicate_set:__hiwire_deduplicate_set,__indirect_function_table:wasmTable,__memory_base:___memory_base,__resumeException:___resumeException,__stack_high:___stack_high,__stack_low:___stack_low,__stack_pointer:___stack_pointer,__syscall__newselect:___syscall__newselect,__syscall_accept4:___syscall_accept4,__syscall_bind:___syscall_bind,__syscall_chdir:___syscall_chdir,__syscall_chmod:___syscall_chmod,__syscall_connect:___syscall_connect,__syscall_dup:___syscall_dup,__syscall_dup3:___syscall_dup3,__syscall_faccessat:___syscall_faccessat,__syscall_fadvise64:___syscall_fadvise64,__syscall_fallocate:___syscall_fallocate,__syscall_fchdir:___syscall_fchdir,__syscall_fchmod:___syscall_fchmod,__syscall_fchmodat2:___syscall_fchmodat2,__syscall_fchown32:___syscall_fchown32,__syscall_fchownat:___syscall_fchownat,__syscall_fcntl64:___syscall_fcntl64,__syscall_fdatasync:___syscall_fdatasync,__syscall_fstat64:___syscall_fstat64,__syscall_fstatfs64:___syscall_fstatfs64,__syscall_ftruncate64:___syscall_ftruncate64,__syscall_getcwd:___syscall_getcwd,__syscall_getdents64:___syscall_getdents64,__syscall_getpeername:___syscall_getpeername,__syscall_getsockname:___syscall_getsockname,__syscall_getsockopt:___syscall_getsockopt,__syscall_ioctl:___syscall_ioctl,__syscall_listen:___syscall_listen,__syscall_lstat64:___syscall_lstat64,__syscall_mkdirat:___syscall_mkdirat,__syscall_mknodat:___syscall_mknodat,__syscall_newfstatat:___syscall_newfstatat,__syscall_openat:___syscall_openat,__syscall_pipe:___syscall_pipe,__syscall_poll:___syscall_poll,__syscall_readlinkat:___syscall_readlinkat,__syscall_recvfrom:___syscall_recvfrom,__syscall_recvmsg:___syscall_recvmsg,__syscall_renameat:___syscall_renameat,__syscall_rmdir:___syscall_rmdir,__syscall_sendmsg:___syscall_sendmsg,__syscall_sendto:___syscall_sendto,__syscall_socket:___syscall_socket,__syscall_stat64:___syscall_stat64,__syscall_statfs64:___syscall_statfs64,__syscall_symlink:___syscall_symlink,__syscall_symlinkat:___syscall_symlinkat,__syscall_truncate64:___syscall_truncate64,__syscall_unlinkat:___syscall_unlinkat,__syscall_utimensat:___syscall_utimensat,__table_base:___table_base,_agen_handle_result_js:_agen_handle_result_js,_dlopen_js:__dlopen_js,_dlsym_catchup_js:__dlsym_catchup_js,_dlsym_js:__dlsym_js,_emscripten_dlopen_js:__emscripten_dlopen_js,_emscripten_fs_load_embedded_files:__emscripten_fs_load_embedded_files,_emscripten_get_now_is_monotonic:__emscripten_get_now_is_monotonic,_emscripten_get_progname:__emscripten_get_progname,_emscripten_lookup_name:__emscripten_lookup_name,_emscripten_push_main_loop_blocker:__emscripten_push_main_loop_blocker,_emscripten_push_uncounted_main_loop_blocker:__emscripten_push_uncounted_main_loop_blocker,_emscripten_runtime_keepalive_clear:__emscripten_runtime_keepalive_clear,_emscripten_set_offscreencanvas_size:__emscripten_set_offscreencanvas_size,_emscripten_system:__emscripten_system,_emscripten_throw_longjmp:__emscripten_throw_longjmp,_glGetActiveAttribOrUniform:__glGetActiveAttribOrUniform,_gmtime_js:__gmtime_js,_localtime_js:__localtime_js,_mktime_js:__mktime_js,_mmap_js:__mmap_js,_msync_js:__msync_js,_munmap_js:__munmap_js,_pyproxyGen_make_result:_pyproxyGen_make_result,_pyproxy_get_buffer_result:_pyproxy_get_buffer_result,_python2js_add_to_cache:_python2js_add_to_cache,_python2js_addto_postprocess_list:_python2js_addto_postprocess_list,_python2js_buffer_inner:_python2js_buffer_inner,_python2js_cache_lookup:_python2js_cache_lookup,_python2js_handle_postprocess_list:_python2js_handle_postprocess_list,_python2js_ucs1:_python2js_ucs1,_python2js_ucs2:_python2js_ucs2,_python2js_ucs4:_python2js_ucs4,_setitimer_js:__setitimer_js,_timegm_js:__timegm_js,_tzset_js:__tzset_js,abort:_abort,array_to_js:array_to_js,boxColor:_boxColor,boxRGBA:_boxRGBA,can_run_sync_js:can_run_sync_js,capture_stderr:capture_stderr,clock_res_get:_clock_res_get,clock_time_get:_clock_time_get,create_once_callable:create_once_callable,create_promise_handles:create_promise_handles,destroy_jsarray_entries:destroy_jsarray_entries,destroy_proxies:destroy_proxies,destroy_proxies_js:destroy_proxies_js,destroy_proxy:destroy_proxy,eglBindAPI:_eglBindAPI,eglChooseConfig:_eglChooseConfig,eglCreateContext:_eglCreateContext,eglCreateWindowSurface:_eglCreateWindowSurface,eglDestroyContext:_eglDestroyContext,eglDestroySurface:_eglDestroySurface,eglGetConfigAttrib:_eglGetConfigAttrib,eglGetConfigs:_eglGetConfigs,eglGetCurrentContext:_eglGetCurrentContext,eglGetCurrentDisplay:_eglGetCurrentDisplay,eglGetCurrentSurface:_eglGetCurrentSurface,eglGetDisplay:_eglGetDisplay,eglGetError:_eglGetError,eglInitialize:_eglInitialize,eglMakeCurrent:_eglMakeCurrent,eglQueryAPI:_eglQueryAPI,eglQueryContext:_eglQueryContext,eglQueryString:_eglQueryString,eglQuerySurface:_eglQuerySurface,eglReleaseThread:_eglReleaseThread,eglSwapBuffers:_eglSwapBuffers,eglSwapInterval:_eglSwapInterval,eglTerminate:_eglTerminate,eglWaitClient:_eglWaitClient,eglWaitGL:_eglWaitGL,eglWaitNative:_eglWaitNative,ellipseColor:_ellipseColor,ellipseRGBA:_ellipseRGBA,emscripten_SDL_SetEventHandler:_emscripten_SDL_SetEventHandler,emscripten_asm_const_async_on_main_thread:_emscripten_asm_const_async_on_main_thread,emscripten_asm_const_double:_emscripten_asm_const_double,emscripten_asm_const_double_sync_on_main_thread:_emscripten_asm_const_double_sync_on_main_thread,emscripten_asm_const_int:_emscripten_asm_const_int,emscripten_asm_const_int_sync_on_main_thread:_emscripten_asm_const_int_sync_on_main_thread,emscripten_asm_const_ptr:_emscripten_asm_const_ptr,emscripten_asm_const_ptr_sync_on_main_thread:_emscripten_asm_const_ptr_sync_on_main_thread,emscripten_async_call:_emscripten_async_call,emscripten_async_load_script:_emscripten_async_load_script,emscripten_async_run_script:_emscripten_async_run_script,emscripten_async_wget:_emscripten_async_wget,emscripten_async_wget2:_emscripten_async_wget2,emscripten_async_wget2_abort:_emscripten_async_wget2_abort,emscripten_async_wget2_data:_emscripten_async_wget2_data,emscripten_async_wget_data:_emscripten_async_wget_data,emscripten_call_worker:_emscripten_call_worker,emscripten_cancel_animation_frame:_emscripten_cancel_animation_frame,emscripten_cancel_main_loop:_emscripten_cancel_main_loop,emscripten_clear_immediate:_emscripten_clear_immediate,emscripten_clear_interval:_emscripten_clear_interval,emscripten_clear_timeout:_emscripten_clear_timeout,emscripten_console_error:_emscripten_console_error,emscripten_console_log:_emscripten_console_log,emscripten_console_warn:_emscripten_console_warn,emscripten_create_worker:_emscripten_create_worker,emscripten_date_now:_emscripten_date_now,emscripten_debugger:_emscripten_debugger,emscripten_destroy_worker:_emscripten_destroy_worker,emscripten_enter_soft_fullscreen:_emscripten_enter_soft_fullscreen,emscripten_err:_emscripten_err,emscripten_errn:_emscripten_errn,emscripten_exit_fullscreen:_emscripten_exit_fullscreen,emscripten_exit_pointerlock:_emscripten_exit_pointerlock,emscripten_exit_soft_fullscreen:_emscripten_exit_soft_fullscreen,emscripten_exit_with_live_runtime:_emscripten_exit_with_live_runtime,emscripten_force_exit:_emscripten_force_exit,emscripten_get_battery_status:_emscripten_get_battery_status,emscripten_get_callstack:_emscripten_get_callstack,emscripten_get_canvas_element_size:_emscripten_get_canvas_element_size,emscripten_get_canvas_size:_emscripten_get_canvas_size,emscripten_get_compiler_setting:_emscripten_get_compiler_setting,emscripten_get_device_pixel_ratio:_emscripten_get_device_pixel_ratio,emscripten_get_devicemotion_status:_emscripten_get_devicemotion_status,emscripten_get_deviceorientation_status:_emscripten_get_deviceorientation_status,emscripten_get_element_css_size:_emscripten_get_element_css_size,emscripten_get_fullscreen_status:_emscripten_get_fullscreen_status,emscripten_get_gamepad_status:_emscripten_get_gamepad_status,emscripten_get_heap_max:_emscripten_get_heap_max,emscripten_get_main_loop_timing:_emscripten_get_main_loop_timing,emscripten_get_module_name:_emscripten_get_module_name,emscripten_get_mouse_status:_emscripten_get_mouse_status,emscripten_get_now:_emscripten_get_now,emscripten_get_now_res:_emscripten_get_now_res,emscripten_get_num_gamepads:_emscripten_get_num_gamepads,emscripten_get_orientation_status:_emscripten_get_orientation_status,emscripten_get_pointerlock_status:_emscripten_get_pointerlock_status,emscripten_get_preloaded_image_data:_emscripten_get_preloaded_image_data,emscripten_get_preloaded_image_data_from_FILE:_emscripten_get_preloaded_image_data_from_FILE,emscripten_get_screen_size:_emscripten_get_screen_size,emscripten_get_visibility_status:_emscripten_get_visibility_status,emscripten_get_window_title:_emscripten_get_window_title,emscripten_get_worker_queue_size:_emscripten_get_worker_queue_size,emscripten_glActiveTexture:_emscripten_glActiveTexture,emscripten_glAttachShader:_emscripten_glAttachShader,emscripten_glBegin:_emscripten_glBegin,emscripten_glBeginQueryEXT:_emscripten_glBeginQueryEXT,emscripten_glBindAttribLocation:_emscripten_glBindAttribLocation,emscripten_glBindBuffer:_emscripten_glBindBuffer,emscripten_glBindFramebuffer:_emscripten_glBindFramebuffer,emscripten_glBindRenderbuffer:_emscripten_glBindRenderbuffer,emscripten_glBindTexture:_emscripten_glBindTexture,emscripten_glBindVertexArray:_emscripten_glBindVertexArray,emscripten_glBindVertexArrayOES:_emscripten_glBindVertexArrayOES,emscripten_glBlendColor:_emscripten_glBlendColor,emscripten_glBlendEquation:_emscripten_glBlendEquation,emscripten_glBlendEquationSeparate:_emscripten_glBlendEquationSeparate,emscripten_glBlendFunc:_emscripten_glBlendFunc,emscripten_glBlendFuncSeparate:_emscripten_glBlendFuncSeparate,emscripten_glBufferData:_emscripten_glBufferData,emscripten_glBufferSubData:_emscripten_glBufferSubData,emscripten_glCheckFramebufferStatus:_emscripten_glCheckFramebufferStatus,emscripten_glClear:_emscripten_glClear,emscripten_glClearColor:_emscripten_glClearColor,emscripten_glClearDepth:_emscripten_glClearDepth,emscripten_glClearDepthf:_emscripten_glClearDepthf,emscripten_glClearStencil:_emscripten_glClearStencil,emscripten_glColorMask:_emscripten_glColorMask,emscripten_glCompileShader:_emscripten_glCompileShader,emscripten_glCompressedTexImage2D:_emscripten_glCompressedTexImage2D,emscripten_glCompressedTexSubImage2D:_emscripten_glCompressedTexSubImage2D,emscripten_glCopyTexImage2D:_emscripten_glCopyTexImage2D,emscripten_glCopyTexSubImage2D:_emscripten_glCopyTexSubImage2D,emscripten_glCreateProgram:_emscripten_glCreateProgram,emscripten_glCreateShader:_emscripten_glCreateShader,emscripten_glCullFace:_emscripten_glCullFace,emscripten_glDeleteBuffers:_emscripten_glDeleteBuffers,emscripten_glDeleteFramebuffers:_emscripten_glDeleteFramebuffers,emscripten_glDeleteProgram:_emscripten_glDeleteProgram,emscripten_glDeleteQueriesEXT:_emscripten_glDeleteQueriesEXT,emscripten_glDeleteRenderbuffers:_emscripten_glDeleteRenderbuffers,emscripten_glDeleteShader:_emscripten_glDeleteShader,emscripten_glDeleteTextures:_emscripten_glDeleteTextures,emscripten_glDeleteVertexArrays:_emscripten_glDeleteVertexArrays,emscripten_glDeleteVertexArraysOES:_emscripten_glDeleteVertexArraysOES,emscripten_glDepthFunc:_emscripten_glDepthFunc,emscripten_glDepthMask:_emscripten_glDepthMask,emscripten_glDepthRange:_emscripten_glDepthRange,emscripten_glDepthRangef:_emscripten_glDepthRangef,emscripten_glDetachShader:_emscripten_glDetachShader,emscripten_glDisable:_emscripten_glDisable,emscripten_glDisableVertexAttribArray:_emscripten_glDisableVertexAttribArray,emscripten_glDrawArrays:_emscripten_glDrawArrays,emscripten_glDrawArraysInstanced:_emscripten_glDrawArraysInstanced,emscripten_glDrawArraysInstancedANGLE:_emscripten_glDrawArraysInstancedANGLE,emscripten_glDrawArraysInstancedARB:_emscripten_glDrawArraysInstancedARB,emscripten_glDrawArraysInstancedEXT:_emscripten_glDrawArraysInstancedEXT,emscripten_glDrawArraysInstancedNV:_emscripten_glDrawArraysInstancedNV,emscripten_glDrawBuffers:_emscripten_glDrawBuffers,emscripten_glDrawBuffersEXT:_emscripten_glDrawBuffersEXT,emscripten_glDrawBuffersWEBGL:_emscripten_glDrawBuffersWEBGL,emscripten_glDrawElements:_emscripten_glDrawElements,emscripten_glDrawElementsInstanced:_emscripten_glDrawElementsInstanced,emscripten_glDrawElementsInstancedANGLE:_emscripten_glDrawElementsInstancedANGLE,emscripten_glDrawElementsInstancedARB:_emscripten_glDrawElementsInstancedARB,emscripten_glDrawElementsInstancedEXT:_emscripten_glDrawElementsInstancedEXT,emscripten_glDrawElementsInstancedNV:_emscripten_glDrawElementsInstancedNV,emscripten_glEnable:_emscripten_glEnable,emscripten_glEnableVertexAttribArray:_emscripten_glEnableVertexAttribArray,emscripten_glEndQueryEXT:_emscripten_glEndQueryEXT,emscripten_glFinish:_emscripten_glFinish,emscripten_glFlush:_emscripten_glFlush,emscripten_glFramebufferRenderbuffer:_emscripten_glFramebufferRenderbuffer,emscripten_glFramebufferTexture2D:_emscripten_glFramebufferTexture2D,emscripten_glFrontFace:_emscripten_glFrontFace,emscripten_glGenBuffers:_emscripten_glGenBuffers,emscripten_glGenFramebuffers:_emscripten_glGenFramebuffers,emscripten_glGenQueriesEXT:_emscripten_glGenQueriesEXT,emscripten_glGenRenderbuffers:_emscripten_glGenRenderbuffers,emscripten_glGenTextures:_emscripten_glGenTextures,emscripten_glGenVertexArrays:_emscripten_glGenVertexArrays,emscripten_glGenVertexArraysOES:_emscripten_glGenVertexArraysOES,emscripten_glGenerateMipmap:_emscripten_glGenerateMipmap,emscripten_glGetActiveAttrib:_emscripten_glGetActiveAttrib,emscripten_glGetActiveUniform:_emscripten_glGetActiveUniform,emscripten_glGetAttachedShaders:_emscripten_glGetAttachedShaders,emscripten_glGetAttribLocation:_emscripten_glGetAttribLocation,emscripten_glGetBooleanv:_emscripten_glGetBooleanv,emscripten_glGetBufferParameteriv:_emscripten_glGetBufferParameteriv,emscripten_glGetError:_emscripten_glGetError,emscripten_glGetFloatv:_emscripten_glGetFloatv,emscripten_glGetFramebufferAttachmentParameteriv:_emscripten_glGetFramebufferAttachmentParameteriv,emscripten_glGetIntegerv:_emscripten_glGetIntegerv,emscripten_glGetProgramInfoLog:_emscripten_glGetProgramInfoLog,emscripten_glGetProgramiv:_emscripten_glGetProgramiv,emscripten_glGetQueryObjecti64vEXT:_emscripten_glGetQueryObjecti64vEXT,emscripten_glGetQueryObjectivEXT:_emscripten_glGetQueryObjectivEXT,emscripten_glGetQueryObjectui64vEXT:_emscripten_glGetQueryObjectui64vEXT,emscripten_glGetQueryObjectuivEXT:_emscripten_glGetQueryObjectuivEXT,emscripten_glGetQueryivEXT:_emscripten_glGetQueryivEXT,emscripten_glGetRenderbufferParameteriv:_emscripten_glGetRenderbufferParameteriv,emscripten_glGetShaderInfoLog:_emscripten_glGetShaderInfoLog,emscripten_glGetShaderPrecisionFormat:_emscripten_glGetShaderPrecisionFormat,emscripten_glGetShaderSource:_emscripten_glGetShaderSource,emscripten_glGetShaderiv:_emscripten_glGetShaderiv,emscripten_glGetString:_emscripten_glGetString,emscripten_glGetTexParameterfv:_emscripten_glGetTexParameterfv,emscripten_glGetTexParameteriv:_emscripten_glGetTexParameteriv,emscripten_glGetUniformLocation:_emscripten_glGetUniformLocation,emscripten_glGetUniformfv:_emscripten_glGetUniformfv,emscripten_glGetUniformiv:_emscripten_glGetUniformiv,emscripten_glGetVertexAttribPointerv:_emscripten_glGetVertexAttribPointerv,emscripten_glGetVertexAttribfv:_emscripten_glGetVertexAttribfv,emscripten_glGetVertexAttribiv:_emscripten_glGetVertexAttribiv,emscripten_glHint:_emscripten_glHint,emscripten_glIsBuffer:_emscripten_glIsBuffer,emscripten_glIsEnabled:_emscripten_glIsEnabled,emscripten_glIsFramebuffer:_emscripten_glIsFramebuffer,emscripten_glIsProgram:_emscripten_glIsProgram,emscripten_glIsQueryEXT:_emscripten_glIsQueryEXT,emscripten_glIsRenderbuffer:_emscripten_glIsRenderbuffer,emscripten_glIsShader:_emscripten_glIsShader,emscripten_glIsTexture:_emscripten_glIsTexture,emscripten_glIsVertexArray:_emscripten_glIsVertexArray,emscripten_glIsVertexArrayOES:_emscripten_glIsVertexArrayOES,emscripten_glLineWidth:_emscripten_glLineWidth,emscripten_glLinkProgram:_emscripten_glLinkProgram,emscripten_glLoadIdentity:_emscripten_glLoadIdentity,emscripten_glMatrixMode:_emscripten_glMatrixMode,emscripten_glMultiDrawArrays:_emscripten_glMultiDrawArrays,emscripten_glMultiDrawArraysANGLE:_emscripten_glMultiDrawArraysANGLE,emscripten_glMultiDrawArraysInstancedANGLE:_emscripten_glMultiDrawArraysInstancedANGLE,emscripten_glMultiDrawArraysInstancedWEBGL:_emscripten_glMultiDrawArraysInstancedWEBGL,emscripten_glMultiDrawArraysWEBGL:_emscripten_glMultiDrawArraysWEBGL,emscripten_glMultiDrawElements:_emscripten_glMultiDrawElements,emscripten_glMultiDrawElementsANGLE:_emscripten_glMultiDrawElementsANGLE,emscripten_glMultiDrawElementsInstancedANGLE:_emscripten_glMultiDrawElementsInstancedANGLE,emscripten_glMultiDrawElementsInstancedWEBGL:_emscripten_glMultiDrawElementsInstancedWEBGL,emscripten_glMultiDrawElementsWEBGL:_emscripten_glMultiDrawElementsWEBGL,emscripten_glPixelStorei:_emscripten_glPixelStorei,emscripten_glPolygonOffset:_emscripten_glPolygonOffset,emscripten_glQueryCounterEXT:_emscripten_glQueryCounterEXT,emscripten_glReadPixels:_emscripten_glReadPixels,emscripten_glReleaseShaderCompiler:_emscripten_glReleaseShaderCompiler,emscripten_glRenderbufferStorage:_emscripten_glRenderbufferStorage,emscripten_glSampleCoverage:_emscripten_glSampleCoverage,emscripten_glScissor:_emscripten_glScissor,emscripten_glShaderBinary:_emscripten_glShaderBinary,emscripten_glShaderSource:_emscripten_glShaderSource,emscripten_glStencilFunc:_emscripten_glStencilFunc,emscripten_glStencilFuncSeparate:_emscripten_glStencilFuncSeparate,emscripten_glStencilMask:_emscripten_glStencilMask,emscripten_glStencilMaskSeparate:_emscripten_glStencilMaskSeparate,emscripten_glStencilOp:_emscripten_glStencilOp,emscripten_glStencilOpSeparate:_emscripten_glStencilOpSeparate,emscripten_glTexImage2D:_emscripten_glTexImage2D,emscripten_glTexParameterf:_emscripten_glTexParameterf,emscripten_glTexParameterfv:_emscripten_glTexParameterfv,emscripten_glTexParameteri:_emscripten_glTexParameteri,emscripten_glTexParameteriv:_emscripten_glTexParameteriv,emscripten_glTexSubImage2D:_emscripten_glTexSubImage2D,emscripten_glUniform1f:_emscripten_glUniform1f,emscripten_glUniform1fv:_emscripten_glUniform1fv,emscripten_glUniform1i:_emscripten_glUniform1i,emscripten_glUniform1iv:_emscripten_glUniform1iv,emscripten_glUniform2f:_emscripten_glUniform2f,emscripten_glUniform2fv:_emscripten_glUniform2fv,emscripten_glUniform2i:_emscripten_glUniform2i,emscripten_glUniform2iv:_emscripten_glUniform2iv,emscripten_glUniform3f:_emscripten_glUniform3f,emscripten_glUniform3fv:_emscripten_glUniform3fv,emscripten_glUniform3i:_emscripten_glUniform3i,emscripten_glUniform3iv:_emscripten_glUniform3iv,emscripten_glUniform4f:_emscripten_glUniform4f,emscripten_glUniform4fv:_emscripten_glUniform4fv,emscripten_glUniform4i:_emscripten_glUniform4i,emscripten_glUniform4iv:_emscripten_glUniform4iv,emscripten_glUniformMatrix2fv:_emscripten_glUniformMatrix2fv,emscripten_glUniformMatrix3fv:_emscripten_glUniformMatrix3fv,emscripten_glUniformMatrix4fv:_emscripten_glUniformMatrix4fv,emscripten_glUseProgram:_emscripten_glUseProgram,emscripten_glValidateProgram:_emscripten_glValidateProgram,emscripten_glVertexAttrib1f:_emscripten_glVertexAttrib1f,emscripten_glVertexAttrib1fv:_emscripten_glVertexAttrib1fv,emscripten_glVertexAttrib2f:_emscripten_glVertexAttrib2f,emscripten_glVertexAttrib2fv:_emscripten_glVertexAttrib2fv,emscripten_glVertexAttrib3f:_emscripten_glVertexAttrib3f,emscripten_glVertexAttrib3fv:_emscripten_glVertexAttrib3fv,emscripten_glVertexAttrib4f:_emscripten_glVertexAttrib4f,emscripten_glVertexAttrib4fv:_emscripten_glVertexAttrib4fv,emscripten_glVertexAttribDivisor:_emscripten_glVertexAttribDivisor,emscripten_glVertexAttribDivisorANGLE:_emscripten_glVertexAttribDivisorANGLE,emscripten_glVertexAttribDivisorARB:_emscripten_glVertexAttribDivisorARB,emscripten_glVertexAttribDivisorEXT:_emscripten_glVertexAttribDivisorEXT,emscripten_glVertexAttribDivisorNV:_emscripten_glVertexAttribDivisorNV,emscripten_glVertexAttribPointer:_emscripten_glVertexAttribPointer,emscripten_glVertexPointer:_emscripten_glVertexPointer,emscripten_glViewport:_emscripten_glViewport,emscripten_has_asyncify:_emscripten_has_asyncify,emscripten_hide_mouse:_emscripten_hide_mouse,emscripten_html5_remove_all_event_listeners:_emscripten_html5_remove_all_event_listeners,emscripten_is_main_browser_thread:_emscripten_is_main_browser_thread,emscripten_is_webgl_context_lost:_emscripten_is_webgl_context_lost,emscripten_lock_orientation:_emscripten_lock_orientation,emscripten_log:_emscripten_log,emscripten_math_acos:_emscripten_math_acos,emscripten_math_acosh:_emscripten_math_acosh,emscripten_math_asin:_emscripten_math_asin,emscripten_math_asinh:_emscripten_math_asinh,emscripten_math_atan:_emscripten_math_atan,emscripten_math_atan2:_emscripten_math_atan2,emscripten_math_atanh:_emscripten_math_atanh,emscripten_math_cbrt:_emscripten_math_cbrt,emscripten_math_cos:_emscripten_math_cos,emscripten_math_cosh:_emscripten_math_cosh,emscripten_math_exp:_emscripten_math_exp,emscripten_math_expm1:_emscripten_math_expm1,emscripten_math_fmod:_emscripten_math_fmod,emscripten_math_hypot:_emscripten_math_hypot,emscripten_math_log:_emscripten_math_log,emscripten_math_log10:_emscripten_math_log10,emscripten_math_log1p:_emscripten_math_log1p,emscripten_math_log2:_emscripten_math_log2,emscripten_math_pow:_emscripten_math_pow,emscripten_math_random:_emscripten_math_random,emscripten_math_round:_emscripten_math_round,emscripten_math_sign:_emscripten_math_sign,emscripten_math_sin:_emscripten_math_sin,emscripten_math_sinh:_emscripten_math_sinh,emscripten_math_sqrt:_emscripten_math_sqrt,emscripten_math_tan:_emscripten_math_tan,emscripten_math_tanh:_emscripten_math_tanh,emscripten_notify_memory_growth:_emscripten_notify_memory_growth,emscripten_out:_emscripten_out,emscripten_outn:_emscripten_outn,emscripten_pause_main_loop:_emscripten_pause_main_loop,emscripten_pc_get_column:_emscripten_pc_get_column,emscripten_pc_get_file:_emscripten_pc_get_file,emscripten_pc_get_function:_emscripten_pc_get_function,emscripten_pc_get_line:_emscripten_pc_get_line,emscripten_performance_now:_emscripten_performance_now,emscripten_print_double:_emscripten_print_double,emscripten_promise_all:_emscripten_promise_all,emscripten_promise_all_settled:_emscripten_promise_all_settled,emscripten_promise_any:_emscripten_promise_any,emscripten_promise_await:_emscripten_promise_await,emscripten_promise_create:_emscripten_promise_create,emscripten_promise_destroy:_emscripten_promise_destroy,emscripten_promise_race:_emscripten_promise_race,emscripten_promise_resolve:_emscripten_promise_resolve,emscripten_promise_then:_emscripten_promise_then,emscripten_random:_emscripten_random,emscripten_request_animation_frame:_emscripten_request_animation_frame,emscripten_request_animation_frame_loop:_emscripten_request_animation_frame_loop,emscripten_request_fullscreen:_emscripten_request_fullscreen,emscripten_request_fullscreen_strategy:_emscripten_request_fullscreen_strategy,emscripten_request_pointerlock:_emscripten_request_pointerlock,emscripten_resize_heap:_emscripten_resize_heap,emscripten_resume_main_loop:_emscripten_resume_main_loop,emscripten_return_address:_emscripten_return_address,emscripten_run_preload_plugins:_emscripten_run_preload_plugins,emscripten_run_preload_plugins_data:_emscripten_run_preload_plugins_data,emscripten_run_script:_emscripten_run_script,emscripten_run_script_int:_emscripten_run_script_int,emscripten_run_script_string:_emscripten_run_script_string,emscripten_runtime_keepalive_check:_emscripten_runtime_keepalive_check,emscripten_runtime_keepalive_pop:_emscripten_runtime_keepalive_pop,emscripten_runtime_keepalive_push:_emscripten_runtime_keepalive_push,emscripten_sample_gamepad_data:_emscripten_sample_gamepad_data,emscripten_set_batterychargingchange_callback_on_thread:_emscripten_set_batterychargingchange_callback_on_thread,emscripten_set_batterylevelchange_callback_on_thread:_emscripten_set_batterylevelchange_callback_on_thread,emscripten_set_beforeunload_callback_on_thread:_emscripten_set_beforeunload_callback_on_thread,emscripten_set_blur_callback_on_thread:_emscripten_set_blur_callback_on_thread,emscripten_set_canvas_element_size:_emscripten_set_canvas_element_size,emscripten_set_canvas_size:_emscripten_set_canvas_size,emscripten_set_click_callback_on_thread:_emscripten_set_click_callback_on_thread,emscripten_set_dblclick_callback_on_thread:_emscripten_set_dblclick_callback_on_thread,emscripten_set_devicemotion_callback_on_thread:_emscripten_set_devicemotion_callback_on_thread,emscripten_set_deviceorientation_callback_on_thread:_emscripten_set_deviceorientation_callback_on_thread,emscripten_set_element_css_size:_emscripten_set_element_css_size,emscripten_set_focus_callback_on_thread:_emscripten_set_focus_callback_on_thread,emscripten_set_focusin_callback_on_thread:_emscripten_set_focusin_callback_on_thread,emscripten_set_focusout_callback_on_thread:_emscripten_set_focusout_callback_on_thread,emscripten_set_fullscreenchange_callback_on_thread:_emscripten_set_fullscreenchange_callback_on_thread,emscripten_set_gamepadconnected_callback_on_thread:_emscripten_set_gamepadconnected_callback_on_thread,emscripten_set_gamepaddisconnected_callback_on_thread:_emscripten_set_gamepaddisconnected_callback_on_thread,emscripten_set_immediate:_emscripten_set_immediate,emscripten_set_immediate_loop:_emscripten_set_immediate_loop,emscripten_set_interval:_emscripten_set_interval,emscripten_set_keydown_callback_on_thread:_emscripten_set_keydown_callback_on_thread,emscripten_set_keypress_callback_on_thread:_emscripten_set_keypress_callback_on_thread,emscripten_set_keyup_callback_on_thread:_emscripten_set_keyup_callback_on_thread,emscripten_set_main_loop:_emscripten_set_main_loop,emscripten_set_main_loop_arg:_emscripten_set_main_loop_arg,emscripten_set_main_loop_expected_blockers:_emscripten_set_main_loop_expected_blockers,emscripten_set_main_loop_timing:_emscripten_set_main_loop_timing,emscripten_set_mousedown_callback_on_thread:_emscripten_set_mousedown_callback_on_thread,emscripten_set_mouseenter_callback_on_thread:_emscripten_set_mouseenter_callback_on_thread,emscripten_set_mouseleave_callback_on_thread:_emscripten_set_mouseleave_callback_on_thread,emscripten_set_mousemove_callback_on_thread:_emscripten_set_mousemove_callback_on_thread,emscripten_set_mouseout_callback_on_thread:_emscripten_set_mouseout_callback_on_thread,emscripten_set_mouseover_callback_on_thread:_emscripten_set_mouseover_callback_on_thread,emscripten_set_mouseup_callback_on_thread:_emscripten_set_mouseup_callback_on_thread,emscripten_set_orientationchange_callback_on_thread:_emscripten_set_orientationchange_callback_on_thread,emscripten_set_pointerlockchange_callback_on_thread:_emscripten_set_pointerlockchange_callback_on_thread,emscripten_set_pointerlockerror_callback_on_thread:_emscripten_set_pointerlockerror_callback_on_thread,emscripten_set_resize_callback_on_thread:_emscripten_set_resize_callback_on_thread,emscripten_set_scroll_callback_on_thread:_emscripten_set_scroll_callback_on_thread,emscripten_set_socket_close_callback:_emscripten_set_socket_close_callback,emscripten_set_socket_connection_callback:_emscripten_set_socket_connection_callback,emscripten_set_socket_error_callback:_emscripten_set_socket_error_callback,emscripten_set_socket_listen_callback:_emscripten_set_socket_listen_callback,emscripten_set_socket_message_callback:_emscripten_set_socket_message_callback,emscripten_set_socket_open_callback:_emscripten_set_socket_open_callback,emscripten_set_timeout:_emscripten_set_timeout,emscripten_set_timeout_loop:_emscripten_set_timeout_loop,emscripten_set_touchcancel_callback_on_thread:_emscripten_set_touchcancel_callback_on_thread,emscripten_set_touchend_callback_on_thread:_emscripten_set_touchend_callback_on_thread,emscripten_set_touchmove_callback_on_thread:_emscripten_set_touchmove_callback_on_thread,emscripten_set_touchstart_callback_on_thread:_emscripten_set_touchstart_callback_on_thread,emscripten_set_visibilitychange_callback_on_thread:_emscripten_set_visibilitychange_callback_on_thread,emscripten_set_webglcontextlost_callback_on_thread:_emscripten_set_webglcontextlost_callback_on_thread,emscripten_set_webglcontextrestored_callback_on_thread:_emscripten_set_webglcontextrestored_callback_on_thread,emscripten_set_wheel_callback_on_thread:_emscripten_set_wheel_callback_on_thread,emscripten_set_window_title:_emscripten_set_window_title,emscripten_stack_snapshot:_emscripten_stack_snapshot,emscripten_stack_unwind_buffer:_emscripten_stack_unwind_buffer,emscripten_supports_offscreencanvas:_emscripten_supports_offscreencanvas,emscripten_throw_number:_emscripten_throw_number,emscripten_throw_string:_emscripten_throw_string,emscripten_unlock_orientation:_emscripten_unlock_orientation,emscripten_unwind_to_js_event_loop:_emscripten_unwind_to_js_event_loop,emscripten_vibrate:_emscripten_vibrate,emscripten_vibrate_pattern:_emscripten_vibrate_pattern,emscripten_webgl_commit_frame:_emscripten_webgl_commit_frame,emscripten_webgl_create_context:_emscripten_webgl_create_context,emscripten_webgl_destroy_context:_emscripten_webgl_destroy_context,emscripten_webgl_do_commit_frame:_emscripten_webgl_do_commit_frame,emscripten_webgl_do_create_context:_emscripten_webgl_do_create_context,emscripten_webgl_do_get_current_context:_emscripten_webgl_do_get_current_context,emscripten_webgl_enable_ANGLE_instanced_arrays:_emscripten_webgl_enable_ANGLE_instanced_arrays,emscripten_webgl_enable_OES_vertex_array_object:_emscripten_webgl_enable_OES_vertex_array_object,emscripten_webgl_enable_WEBGL_draw_buffers:_emscripten_webgl_enable_WEBGL_draw_buffers,emscripten_webgl_enable_WEBGL_multi_draw:_emscripten_webgl_enable_WEBGL_multi_draw,emscripten_webgl_enable_extension:_emscripten_webgl_enable_extension,emscripten_webgl_get_context_attributes:_emscripten_webgl_get_context_attributes,emscripten_webgl_get_current_context:_emscripten_webgl_get_current_context,emscripten_webgl_get_drawing_buffer_size:_emscripten_webgl_get_drawing_buffer_size,emscripten_webgl_get_parameter_d:_emscripten_webgl_get_parameter_d,emscripten_webgl_get_parameter_i64v:_emscripten_webgl_get_parameter_i64v,emscripten_webgl_get_parameter_o:_emscripten_webgl_get_parameter_o,emscripten_webgl_get_parameter_utf8:_emscripten_webgl_get_parameter_utf8,emscripten_webgl_get_parameter_v:_emscripten_webgl_get_parameter_v,emscripten_webgl_get_program_info_log_utf8:_emscripten_webgl_get_program_info_log_utf8,emscripten_webgl_get_program_parameter_d:_emscripten_webgl_get_program_parameter_d,emscripten_webgl_get_shader_info_log_utf8:_emscripten_webgl_get_shader_info_log_utf8,emscripten_webgl_get_shader_parameter_d:_emscripten_webgl_get_shader_parameter_d,emscripten_webgl_get_shader_source_utf8:_emscripten_webgl_get_shader_source_utf8,emscripten_webgl_get_supported_extensions:_emscripten_webgl_get_supported_extensions,emscripten_webgl_get_uniform_d:_emscripten_webgl_get_uniform_d,emscripten_webgl_get_uniform_v:_emscripten_webgl_get_uniform_v,emscripten_webgl_get_vertex_attrib_d:_emscripten_webgl_get_vertex_attrib_d,emscripten_webgl_get_vertex_attrib_o:_emscripten_webgl_get_vertex_attrib_o,emscripten_webgl_get_vertex_attrib_v:_emscripten_webgl_get_vertex_attrib_v,emscripten_webgl_make_context_current:_emscripten_webgl_make_context_current,emscripten_websocket_close:_emscripten_websocket_close,emscripten_websocket_deinitialize:_emscripten_websocket_deinitialize,emscripten_websocket_delete:_emscripten_websocket_delete,emscripten_websocket_get_buffered_amount:_emscripten_websocket_get_buffered_amount,emscripten_websocket_get_extensions:_emscripten_websocket_get_extensions,emscripten_websocket_get_extensions_length:_emscripten_websocket_get_extensions_length,emscripten_websocket_get_protocol:_emscripten_websocket_get_protocol,emscripten_websocket_get_protocol_length:_emscripten_websocket_get_protocol_length,emscripten_websocket_get_ready_state:_emscripten_websocket_get_ready_state,emscripten_websocket_get_url:_emscripten_websocket_get_url,emscripten_websocket_get_url_length:_emscripten_websocket_get_url_length,emscripten_websocket_is_supported:_emscripten_websocket_is_supported,emscripten_websocket_new:_emscripten_websocket_new,emscripten_websocket_send_binary:_emscripten_websocket_send_binary,emscripten_websocket_send_utf8_text:_emscripten_websocket_send_utf8_text,emscripten_websocket_set_onclose_callback_on_thread:_emscripten_websocket_set_onclose_callback_on_thread,emscripten_websocket_set_onerror_callback_on_thread:_emscripten_websocket_set_onerror_callback_on_thread,emscripten_websocket_set_onmessage_callback_on_thread:_emscripten_websocket_set_onmessage_callback_on_thread,emscripten_websocket_set_onopen_callback_on_thread:_emscripten_websocket_set_onopen_callback_on_thread,endprotoent:_endprotoent,environ_get:_environ_get,environ_sizes_get:_environ_sizes_get,exit:_exit,fail_test:fail_test,fd_close:_fd_close,fd_fdstat_get:_fd_fdstat_get,fd_pread:_fd_pread,fd_pwrite:_fd_pwrite,fd_read:_fd_read,fd_seek:_fd_seek,fd_sync:_fd_sync,fd_write:_fd_write,ffi_call_js:ffi_call_js,ffi_closure_alloc_js:ffi_closure_alloc_js,ffi_closure_free_js:ffi_closure_free_js,ffi_prep_closure_loc_js:ffi_prep_closure_loc_js,filledEllipseColor:_filledEllipseColor,filledEllipseRGBA:_filledEllipseRGBA,gc_register_proxies:gc_register_proxies,get_async_js_call_done_callback:get_async_js_call_done_callback,get_length_helper:get_length_helper,get_length_string:get_length_string,get_suspender:get_suspender,getaddrinfo:_getaddrinfo,getentropy:_getentropy,getnameinfo:_getnameinfo,getprotobyname:_getprotobyname,getprotobynumber:_getprotobynumber,getprotoent:_getprotoent,glActiveTexture:_glActiveTexture,glAttachShader:_glAttachShader,glBegin:_glBegin,glBeginQueryEXT:_glBeginQueryEXT,glBindAttribLocation:_glBindAttribLocation,glBindBuffer:_glBindBuffer,glBindFramebuffer:_glBindFramebuffer,glBindRenderbuffer:_glBindRenderbuffer,glBindTexture:_glBindTexture,glBindVertexArray:_glBindVertexArray,glBindVertexArrayOES:_glBindVertexArrayOES,glBlendColor:_glBlendColor,glBlendEquation:_glBlendEquation,glBlendEquationSeparate:_glBlendEquationSeparate,glBlendFunc:_glBlendFunc,glBlendFuncSeparate:_glBlendFuncSeparate,glBufferData:_glBufferData,glBufferSubData:_glBufferSubData,glCheckFramebufferStatus:_glCheckFramebufferStatus,glClear:_glClear,glClearColor:_glClearColor,glClearDepth:_glClearDepth,glClearDepthf:_glClearDepthf,glClearStencil:_glClearStencil,glColorMask:_glColorMask,glCompileShader:_glCompileShader,glCompressedTexImage2D:_glCompressedTexImage2D,glCompressedTexSubImage2D:_glCompressedTexSubImage2D,glCopyTexImage2D:_glCopyTexImage2D,glCopyTexSubImage2D:_glCopyTexSubImage2D,glCreateProgram:_glCreateProgram,glCreateShader:_glCreateShader,glCullFace:_glCullFace,glDeleteBuffers:_glDeleteBuffers,glDeleteFramebuffers:_glDeleteFramebuffers,glDeleteProgram:_glDeleteProgram,glDeleteQueriesEXT:_glDeleteQueriesEXT,glDeleteRenderbuffers:_glDeleteRenderbuffers,glDeleteShader:_glDeleteShader,glDeleteTextures:_glDeleteTextures,glDeleteVertexArrays:_glDeleteVertexArrays,glDeleteVertexArraysOES:_glDeleteVertexArraysOES,glDepthFunc:_glDepthFunc,glDepthMask:_glDepthMask,glDepthRange:_glDepthRange,glDepthRangef:_glDepthRangef,glDetachShader:_glDetachShader,glDisable:_glDisable,glDisableVertexAttribArray:_glDisableVertexAttribArray,glDrawArrays:_glDrawArrays,glDrawArraysInstanced:_glDrawArraysInstanced,glDrawArraysInstancedANGLE:_glDrawArraysInstancedANGLE,glDrawArraysInstancedARB:_glDrawArraysInstancedARB,glDrawArraysInstancedEXT:_glDrawArraysInstancedEXT,glDrawArraysInstancedNV:_glDrawArraysInstancedNV,glDrawBuffers:_glDrawBuffers,glDrawBuffersEXT:_glDrawBuffersEXT,glDrawBuffersWEBGL:_glDrawBuffersWEBGL,glDrawElements:_glDrawElements,glDrawElementsInstanced:_glDrawElementsInstanced,glDrawElementsInstancedANGLE:_glDrawElementsInstancedANGLE,glDrawElementsInstancedARB:_glDrawElementsInstancedARB,glDrawElementsInstancedEXT:_glDrawElementsInstancedEXT,glDrawElementsInstancedNV:_glDrawElementsInstancedNV,glEnable:_glEnable,glEnableVertexAttribArray:_glEnableVertexAttribArray,glEndQueryEXT:_glEndQueryEXT,glFinish:_glFinish,glFlush:_glFlush,glFramebufferRenderbuffer:_glFramebufferRenderbuffer,glFramebufferTexture2D:_glFramebufferTexture2D,glFrontFace:_glFrontFace,glGenBuffers:_glGenBuffers,glGenFramebuffers:_glGenFramebuffers,glGenQueriesEXT:_glGenQueriesEXT,glGenRenderbuffers:_glGenRenderbuffers,glGenTextures:_glGenTextures,glGenVertexArrays:_glGenVertexArrays,glGenVertexArraysOES:_glGenVertexArraysOES,glGenerateMipmap:_glGenerateMipmap,glGetActiveAttrib:_glGetActiveAttrib,glGetActiveUniform:_glGetActiveUniform,glGetAttachedShaders:_glGetAttachedShaders,glGetAttribLocation:_glGetAttribLocation,glGetBooleanv:_glGetBooleanv,glGetBufferParameteriv:_glGetBufferParameteriv,glGetError:_glGetError,glGetFloatv:_glGetFloatv,glGetFramebufferAttachmentParameteriv:_glGetFramebufferAttachmentParameteriv,glGetIntegerv:_glGetIntegerv,glGetProgramInfoLog:_glGetProgramInfoLog,glGetProgramiv:_glGetProgramiv,glGetQueryObjecti64vEXT:_glGetQueryObjecti64vEXT,glGetQueryObjectivEXT:_glGetQueryObjectivEXT,glGetQueryObjectui64vEXT:_glGetQueryObjectui64vEXT,glGetQueryObjectuivEXT:_glGetQueryObjectuivEXT,glGetQueryivEXT:_glGetQueryivEXT,glGetRenderbufferParameteriv:_glGetRenderbufferParameteriv,glGetShaderInfoLog:_glGetShaderInfoLog,glGetShaderPrecisionFormat:_glGetShaderPrecisionFormat,glGetShaderSource:_glGetShaderSource,glGetShaderiv:_glGetShaderiv,glGetString:_glGetString,glGetTexParameterfv:_glGetTexParameterfv,glGetTexParameteriv:_glGetTexParameteriv,glGetUniformLocation:_glGetUniformLocation,glGetUniformfv:_glGetUniformfv,glGetUniformiv:_glGetUniformiv,glGetVertexAttribPointerv:_glGetVertexAttribPointerv,glGetVertexAttribfv:_glGetVertexAttribfv,glGetVertexAttribiv:_glGetVertexAttribiv,glHint:_glHint,glIsBuffer:_glIsBuffer,glIsEnabled:_glIsEnabled,glIsFramebuffer:_glIsFramebuffer,glIsProgram:_glIsProgram,glIsQueryEXT:_glIsQueryEXT,glIsRenderbuffer:_glIsRenderbuffer,glIsShader:_glIsShader,glIsTexture:_glIsTexture,glIsVertexArray:_glIsVertexArray,glIsVertexArrayOES:_glIsVertexArrayOES,glLineWidth:_glLineWidth,glLinkProgram:_glLinkProgram,glLoadIdentity:_glLoadIdentity,glMatrixMode:_glMatrixMode,glMultiDrawArrays:_glMultiDrawArrays,glMultiDrawArraysANGLE:_glMultiDrawArraysANGLE,glMultiDrawArraysInstancedANGLE:_glMultiDrawArraysInstancedANGLE,glMultiDrawArraysInstancedWEBGL:_glMultiDrawArraysInstancedWEBGL,glMultiDrawArraysWEBGL:_glMultiDrawArraysWEBGL,glMultiDrawElements:_glMultiDrawElements,glMultiDrawElementsANGLE:_glMultiDrawElementsANGLE,glMultiDrawElementsInstancedANGLE:_glMultiDrawElementsInstancedANGLE,glMultiDrawElementsInstancedWEBGL:_glMultiDrawElementsInstancedWEBGL,glMultiDrawElementsWEBGL:_glMultiDrawElementsWEBGL,glPixelStorei:_glPixelStorei,glPolygonOffset:_glPolygonOffset,glQueryCounterEXT:_glQueryCounterEXT,glReadPixels:_glReadPixels,glReleaseShaderCompiler:_glReleaseShaderCompiler,glRenderbufferStorage:_glRenderbufferStorage,glSampleCoverage:_glSampleCoverage,glScissor:_glScissor,glShaderBinary:_glShaderBinary,glShaderSource:_glShaderSource,glStencilFunc:_glStencilFunc,glStencilFuncSeparate:_glStencilFuncSeparate,glStencilMask:_glStencilMask,glStencilMaskSeparate:_glStencilMaskSeparate,glStencilOp:_glStencilOp,glStencilOpSeparate:_glStencilOpSeparate,glTexImage2D:_glTexImage2D,glTexParameterf:_glTexParameterf,glTexParameterfv:_glTexParameterfv,glTexParameteri:_glTexParameteri,glTexParameteriv:_glTexParameteriv,glTexSubImage2D:_glTexSubImage2D,glUniform1f:_glUniform1f,glUniform1fv:_glUniform1fv,glUniform1i:_glUniform1i,glUniform1iv:_glUniform1iv,glUniform2f:_glUniform2f,glUniform2fv:_glUniform2fv,glUniform2i:_glUniform2i,glUniform2iv:_glUniform2iv,glUniform3f:_glUniform3f,glUniform3fv:_glUniform3fv,glUniform3i:_glUniform3i,glUniform3iv:_glUniform3iv,glUniform4f:_glUniform4f,glUniform4fv:_glUniform4fv,glUniform4i:_glUniform4i,glUniform4iv:_glUniform4iv,glUniformMatrix2fv:_glUniformMatrix2fv,glUniformMatrix3fv:_glUniformMatrix3fv,glUniformMatrix4fv:_glUniformMatrix4fv,glUseProgram:_glUseProgram,glValidateProgram:_glValidateProgram,glVertexAttrib1f:_glVertexAttrib1f,glVertexAttrib1fv:_glVertexAttrib1fv,glVertexAttrib2f:_glVertexAttrib2f,glVertexAttrib2fv:_glVertexAttrib2fv,glVertexAttrib3f:_glVertexAttrib3f,glVertexAttrib3fv:_glVertexAttrib3fv,glVertexAttrib4f:_glVertexAttrib4f,glVertexAttrib4fv:_glVertexAttrib4fv,glVertexAttribDivisor:_glVertexAttribDivisor,glVertexAttribDivisorANGLE:_glVertexAttribDivisorANGLE,glVertexAttribDivisorARB:_glVertexAttribDivisorARB,glVertexAttribDivisorEXT:_glVertexAttribDivisorEXT,glVertexAttribDivisorNV:_glVertexAttribDivisorNV,glVertexAttribPointer:_glVertexAttribPointer,glVertexPointer:_glVertexPointer,glViewport:_glViewport,handle_next_result_js:handle_next_result_js,hiwire_invalid_ref_js:hiwire_invalid_ref_js,invoke_diii:invoke_diii,invoke_fiii:invoke_fiii,invoke_i:invoke_i,invoke_ii:invoke_ii,invoke_iii:invoke_iii,invoke_iiii:invoke_iiii,invoke_iiiii:invoke_iiiii,invoke_iiiiid:invoke_iiiiid,invoke_iiiiii:invoke_iiiiii,invoke_iiiiiii:invoke_iiiiiii,invoke_iiiiiiii:invoke_iiiiiiii,invoke_iiiiiiiiiii:invoke_iiiiiiiiiii,invoke_iiiiiiiiiiii:invoke_iiiiiiiiiiii,invoke_iiiiiiiiiiiii:invoke_iiiiiiiiiiiii,invoke_iiiiij:invoke_iiiiij,invoke_iiiiijj:invoke_iiiiijj,invoke_iiji:invoke_iiji,invoke_j:invoke_j,invoke_ji:invoke_ji,invoke_jii:invoke_jii,invoke_jiii:invoke_jiii,invoke_jiiii:invoke_jiiii,invoke_v:invoke_v,invoke_vi:invoke_vi,invoke_vii:invoke_vii,invoke_viid:invoke_viid,invoke_viif:invoke_viif,invoke_viii:invoke_viii,invoke_viiidi:invoke_viiidi,invoke_viiifi:invoke_viiifi,invoke_viiii:invoke_viiii,invoke_viiiii:invoke_viiiii,invoke_viiiiii:invoke_viiiiii,invoke_viiiiiii:invoke_viiiiiii,invoke_viiiiiiiiii:invoke_viiiiiiiiii,invoke_viiiiiiiiiiiiiii:invoke_viiiiiiiiiiiiiii,invoke_viijii:invoke_viijii,invoke_viijj:invoke_viijj,is_comlink_proxy:is_comlink_proxy,js2python_convert:js2python_convert,js2python_immutable_js:js2python_immutable_js,js2python_js:js2python_js,jslib_init_buffers_js:jslib_init_buffers_js,jslib_init_js:jslib_init_js,lineColor:_lineColor,lineRGBA:_lineRGBA,llvm_eh_typeid_for:_llvm_eh_typeid_for,memory:wasmMemory,my_dict_converter:my_dict_converter,new_error:new_error,pixelRGBA:_pixelRGBA,proc_exit:_proc_exit,proxy_cache_get:proxy_cache_get,proxy_cache_set:proxy_cache_set,pyodide_js_init:pyodide_js_init,pyproxy_AsPyObject:pyproxy_AsPyObject,pyproxy_Check:pyproxy_Check,pyproxy_new:pyproxy_new,pyproxy_new_ex:pyproxy_new_ex,python2js__default_converter_js:python2js__default_converter_js,python2js__eager_converter_js:python2js__eager_converter_js,python2js_custom__create_jscontext:python2js_custom__create_jscontext,random_get:_random_get,raw_call_js:raw_call_js,rectangleColor:_rectangleColor,rectangleRGBA:_rectangleRGBA,restoreState:restoreState,restore_stderr:restore_stderr,rotozoomSurface:_rotozoomSurface,saveState:saveState,setNetworkCallback:_setNetworkCallback,set_pyodide_module:set_pyodide_module,set_suspender:set_suspender,setprotoent:_setprotoent,stackAlloc:_stackAlloc,stackRestore:_stackRestore,stackSave:_stackSave,strftime:_strftime,strftime_l:_strftime_l,strptime:_strptime,strptime_l:_strptime_l,syncifyHandler:syncifyHandler,throw_no_gil:throw_no_gil,wrap_async_generator:wrap_async_generator,wrap_generator:wrap_generator,zoomSurface:_zoomSurface};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["__wasm_call_ctors"])();var ___wasm_apply_data_relocs=()=>(___wasm_apply_data_relocs=wasmExports["__wasm_apply_data_relocs"])();var _set_method_docstring=Module["_set_method_docstring"]=(a0,a1)=>(_set_method_docstring=Module["_set_method_docstring"]=wasmExports["set_method_docstring"])(a0,a1);var _PyObject_GetAttrString=Module["_PyObject_GetAttrString"]=(a0,a1)=>(_PyObject_GetAttrString=Module["_PyObject_GetAttrString"]=wasmExports["PyObject_GetAttrString"])(a0,a1);var __PyUnicode_FromId=Module["__PyUnicode_FromId"]=a0=>(__PyUnicode_FromId=Module["__PyUnicode_FromId"]=wasmExports["_PyUnicode_FromId"])(a0);var _PyObject_VectorcallMethod=Module["_PyObject_VectorcallMethod"]=(a0,a1,a2,a3)=>(_PyObject_VectorcallMethod=Module["_PyObject_VectorcallMethod"]=wasmExports["PyObject_VectorcallMethod"])(a0,a1,a2,a3);var _PyUnicode_AsUTF8AndSize=Module["_PyUnicode_AsUTF8AndSize"]=(a0,a1)=>(_PyUnicode_AsUTF8AndSize=Module["_PyUnicode_AsUTF8AndSize"]=wasmExports["PyUnicode_AsUTF8AndSize"])(a0,a1);var _malloc=a0=>(_malloc=wasmExports["malloc"])(a0);var _memcpy=(a0,a1,a2)=>(_memcpy=wasmExports["memcpy"])(a0,a1,a2);var __Py_Dealloc=Module["__Py_Dealloc"]=a0=>(__Py_Dealloc=Module["__Py_Dealloc"]=wasmExports["_Py_Dealloc"])(a0);var _PyErr_Format=Module["_PyErr_Format"]=(a0,a1,a2)=>(_PyErr_Format=Module["_PyErr_Format"]=wasmExports["PyErr_Format"])(a0,a1,a2);var _add_methods_and_set_docstrings=Module["_add_methods_and_set_docstrings"]=(a0,a1,a2)=>(_add_methods_and_set_docstrings=Module["_add_methods_and_set_docstrings"]=wasmExports["add_methods_and_set_docstrings"])(a0,a1,a2);var _PyModule_AddFunctions=Module["_PyModule_AddFunctions"]=(a0,a1)=>(_PyModule_AddFunctions=Module["_PyModule_AddFunctions"]=wasmExports["PyModule_AddFunctions"])(a0,a1);var _docstring_init=Module["_docstring_init"]=()=>(_docstring_init=Module["_docstring_init"]=wasmExports["docstring_init"])();var _PyImport_ImportModule=Module["_PyImport_ImportModule"]=a0=>(_PyImport_ImportModule=Module["_PyImport_ImportModule"]=wasmExports["PyImport_ImportModule"])(a0);var _dump_traceback=Module["_dump_traceback"]=()=>(_dump_traceback=Module["_dump_traceback"]=wasmExports["dump_traceback"])();var _fileno=a0=>(_fileno=wasmExports["fileno"])(a0);var _PyGILState_GetThisThreadState=Module["_PyGILState_GetThisThreadState"]=()=>(_PyGILState_GetThisThreadState=Module["_PyGILState_GetThisThreadState"]=wasmExports["PyGILState_GetThisThreadState"])();var __Py_DumpTraceback=Module["__Py_DumpTraceback"]=(a0,a1)=>(__Py_DumpTraceback=Module["__Py_DumpTraceback"]=wasmExports["_Py_DumpTraceback"])(a0,a1);var _set_error=Module["_set_error"]=a0=>(_set_error=Module["_set_error"]=wasmExports["set_error"])(a0);var _PyErr_SetObject=Module["_PyErr_SetObject"]=(a0,a1)=>(_PyErr_SetObject=Module["_PyErr_SetObject"]=wasmExports["PyErr_SetObject"])(a0,a1);var _restore_sys_last_exception=Module["_restore_sys_last_exception"]=a0=>(_restore_sys_last_exception=Module["_restore_sys_last_exception"]=wasmExports["restore_sys_last_exception"])(a0);var _PySys_GetObject=Module["_PySys_GetObject"]=a0=>(_PySys_GetObject=Module["_PySys_GetObject"]=wasmExports["PySys_GetObject"])(a0);var _PyErr_SetRaisedException=Module["_PyErr_SetRaisedException"]=a0=>(_PyErr_SetRaisedException=Module["_PyErr_SetRaisedException"]=wasmExports["PyErr_SetRaisedException"])(a0);var _wrap_exception=Module["_wrap_exception"]=()=>(_wrap_exception=Module["_wrap_exception"]=wasmExports["wrap_exception"])();var _PyErr_GetRaisedException=Module["_PyErr_GetRaisedException"]=()=>(_PyErr_GetRaisedException=Module["_PyErr_GetRaisedException"]=wasmExports["PyErr_GetRaisedException"])();var _PyErr_GivenExceptionMatches=Module["_PyErr_GivenExceptionMatches"]=(a0,a1)=>(_PyErr_GivenExceptionMatches=Module["_PyErr_GivenExceptionMatches"]=wasmExports["PyErr_GivenExceptionMatches"])(a0,a1);var _PyErr_Print=Module["_PyErr_Print"]=()=>(_PyErr_Print=Module["_PyErr_Print"]=wasmExports["PyErr_Print"])();var __PyObject_GetAttrId=Module["__PyObject_GetAttrId"]=(a0,a1)=>(__PyObject_GetAttrId=Module["__PyObject_GetAttrId"]=wasmExports["_PyObject_GetAttrId"])(a0,a1);var _PyUnicode_AsUTF8=Module["_PyUnicode_AsUTF8"]=a0=>(_PyUnicode_AsUTF8=Module["_PyUnicode_AsUTF8"]=wasmExports["PyUnicode_AsUTF8"])(a0);var _JsvNull_Check=Module["_JsvNull_Check"]=a0=>(_JsvNull_Check=Module["_JsvNull_Check"]=wasmExports["JsvNull_Check"])(a0);var _PySys_WriteStderr=Module["_PySys_WriteStderr"]=(a0,a1)=>(_PySys_WriteStderr=Module["_PySys_WriteStderr"]=wasmExports["PySys_WriteStderr"])(a0,a1);var _PyErr_DisplayException=Module["_PyErr_DisplayException"]=a0=>(_PyErr_DisplayException=Module["_PyErr_DisplayException"]=wasmExports["PyErr_DisplayException"])(a0);var _JsvString_FromId=Module["_JsvString_FromId"]=a0=>(_JsvString_FromId=Module["_JsvString_FromId"]=wasmExports["JsvString_FromId"])(a0);var _pythonexc2js=Module["_pythonexc2js"]=()=>(_pythonexc2js=Module["_pythonexc2js"]=wasmExports["pythonexc2js"])();var _trigger_fatal_error=Module["_trigger_fatal_error"]=(a0,a1)=>(_trigger_fatal_error=Module["_trigger_fatal_error"]=wasmExports["trigger_fatal_error"])(a0,a1);var _raw_call=Module["_raw_call"]=(a0,a1)=>(_raw_call=Module["_raw_call"]=wasmExports["raw_call"])(a0,a1);var _JsProxy_Val=Module["_JsProxy_Val"]=a0=>(_JsProxy_Val=Module["_JsProxy_Val"]=wasmExports["JsProxy_Val"])(a0);var _error_handling_init=Module["_error_handling_init"]=a0=>(_error_handling_init=Module["_error_handling_init"]=wasmExports["error_handling_init"])(a0);var _hiwire_invalid_ref=Module["_hiwire_invalid_ref"]=(a0,a1)=>(_hiwire_invalid_ref=Module["_hiwire_invalid_ref"]=wasmExports["hiwire_invalid_ref"])(a0,a1);var _init_pyodide_proxy=Module["_init_pyodide_proxy"]=()=>(_init_pyodide_proxy=Module["_init_pyodide_proxy"]=wasmExports["init_pyodide_proxy"])();var _python2js=Module["_python2js"]=a0=>(_python2js=Module["_python2js"]=wasmExports["python2js"])(a0);var _PyInit__pyodide_core=Module["_PyInit__pyodide_core"]=()=>(_PyInit__pyodide_core=Module["_PyInit__pyodide_core"]=wasmExports["PyInit__pyodide_core"])();var _PyErr_Occurred=Module["_PyErr_Occurred"]=()=>(_PyErr_Occurred=Module["_PyErr_Occurred"]=wasmExports["PyErr_Occurred"])();var __PyErr_FormatFromCause=Module["__PyErr_FormatFromCause"]=(a0,a1,a2)=>(__PyErr_FormatFromCause=Module["__PyErr_FormatFromCause"]=wasmExports["_PyErr_FormatFromCause"])(a0,a1,a2);var _PyModule_Create2=Module["_PyModule_Create2"]=(a0,a1)=>(_PyModule_Create2=Module["_PyModule_Create2"]=wasmExports["PyModule_Create2"])(a0,a1);var _PyImport_GetModuleDict=Module["_PyImport_GetModuleDict"]=()=>(_PyImport_GetModuleDict=Module["_PyImport_GetModuleDict"]=wasmExports["PyImport_GetModuleDict"])();var _PyDict_SetItemString=Module["_PyDict_SetItemString"]=(a0,a1,a2)=>(_PyDict_SetItemString=Module["_PyDict_SetItemString"]=wasmExports["PyDict_SetItemString"])(a0,a1,a2);var _jslib_init=Module["_jslib_init"]=()=>(_jslib_init=Module["_jslib_init"]=wasmExports["jslib_init"])();var _python2js_init=Module["_python2js_init"]=a0=>(_python2js_init=Module["_python2js_init"]=wasmExports["python2js_init"])(a0);var _jsproxy_init=Module["_jsproxy_init"]=a0=>(_jsproxy_init=Module["_jsproxy_init"]=wasmExports["jsproxy_init"])(a0);var _jsproxy_call_init=Module["_jsproxy_call_init"]=a0=>(_jsproxy_call_init=Module["_jsproxy_call_init"]=wasmExports["jsproxy_call_init"])(a0);var _pyproxy_init=Module["_pyproxy_init"]=a0=>(_pyproxy_init=Module["_pyproxy_init"]=wasmExports["pyproxy_init"])(a0);var _jsbind_init=Module["_jsbind_init"]=a0=>(_jsbind_init=Module["_jsbind_init"]=wasmExports["jsbind_init"])(a0);var _pyodide_export=Module["_pyodide_export"]=()=>(_pyodide_export=Module["_pyodide_export"]=wasmExports["pyodide_export"])();var _py_version_major=Module["_py_version_major"]=()=>(_py_version_major=Module["_py_version_major"]=wasmExports["py_version_major"])();var _set_new_cframe=Module["_set_new_cframe"]=a0=>(_set_new_cframe=Module["_set_new_cframe"]=wasmExports["set_new_cframe"])(a0);var _PyUnicode_Data=Module["_PyUnicode_Data"]=a0=>(_PyUnicode_Data=Module["_PyUnicode_Data"]=wasmExports["PyUnicode_Data"])(a0);var __js2python_none=Module["__js2python_none"]=()=>(__js2python_none=Module["__js2python_none"]=wasmExports["_js2python_none"])();var __js2python_true=Module["__js2python_true"]=()=>(__js2python_true=Module["__js2python_true"]=wasmExports["_js2python_true"])();var __js2python_false=Module["__js2python_false"]=()=>(__js2python_false=Module["__js2python_false"]=wasmExports["_js2python_false"])();var __js2python_pyproxy=Module["__js2python_pyproxy"]=a0=>(__js2python_pyproxy=Module["__js2python_pyproxy"]=wasmExports["_js2python_pyproxy"])(a0);var _js2python_immutable=Module["_js2python_immutable"]=a0=>(_js2python_immutable=Module["_js2python_immutable"]=wasmExports["js2python_immutable"])(a0);var _js2python=Module["_js2python"]=a0=>(_js2python=Module["_js2python"]=wasmExports["js2python"])(a0);var _JsProxy_getflags=Module["_JsProxy_getflags"]=a0=>(_JsProxy_getflags=Module["_JsProxy_getflags"]=wasmExports["JsProxy_getflags"])(a0);var _PyLong_AsLong=Module["_PyLong_AsLong"]=a0=>(_PyLong_AsLong=Module["_PyLong_AsLong"]=wasmExports["PyLong_AsLong"])(a0);var _JsProxy_is_py_json=Module["_JsProxy_is_py_json"]=a0=>(_JsProxy_is_py_json=Module["_JsProxy_is_py_json"]=wasmExports["JsProxy_is_py_json"])(a0);var _js2python_as_py_json=Module["_js2python_as_py_json"]=a0=>(_js2python_as_py_json=Module["_js2python_as_py_json"]=wasmExports["js2python_as_py_json"])(a0);var _JsProxy_create_with_type=Module["_JsProxy_create_with_type"]=(a0,a1,a2,a3)=>(_JsProxy_create_with_type=Module["_JsProxy_create_with_type"]=wasmExports["JsProxy_create_with_type"])(a0,a1,a2,a3);var _JsProxy_bind_sig=Module["_JsProxy_bind_sig"]=(a0,a1)=>(_JsProxy_bind_sig=Module["_JsProxy_bind_sig"]=wasmExports["JsProxy_bind_sig"])(a0,a1);var _hiwire_get=Module["_hiwire_get"]=a0=>(_hiwire_get=Module["_hiwire_get"]=wasmExports["hiwire_get"])(a0);var _JsRef_toVal=Module["_JsRef_toVal"]=a0=>(_JsRef_toVal=Module["_JsRef_toVal"]=wasmExports["JsRef_toVal"])(a0);var _PyErr_SetString=Module["_PyErr_SetString"]=(a0,a1)=>(_PyErr_SetString=Module["_PyErr_SetString"]=wasmExports["PyErr_SetString"])(a0,a1);var _JsProxy_create_with_this=Module["_JsProxy_create_with_this"]=(a0,a1,a2,a3)=>(_JsProxy_create_with_this=Module["_JsProxy_create_with_this"]=wasmExports["JsProxy_create_with_this"])(a0,a1,a2,a3);var _JsProxy_bind_class=Module["_JsProxy_bind_class"]=(a0,a1)=>(_JsProxy_bind_class=Module["_JsProxy_bind_class"]=wasmExports["JsProxy_bind_class"])(a0,a1);var _clear_method_call_singleton=Module["_clear_method_call_singleton"]=()=>(_clear_method_call_singleton=Module["_clear_method_call_singleton"]=wasmExports["clear_method_call_singleton"])();var _hiwire_decref=Module["_hiwire_decref"]=a0=>(_hiwire_decref=Module["_hiwire_decref"]=wasmExports["hiwire_decref"])(a0);var _JsProxy_GetMethod=Module["_JsProxy_GetMethod"]=(a0,a1)=>(_JsProxy_GetMethod=Module["_JsProxy_GetMethod"]=wasmExports["JsProxy_GetMethod"])(a0,a1);var __PyObject_GenericGetAttrWithDict=Module["__PyObject_GenericGetAttrWithDict"]=(a0,a1,a2,a3)=>(__PyObject_GenericGetAttrWithDict=Module["__PyObject_GenericGetAttrWithDict"]=wasmExports["_PyObject_GenericGetAttrWithDict"])(a0,a1,a2,a3);var _strcmp=Module["_strcmp"]=(a0,a1)=>(_strcmp=Module["_strcmp"]=wasmExports["strcmp"])(a0,a1);var __PyObject_CallMethodIdObjArgs=Module["__PyObject_CallMethodIdObjArgs"]=(a0,a1,a2)=>(__PyObject_CallMethodIdObjArgs=Module["__PyObject_CallMethodIdObjArgs"]=wasmExports["_PyObject_CallMethodIdObjArgs"])(a0,a1,a2);var __PyArg_ParseTuple_SizeT=Module["__PyArg_ParseTuple_SizeT"]=(a0,a1,a2)=>(__PyArg_ParseTuple_SizeT=Module["__PyArg_ParseTuple_SizeT"]=wasmExports["_PyArg_ParseTuple_SizeT"])(a0,a1,a2);var _Js2PyConverter_convert=Module["_Js2PyConverter_convert"]=(a0,a1,a2)=>(_Js2PyConverter_convert=Module["_Js2PyConverter_convert"]=wasmExports["Js2PyConverter_convert"])(a0,a1,a2);var _hiwire_new=Module["_hiwire_new"]=a0=>(_hiwire_new=Module["_hiwire_new"]=wasmExports["hiwire_new"])(a0);var _hiwire_incref=Module["_hiwire_incref"]=a0=>(_hiwire_incref=Module["_hiwire_incref"]=wasmExports["hiwire_incref"])(a0);var _JsProxy_GetAttr=Module["_JsProxy_GetAttr"]=(a0,a1)=>(_JsProxy_GetAttr=Module["_JsProxy_GetAttr"]=wasmExports["JsProxy_GetAttr"])(a0,a1);var _handle_next_result=Module["_handle_next_result"]=(a0,a1,a2)=>(_handle_next_result=Module["_handle_next_result"]=wasmExports["handle_next_result"])(a0,a1,a2);var _free=Module["_free"]=a0=>(_free=Module["_free"]=wasmExports["free"])(a0);var _JsProxy_create_objmap=Module["_JsProxy_create_objmap"]=(a0,a1)=>(_JsProxy_create_objmap=Module["_JsProxy_create_objmap"]=wasmExports["JsProxy_create_objmap"])(a0,a1);var _JsProxy_am_send=Module["_JsProxy_am_send"]=(a0,a1,a2)=>(_JsProxy_am_send=Module["_JsProxy_am_send"]=wasmExports["JsProxy_am_send"])(a0,a1,a2);var _python2js_track_proxies=Module["_python2js_track_proxies"]=(a0,a1,a2)=>(_python2js_track_proxies=Module["_python2js_track_proxies"]=wasmExports["python2js_track_proxies"])(a0,a1,a2);var _JsvObject_CallMethodId_OneArg=Module["_JsvObject_CallMethodId_OneArg"]=(a0,a1,a2)=>(_JsvObject_CallMethodId_OneArg=Module["_JsvObject_CallMethodId_OneArg"]=wasmExports["JsvObject_CallMethodId_OneArg"])(a0,a1,a2);var _JsProxy_IterNext=Module["_JsProxy_IterNext"]=a0=>(_JsProxy_IterNext=Module["_JsProxy_IterNext"]=wasmExports["JsProxy_IterNext"])(a0);var __PyGen_SetStopIterationValue=Module["__PyGen_SetStopIterationValue"]=a0=>(__PyGen_SetStopIterationValue=Module["__PyGen_SetStopIterationValue"]=wasmExports["_PyGen_SetStopIterationValue"])(a0);var _JsGenerator_send=Module["_JsGenerator_send"]=(a0,a1)=>(_JsGenerator_send=Module["_JsGenerator_send"]=wasmExports["JsGenerator_send"])(a0,a1);var _PyErr_SetNone=Module["_PyErr_SetNone"]=a0=>(_PyErr_SetNone=Module["_PyErr_SetNone"]=wasmExports["PyErr_SetNone"])(a0);var _JsException_js_error_getter=Module["_JsException_js_error_getter"]=(a0,a1)=>(_JsException_js_error_getter=Module["_JsException_js_error_getter"]=wasmExports["JsException_js_error_getter"])(a0,a1);var _process_throw_args=Module["_process_throw_args"]=(a0,a1,a2,a3)=>(_process_throw_args=Module["_process_throw_args"]=wasmExports["process_throw_args"])(a0,a1,a2,a3);var _PyErr_NormalizeException=Module["_PyErr_NormalizeException"]=(a0,a1,a2)=>(_PyErr_NormalizeException=Module["_PyErr_NormalizeException"]=wasmExports["PyErr_NormalizeException"])(a0,a1,a2);var _PyException_GetTraceback=Module["_PyException_GetTraceback"]=a0=>(_PyException_GetTraceback=Module["_PyException_GetTraceback"]=wasmExports["PyException_GetTraceback"])(a0);var _PyException_SetTraceback=Module["_PyException_SetTraceback"]=(a0,a1)=>(_PyException_SetTraceback=Module["_PyException_SetTraceback"]=wasmExports["PyException_SetTraceback"])(a0,a1);var _PyErr_Restore=Module["_PyErr_Restore"]=(a0,a1,a2)=>(_PyErr_Restore=Module["_PyErr_Restore"]=wasmExports["PyErr_Restore"])(a0,a1,a2);var _PyErr_ExceptionMatches=Module["_PyErr_ExceptionMatches"]=a0=>(_PyErr_ExceptionMatches=Module["_PyErr_ExceptionMatches"]=wasmExports["PyErr_ExceptionMatches"])(a0);var _PyErr_Clear=Module["_PyErr_Clear"]=()=>(_PyErr_Clear=Module["_PyErr_Clear"]=wasmExports["PyErr_Clear"])();var _JsvObject_CallMethodId_NoArgs=Module["_JsvObject_CallMethodId_NoArgs"]=(a0,a1)=>(_JsvObject_CallMethodId_NoArgs=Module["_JsvObject_CallMethodId_NoArgs"]=wasmExports["JsvObject_CallMethodId_NoArgs"])(a0,a1);var _PyErr_Fetch=Module["_PyErr_Fetch"]=(a0,a1,a2)=>(_PyErr_Fetch=Module["_PyErr_Fetch"]=wasmExports["PyErr_Fetch"])(a0,a1,a2);var __agen_handle_result_js_c=Module["__agen_handle_result_js_c"]=(a0,a1,a2,a3,a4)=>(__agen_handle_result_js_c=Module["__agen_handle_result_js_c"]=wasmExports["_agen_handle_result_js_c"])(a0,a1,a2,a3,a4);var _PyObject_CallOneArg=Module["_PyObject_CallOneArg"]=(a0,a1)=>(_PyObject_CallOneArg=Module["_PyObject_CallOneArg"]=wasmExports["PyObject_CallOneArg"])(a0,a1);var __agen_handle_result=Module["__agen_handle_result"]=(a0,a1)=>(__agen_handle_result=Module["__agen_handle_result"]=wasmExports["_agen_handle_result"])(a0,a1);var _JsArray_sq_item=Module["_JsArray_sq_item"]=(a0,a1)=>(_JsArray_sq_item=Module["_JsArray_sq_item"]=wasmExports["JsArray_sq_item"])(a0,a1);var _JsArray_sq_ass_item=Module["_JsArray_sq_ass_item"]=(a0,a1,a2)=>(_JsArray_sq_ass_item=Module["_JsArray_sq_ass_item"]=wasmExports["JsArray_sq_ass_item"])(a0,a1,a2);var _JsTypedArray_sq_ass_item=Module["_JsTypedArray_sq_ass_item"]=(a0,a1,a2)=>(_JsTypedArray_sq_ass_item=Module["_JsTypedArray_sq_ass_item"]=wasmExports["JsTypedArray_sq_ass_item"])(a0,a1,a2);var _JsMap_update=Module["_JsMap_update"]=(a0,a1,a2)=>(_JsMap_update=Module["_JsMap_update"]=wasmExports["JsMap_update"])(a0,a1,a2);var _wrap_promise=Module["_wrap_promise"]=(a0,a1,a2)=>(_wrap_promise=Module["_wrap_promise"]=wasmExports["wrap_promise"])(a0,a1,a2);var _PyTuple_GetItem=Module["_PyTuple_GetItem"]=(a0,a1)=>(_PyTuple_GetItem=Module["_PyTuple_GetItem"]=wasmExports["PyTuple_GetItem"])(a0,a1);var _JsvObject_CallMethodId=Module["_JsvObject_CallMethodId"]=(a0,a1,a2)=>(_JsvObject_CallMethodId=Module["_JsvObject_CallMethodId"]=wasmExports["JsvObject_CallMethodId"])(a0,a1,a2);var _JsModule_GetAll=Module["_JsModule_GetAll"]=(a0,a1)=>(_JsModule_GetAll=Module["_JsModule_GetAll"]=wasmExports["JsModule_GetAll"])(a0,a1);var _PyType_IsSubtype=Module["_PyType_IsSubtype"]=(a0,a1)=>(_PyType_IsSubtype=Module["_PyType_IsSubtype"]=wasmExports["PyType_IsSubtype"])(a0,a1);var _JsProxy_Check=Module["_JsProxy_Check"]=a0=>(_JsProxy_Check=Module["_JsProxy_Check"]=wasmExports["JsProxy_Check"])(a0);var _JsBuffer_CopyIntoMemoryView=Module["_JsBuffer_CopyIntoMemoryView"]=(a0,a1,a2,a3)=>(_JsBuffer_CopyIntoMemoryView=Module["_JsBuffer_CopyIntoMemoryView"]=wasmExports["JsBuffer_CopyIntoMemoryView"])(a0,a1,a2,a3);var _PyMem_Malloc=Module["_PyMem_Malloc"]=a0=>(_PyMem_Malloc=Module["_PyMem_Malloc"]=wasmExports["PyMem_Malloc"])(a0);var _PyMemoryView_FromObject=Module["_PyMemoryView_FromObject"]=a0=>(_PyMemoryView_FromObject=Module["_PyMemoryView_FromObject"]=wasmExports["PyMemoryView_FromObject"])(a0);var _JsBuffer_cinit=Module["_JsBuffer_cinit"]=a0=>(_JsBuffer_cinit=Module["_JsBuffer_cinit"]=wasmExports["JsBuffer_cinit"])(a0);var _hiwire_new_deduplicate=Module["_hiwire_new_deduplicate"]=a0=>(_hiwire_new_deduplicate=Module["_hiwire_new_deduplicate"]=wasmExports["hiwire_new_deduplicate"])(a0);var _JsRef_new=Module["_JsRef_new"]=a0=>(_JsRef_new=Module["_JsRef_new"]=wasmExports["JsRef_new"])(a0);var _PyTuple_Pack=Module["_PyTuple_Pack"]=(a0,a1)=>(_PyTuple_Pack=Module["_PyTuple_Pack"]=wasmExports["PyTuple_Pack"])(a0,a1);var _PyLong_FromLong=Module["_PyLong_FromLong"]=a0=>(_PyLong_FromLong=Module["_PyLong_FromLong"]=wasmExports["PyLong_FromLong"])(a0);var _PyDict_GetItemWithError=Module["_PyDict_GetItemWithError"]=(a0,a1)=>(_PyDict_GetItemWithError=Module["_PyDict_GetItemWithError"]=wasmExports["PyDict_GetItemWithError"])(a0,a1);var _PyObject_SelfIter=Module["_PyObject_SelfIter"]=a0=>(_PyObject_SelfIter=Module["_PyObject_SelfIter"]=wasmExports["PyObject_SelfIter"])(a0);var _PyVectorcall_Call=Module["_PyVectorcall_Call"]=(a0,a1,a2)=>(_PyVectorcall_Call=Module["_PyVectorcall_Call"]=wasmExports["PyVectorcall_Call"])(a0,a1,a2);var _PyErr_NoMemory=Module["_PyErr_NoMemory"]=()=>(_PyErr_NoMemory=Module["_PyErr_NoMemory"]=wasmExports["PyErr_NoMemory"])();var _PyType_FromSpecWithBases=Module["_PyType_FromSpecWithBases"]=(a0,a1)=>(_PyType_FromSpecWithBases=Module["_PyType_FromSpecWithBases"]=wasmExports["PyType_FromSpecWithBases"])(a0,a1);var _PyObject_SetAttr=Module["_PyObject_SetAttr"]=(a0,a1,a2)=>(_PyObject_SetAttr=Module["_PyObject_SetAttr"]=wasmExports["PyObject_SetAttr"])(a0,a1,a2);var _PyMem_Free=Module["_PyMem_Free"]=a0=>(_PyMem_Free=Module["_PyMem_Free"]=wasmExports["PyMem_Free"])(a0);var _PyDict_SetItem=Module["_PyDict_SetItem"]=(a0,a1,a2)=>(_PyDict_SetItem=Module["_PyDict_SetItem"]=wasmExports["PyDict_SetItem"])(a0,a1,a2);var _JsProxy_create=Module["_JsProxy_create"]=a0=>(_JsProxy_create=Module["_JsProxy_create"]=wasmExports["JsProxy_create"])(a0);var _JsProxy_init_docstrings=Module["_JsProxy_init_docstrings"]=a0=>(_JsProxy_init_docstrings=Module["_JsProxy_init_docstrings"]=wasmExports["JsProxy_init_docstrings"])(a0);var _run_sync_not_supported=Module["_run_sync_not_supported"]=(a0,a1)=>(_run_sync_not_supported=Module["_run_sync_not_supported"]=wasmExports["run_sync_not_supported"])(a0,a1);var _run_sync=Module["_run_sync"]=(a0,a1)=>(_run_sync=Module["_run_sync"]=wasmExports["run_sync"])(a0,a1);var _py_is_awaitable=Module["_py_is_awaitable"]=a0=>(_py_is_awaitable=Module["_py_is_awaitable"]=wasmExports["py_is_awaitable"])(a0);var _JsvPromise_Syncify=Module["_JsvPromise_Syncify"]=a0=>(_JsvPromise_Syncify=Module["_JsvPromise_Syncify"]=wasmExports["JsvPromise_Syncify"])(a0);var _can_run_sync=Module["_can_run_sync"]=(a0,a1)=>(_can_run_sync=Module["_can_run_sync"]=wasmExports["can_run_sync"])(a0,a1);var _PyDict_New=Module["_PyDict_New"]=()=>(_PyDict_New=Module["_PyDict_New"]=wasmExports["PyDict_New"])();var _PyObject_SetAttrString=Module["_PyObject_SetAttrString"]=(a0,a1,a2)=>(_PyObject_SetAttrString=Module["_PyObject_SetAttrString"]=wasmExports["PyObject_SetAttrString"])(a0,a1,a2);var _PyModule_AddObject=Module["_PyModule_AddObject"]=(a0,a1,a2)=>(_PyModule_AddObject=Module["_PyModule_AddObject"]=wasmExports["PyModule_AddObject"])(a0,a1,a2);var _PyType_Ready=Module["_PyType_Ready"]=a0=>(_PyType_Ready=Module["_PyType_Ready"]=wasmExports["PyType_Ready"])(a0);var _JsMethod_Vectorcall_impl=Module["_JsMethod_Vectorcall_impl"]=(a0,a1,a2,a3,a4,a5)=>(_JsMethod_Vectorcall_impl=Module["_JsMethod_Vectorcall_impl"]=wasmExports["JsMethod_Vectorcall_impl"])(a0,a1,a2,a3,a4,a5);var _JsvObject_CallMethodId_TwoArgs=Module["_JsvObject_CallMethodId_TwoArgs"]=(a0,a1,a2,a3)=>(_JsvObject_CallMethodId_TwoArgs=Module["_JsvObject_CallMethodId_TwoArgs"]=wasmExports["JsvObject_CallMethodId_TwoArgs"])(a0,a1,a2,a3);var _PyObject_Repr=Module["_PyObject_Repr"]=a0=>(_PyObject_Repr=Module["_PyObject_Repr"]=wasmExports["PyObject_Repr"])(a0);var _PyIndex_Check=Module["_PyIndex_Check"]=a0=>(_PyIndex_Check=Module["_PyIndex_Check"]=wasmExports["PyIndex_Check"])(a0);var _PyNumber_AsSsize_t=Module["_PyNumber_AsSsize_t"]=(a0,a1)=>(_PyNumber_AsSsize_t=Module["_PyNumber_AsSsize_t"]=wasmExports["PyNumber_AsSsize_t"])(a0,a1);var _PySlice_Unpack=Module["_PySlice_Unpack"]=(a0,a1,a2,a3)=>(_PySlice_Unpack=Module["_PySlice_Unpack"]=wasmExports["PySlice_Unpack"])(a0,a1,a2,a3);var _PySlice_AdjustIndices=Module["_PySlice_AdjustIndices"]=(a0,a1,a2,a3)=>(_PySlice_AdjustIndices=Module["_PySlice_AdjustIndices"]=wasmExports["PySlice_AdjustIndices"])(a0,a1,a2,a3);var _PySequence_Fast=Module["_PySequence_Fast"]=(a0,a1)=>(_PySequence_Fast=Module["_PySequence_Fast"]=wasmExports["PySequence_Fast"])(a0,a1);var __PyArg_ParseTupleAndKeywords_SizeT=Module["__PyArg_ParseTupleAndKeywords_SizeT"]=(a0,a1,a2,a3,a4)=>(__PyArg_ParseTupleAndKeywords_SizeT=Module["__PyArg_ParseTupleAndKeywords_SizeT"]=wasmExports["_PyArg_ParseTupleAndKeywords_SizeT"])(a0,a1,a2,a3,a4);var _PySet_New=Module["_PySet_New"]=a0=>(_PySet_New=Module["_PySet_New"]=wasmExports["PySet_New"])(a0);var __PySet_Update=Module["__PySet_Update"]=(a0,a1)=>(__PySet_Update=Module["__PySet_Update"]=wasmExports["_PySet_Update"])(a0,a1);var _PyUnicode_FromString=Module["_PyUnicode_FromString"]=a0=>(_PyUnicode_FromString=Module["_PyUnicode_FromString"]=wasmExports["PyUnicode_FromString"])(a0);var _PySet_Discard=Module["_PySet_Discard"]=(a0,a1)=>(_PySet_Discard=Module["_PySet_Discard"]=wasmExports["PySet_Discard"])(a0,a1);var _PyList_New=Module["_PyList_New"]=a0=>(_PyList_New=Module["_PyList_New"]=wasmExports["PyList_New"])(a0);var __PyList_Extend=Module["__PyList_Extend"]=(a0,a1)=>(__PyList_Extend=Module["__PyList_Extend"]=wasmExports["_PyList_Extend"])(a0,a1);var _PyList_Sort=Module["_PyList_Sort"]=a0=>(_PyList_Sort=Module["_PyList_Sort"]=wasmExports["PyList_Sort"])(a0);var __PyArg_ParseStack_SizeT=Module["__PyArg_ParseStack_SizeT"]=(a0,a1,a2,a3)=>(__PyArg_ParseStack_SizeT=Module["__PyArg_ParseStack_SizeT"]=wasmExports["_PyArg_ParseStack_SizeT"])(a0,a1,a2,a3);var _PyObject_GetIter=Module["_PyObject_GetIter"]=a0=>(_PyObject_GetIter=Module["_PyObject_GetIter"]=wasmExports["PyObject_GetIter"])(a0);var _PyObject_RichCompareBool=Module["_PyObject_RichCompareBool"]=(a0,a1,a2)=>(_PyObject_RichCompareBool=Module["_PyObject_RichCompareBool"]=wasmExports["PyObject_RichCompareBool"])(a0,a1,a2);var __PyArg_ParseStackAndKeywords_SizeT=Module["__PyArg_ParseStackAndKeywords_SizeT"]=(a0,a1,a2,a3,a4)=>(__PyArg_ParseStackAndKeywords_SizeT=Module["__PyArg_ParseStackAndKeywords_SizeT"]=wasmExports["_PyArg_ParseStackAndKeywords_SizeT"])(a0,a1,a2,a3,a4);var _hiwire_pop=Module["_hiwire_pop"]=a0=>(_hiwire_pop=Module["_hiwire_pop"]=wasmExports["hiwire_pop"])(a0);var _puts=Module["_puts"]=a0=>(_puts=Module["_puts"]=wasmExports["puts"])(a0);var _strncmp=Module["_strncmp"]=(a0,a1,a2)=>(_strncmp=Module["_strncmp"]=wasmExports["strncmp"])(a0,a1,a2);var _PyObject_GenericSetAttr=Module["_PyObject_GenericSetAttr"]=(a0,a1,a2)=>(_PyObject_GenericSetAttr=Module["_PyObject_GenericSetAttr"]=wasmExports["PyObject_GenericSetAttr"])(a0,a1,a2);var __Py_HashBytes=Module["__Py_HashBytes"]=(a0,a1)=>(__Py_HashBytes=Module["__Py_HashBytes"]=wasmExports["_Py_HashBytes"])(a0,a1);var _JsMethod_Construct_impl=Module["_JsMethod_Construct_impl"]=(a0,a1,a2,a3,a4)=>(_JsMethod_Construct_impl=Module["_JsMethod_Construct_impl"]=wasmExports["JsMethod_Construct_impl"])(a0,a1,a2,a3,a4);var __PyArg_CheckPositional=Module["__PyArg_CheckPositional"]=(a0,a1,a2,a3)=>(__PyArg_CheckPositional=Module["__PyArg_CheckPositional"]=wasmExports["_PyArg_CheckPositional"])(a0,a1,a2,a3);var __PyNumber_Index=Module["__PyNumber_Index"]=a0=>(__PyNumber_Index=Module["__PyNumber_Index"]=wasmExports["_PyNumber_Index"])(a0);var _PyLong_AsSsize_t=Module["_PyLong_AsSsize_t"]=a0=>(_PyLong_AsSsize_t=Module["_PyLong_AsSsize_t"]=wasmExports["PyLong_AsSsize_t"])(a0);var _PyLong_FromSsize_t=Module["_PyLong_FromSsize_t"]=a0=>(_PyLong_FromSsize_t=Module["_PyLong_FromSsize_t"]=wasmExports["PyLong_FromSsize_t"])(a0);var _PyObject_GetItem=Module["_PyObject_GetItem"]=(a0,a1)=>(_PyObject_GetItem=Module["_PyObject_GetItem"]=wasmExports["PyObject_GetItem"])(a0,a1);var _PyObject_DelItem=Module["_PyObject_DelItem"]=(a0,a1)=>(_PyObject_DelItem=Module["_PyObject_DelItem"]=wasmExports["PyObject_DelItem"])(a0,a1);var _PyObject_SetItem=Module["_PyObject_SetItem"]=(a0,a1,a2)=>(_PyObject_SetItem=Module["_PyObject_SetItem"]=wasmExports["PyObject_SetItem"])(a0,a1,a2);var _PyObject_GetBuffer=Module["_PyObject_GetBuffer"]=(a0,a1,a2)=>(_PyObject_GetBuffer=Module["_PyObject_GetBuffer"]=wasmExports["PyObject_GetBuffer"])(a0,a1,a2);var _PyBuffer_Release=Module["_PyBuffer_Release"]=a0=>(_PyBuffer_Release=Module["_PyBuffer_Release"]=wasmExports["PyBuffer_Release"])(a0);var _PyBytes_FromStringAndSize=Module["_PyBytes_FromStringAndSize"]=(a0,a1)=>(_PyBytes_FromStringAndSize=Module["_PyBytes_FromStringAndSize"]=wasmExports["PyBytes_FromStringAndSize"])(a0,a1);var _PyObject_Vectorcall=Module["_PyObject_Vectorcall"]=(a0,a1,a2,a3)=>(_PyObject_Vectorcall=Module["_PyObject_Vectorcall"]=wasmExports["PyObject_Vectorcall"])(a0,a1,a2,a3);var _Py_EnterRecursiveCall=Module["_Py_EnterRecursiveCall"]=a0=>(_Py_EnterRecursiveCall=Module["_Py_EnterRecursiveCall"]=wasmExports["Py_EnterRecursiveCall"])(a0);var _Py_LeaveRecursiveCall=Module["_Py_LeaveRecursiveCall"]=()=>(_Py_LeaveRecursiveCall=Module["_Py_LeaveRecursiveCall"]=wasmExports["Py_LeaveRecursiveCall"])();var _Py2JsConverter_convert=Module["_Py2JsConverter_convert"]=(a0,a1,a2)=>(_Py2JsConverter_convert=Module["_Py2JsConverter_convert"]=wasmExports["Py2JsConverter_convert"])(a0,a1,a2);var __PyUnicode_EQ=Module["__PyUnicode_EQ"]=(a0,a1)=>(__PyUnicode_EQ=Module["__PyUnicode_EQ"]=wasmExports["_PyUnicode_EQ"])(a0,a1);var _PyUnicode_FromFormat=Module["_PyUnicode_FromFormat"]=(a0,a1)=>(_PyUnicode_FromFormat=Module["_PyUnicode_FromFormat"]=wasmExports["PyUnicode_FromFormat"])(a0,a1);var _PyType_GenericNew=Module["_PyType_GenericNew"]=(a0,a1,a2)=>(_PyType_GenericNew=Module["_PyType_GenericNew"]=wasmExports["PyType_GenericNew"])(a0,a1,a2);var _PyObject_IsInstance=Module["_PyObject_IsInstance"]=(a0,a1)=>(_PyObject_IsInstance=Module["_PyObject_IsInstance"]=wasmExports["PyObject_IsInstance"])(a0,a1);var _python2js_inner=Module["_python2js_inner"]=(a0,a1,a2,a3,a4)=>(_python2js_inner=Module["_python2js_inner"]=wasmExports["python2js_inner"])(a0,a1,a2,a3,a4);var _python2js_custom=Module["_python2js_custom"]=(a0,a1,a2,a3,a4,a5)=>(_python2js_custom=Module["_python2js_custom"]=wasmExports["python2js_custom"])(a0,a1,a2,a3,a4,a5);var _PyObject_GC_UnTrack=Module["_PyObject_GC_UnTrack"]=a0=>(_PyObject_GC_UnTrack=Module["_PyObject_GC_UnTrack"]=wasmExports["PyObject_GC_UnTrack"])(a0);var _check_gil=Module["_check_gil"]=()=>(_check_gil=Module["_check_gil"]=wasmExports["check_gil"])();var _PyGILState_Check=Module["_PyGILState_Check"]=()=>(_PyGILState_Check=Module["_PyGILState_Check"]=wasmExports["PyGILState_Check"])();var _PyGen_GetCode=Module["_PyGen_GetCode"]=a0=>(_PyGen_GetCode=Module["_PyGen_GetCode"]=wasmExports["PyGen_GetCode"])(a0);var _pyproxy_getflags=Module["_pyproxy_getflags"]=(a0,a1)=>(_pyproxy_getflags=Module["_pyproxy_getflags"]=wasmExports["pyproxy_getflags"])(a0,a1);var _PyObject_HasAttr=Module["_PyObject_HasAttr"]=(a0,a1)=>(_PyObject_HasAttr=Module["_PyObject_HasAttr"]=wasmExports["PyObject_HasAttr"])(a0,a1);var __PyObject_NextNotImplemented=Module["__PyObject_NextNotImplemented"]=a0=>(__PyObject_NextNotImplemented=Module["__PyObject_NextNotImplemented"]=wasmExports["_PyObject_NextNotImplemented"])(a0);var _PyObject_IsSubclass=Module["_PyObject_IsSubclass"]=(a0,a1)=>(_PyObject_IsSubclass=Module["_PyObject_IsSubclass"]=wasmExports["PyObject_IsSubclass"])(a0,a1);var __pyproxy_repr=Module["__pyproxy_repr"]=a0=>(__pyproxy_repr=Module["__pyproxy_repr"]=wasmExports["_pyproxy_repr"])(a0);var _PyObject_Str=Module["_PyObject_Str"]=a0=>(_PyObject_Str=Module["_PyObject_Str"]=wasmExports["PyObject_Str"])(a0);var __pyproxy_type=Module["__pyproxy_type"]=a0=>(__pyproxy_type=Module["__pyproxy_type"]=wasmExports["_pyproxy_type"])(a0);var __pyproxy_hasattr=Module["__pyproxy_hasattr"]=(a0,a1)=>(__pyproxy_hasattr=Module["__pyproxy_hasattr"]=wasmExports["_pyproxy_hasattr"])(a0,a1);var _python2js_json_adaptor=Module["_python2js_json_adaptor"]=(a0,a1,a2)=>(_python2js_json_adaptor=Module["_python2js_json_adaptor"]=wasmExports["python2js_json_adaptor"])(a0,a1,a2);var __pyproxy_getattr=Module["__pyproxy_getattr"]=(a0,a1,a2)=>(__pyproxy_getattr=Module["__pyproxy_getattr"]=wasmExports["_pyproxy_getattr"])(a0,a1,a2);var __PyObject_GetMethod=Module["__PyObject_GetMethod"]=(a0,a1,a2)=>(__PyObject_GetMethod=Module["__PyObject_GetMethod"]=wasmExports["_PyObject_GetMethod"])(a0,a1,a2);var __pyproxy_setattr=Module["__pyproxy_setattr"]=(a0,a1,a2)=>(__pyproxy_setattr=Module["__pyproxy_setattr"]=wasmExports["_pyproxy_setattr"])(a0,a1,a2);var __pyproxy_delattr=Module["__pyproxy_delattr"]=(a0,a1)=>(__pyproxy_delattr=Module["__pyproxy_delattr"]=wasmExports["_pyproxy_delattr"])(a0,a1);var __pyproxy_getitem=Module["__pyproxy_getitem"]=(a0,a1,a2,a3)=>(__pyproxy_getitem=Module["__pyproxy_getitem"]=wasmExports["_pyproxy_getitem"])(a0,a1,a2,a3);var __pyproxy_setitem=Module["__pyproxy_setitem"]=(a0,a1,a2)=>(__pyproxy_setitem=Module["__pyproxy_setitem"]=wasmExports["_pyproxy_setitem"])(a0,a1,a2);var __pyproxy_delitem=Module["__pyproxy_delitem"]=(a0,a1)=>(__pyproxy_delitem=Module["__pyproxy_delitem"]=wasmExports["_pyproxy_delitem"])(a0,a1);var __pyproxy_slice_assign=Module["__pyproxy_slice_assign"]=(a0,a1,a2,a3)=>(__pyproxy_slice_assign=Module["__pyproxy_slice_assign"]=wasmExports["_pyproxy_slice_assign"])(a0,a1,a2,a3);var _PySequence_Size=Module["_PySequence_Size"]=a0=>(_PySequence_Size=Module["_PySequence_Size"]=wasmExports["PySequence_Size"])(a0);var _PySequence_GetSlice=Module["_PySequence_GetSlice"]=(a0,a1,a2)=>(_PySequence_GetSlice=Module["_PySequence_GetSlice"]=wasmExports["PySequence_GetSlice"])(a0,a1,a2);var _PySequence_SetSlice=Module["_PySequence_SetSlice"]=(a0,a1,a2,a3)=>(_PySequence_SetSlice=Module["_PySequence_SetSlice"]=wasmExports["PySequence_SetSlice"])(a0,a1,a2,a3);var _python2js_with_depth=Module["_python2js_with_depth"]=(a0,a1,a2)=>(_python2js_with_depth=Module["_python2js_with_depth"]=wasmExports["python2js_with_depth"])(a0,a1,a2);var __pyproxy_pop=Module["__pyproxy_pop"]=(a0,a1)=>(__pyproxy_pop=Module["__pyproxy_pop"]=wasmExports["_pyproxy_pop"])(a0,a1);var __pyproxy_contains=Module["__pyproxy_contains"]=(a0,a1)=>(__pyproxy_contains=Module["__pyproxy_contains"]=wasmExports["_pyproxy_contains"])(a0,a1);var _PySequence_Contains=Module["_PySequence_Contains"]=(a0,a1)=>(_PySequence_Contains=Module["_PySequence_Contains"]=wasmExports["PySequence_Contains"])(a0,a1);var __pyproxy_ownKeys=Module["__pyproxy_ownKeys"]=a0=>(__pyproxy_ownKeys=Module["__pyproxy_ownKeys"]=wasmExports["_pyproxy_ownKeys"])(a0);var _PyObject_Dir=Module["_PyObject_Dir"]=a0=>(_PyObject_Dir=Module["_PyObject_Dir"]=wasmExports["PyObject_Dir"])(a0);var _PyList_Size=Module["_PyList_Size"]=a0=>(_PyList_Size=Module["_PyList_Size"]=wasmExports["PyList_Size"])(a0);var _PyList_GetItem=Module["_PyList_GetItem"]=(a0,a1)=>(_PyList_GetItem=Module["_PyList_GetItem"]=wasmExports["PyList_GetItem"])(a0,a1);var __pyproxy_apply=Module["__pyproxy_apply"]=(a0,a1,a2,a3,a4)=>(__pyproxy_apply=Module["__pyproxy_apply"]=wasmExports["_pyproxy_apply"])(a0,a1,a2,a3,a4);var _PyTuple_New=Module["_PyTuple_New"]=a0=>(_PyTuple_New=Module["_PyTuple_New"]=wasmExports["PyTuple_New"])(a0);var __pyproxy_apply_promising=Module["__pyproxy_apply_promising"]=(a0,a1,a2,a3,a4,a5,a6)=>(__pyproxy_apply_promising=Module["__pyproxy_apply_promising"]=wasmExports["_pyproxy_apply_promising"])(a0,a1,a2,a3,a4,a5,a6);var _get_cframe=Module["_get_cframe"]=()=>(_get_cframe=Module["_get_cframe"]=wasmExports["get_cframe"])();var _exit_cframe=Module["_exit_cframe"]=a0=>(_exit_cframe=Module["_exit_cframe"]=wasmExports["exit_cframe"])(a0);var __iscoroutinefunction=Module["__iscoroutinefunction"]=a0=>(__iscoroutinefunction=Module["__iscoroutinefunction"]=wasmExports["_iscoroutinefunction"])(a0);var __pyproxy_iter_next=Module["__pyproxy_iter_next"]=(a0,a1,a2)=>(__pyproxy_iter_next=Module["__pyproxy_iter_next"]=wasmExports["_pyproxy_iter_next"])(a0,a1,a2);var _PyIter_Next=Module["_PyIter_Next"]=a0=>(_PyIter_Next=Module["_PyIter_Next"]=wasmExports["PyIter_Next"])(a0);var __pyproxyGen_Send=Module["__pyproxyGen_Send"]=(a0,a1)=>(__pyproxyGen_Send=Module["__pyproxyGen_Send"]=wasmExports["_pyproxyGen_Send"])(a0,a1);var _PyIter_Send=Module["_PyIter_Send"]=(a0,a1,a2)=>(_PyIter_Send=Module["_PyIter_Send"]=wasmExports["PyIter_Send"])(a0,a1,a2);var __pyproxyGen_return=Module["__pyproxyGen_return"]=(a0,a1)=>(__pyproxyGen_return=Module["__pyproxyGen_return"]=wasmExports["_pyproxyGen_return"])(a0,a1);var __PyGen_FetchStopIterationValue=Module["__PyGen_FetchStopIterationValue"]=a0=>(__PyGen_FetchStopIterationValue=Module["__PyGen_FetchStopIterationValue"]=wasmExports["_PyGen_FetchStopIterationValue"])(a0);var __pyproxyGen_throw=Module["__pyproxyGen_throw"]=(a0,a1)=>(__pyproxyGen_throw=Module["__pyproxyGen_throw"]=wasmExports["_pyproxyGen_throw"])(a0,a1);var __pyproxyGen_asend=Module["__pyproxyGen_asend"]=(a0,a1)=>(__pyproxyGen_asend=Module["__pyproxyGen_asend"]=wasmExports["_pyproxyGen_asend"])(a0,a1);var __pyproxyGen_areturn=Module["__pyproxyGen_areturn"]=a0=>(__pyproxyGen_areturn=Module["__pyproxyGen_areturn"]=wasmExports["_pyproxyGen_areturn"])(a0);var __pyproxyGen_athrow=Module["__pyproxyGen_athrow"]=(a0,a1)=>(__pyproxyGen_athrow=Module["__pyproxyGen_athrow"]=wasmExports["_pyproxyGen_athrow"])(a0,a1);var __pyproxy_aiter_next=Module["__pyproxy_aiter_next"]=a0=>(__pyproxy_aiter_next=Module["__pyproxy_aiter_next"]=wasmExports["_pyproxy_aiter_next"])(a0);var _FutureDoneCallback_call_resolve=Module["_FutureDoneCallback_call_resolve"]=(a0,a1)=>(_FutureDoneCallback_call_resolve=Module["_FutureDoneCallback_call_resolve"]=wasmExports["FutureDoneCallback_call_resolve"])(a0,a1);var _FutureDoneCallback_call_reject=Module["_FutureDoneCallback_call_reject"]=a0=>(_FutureDoneCallback_call_reject=Module["_FutureDoneCallback_call_reject"]=wasmExports["FutureDoneCallback_call_reject"])(a0);var _FutureDoneCallback_call=Module["_FutureDoneCallback_call"]=(a0,a1,a2)=>(_FutureDoneCallback_call=Module["_FutureDoneCallback_call"]=wasmExports["FutureDoneCallback_call"])(a0,a1,a2);var _PyArg_UnpackTuple=Module["_PyArg_UnpackTuple"]=(a0,a1,a2,a3,a4)=>(_PyArg_UnpackTuple=Module["_PyArg_UnpackTuple"]=wasmExports["PyArg_UnpackTuple"])(a0,a1,a2,a3,a4);var __pyproxy_ensure_future=Module["__pyproxy_ensure_future"]=(a0,a1,a2)=>(__pyproxy_ensure_future=Module["__pyproxy_ensure_future"]=wasmExports["_pyproxy_ensure_future"])(a0,a1,a2);var __pyproxy_get_buffer=Module["__pyproxy_get_buffer"]=a0=>(__pyproxy_get_buffer=Module["__pyproxy_get_buffer"]=wasmExports["_pyproxy_get_buffer"])(a0);var _PyBuffer_FillContiguousStrides=Module["_PyBuffer_FillContiguousStrides"]=(a0,a1,a2,a3,a4)=>(_PyBuffer_FillContiguousStrides=Module["_PyBuffer_FillContiguousStrides"]=wasmExports["PyBuffer_FillContiguousStrides"])(a0,a1,a2,a3,a4);var _PyBuffer_IsContiguous=Module["_PyBuffer_IsContiguous"]=(a0,a1)=>(_PyBuffer_IsContiguous=Module["_PyBuffer_IsContiguous"]=wasmExports["PyBuffer_IsContiguous"])(a0,a1);var _create_promise_handles_result_helper=Module["_create_promise_handles_result_helper"]=(a0,a1,a2)=>(_create_promise_handles_result_helper=Module["_create_promise_handles_result_helper"]=wasmExports["create_promise_handles_result_helper"])(a0,a1,a2);var __python2js_buffer=Module["__python2js_buffer"]=a0=>(__python2js_buffer=Module["__python2js_buffer"]=wasmExports["_python2js_buffer"])(a0);var _jslib_init_buffers=Module["_jslib_init_buffers"]=()=>(_jslib_init_buffers=Module["_jslib_init_buffers"]=wasmExports["jslib_init_buffers"])();var _JsRef_pop=Module["_JsRef_pop"]=a0=>(_JsRef_pop=Module["_JsRef_pop"]=wasmExports["JsRef_pop"])(a0);var _JsrString_FromId=Module["_JsrString_FromId"]=a0=>(_JsrString_FromId=Module["_JsrString_FromId"]=wasmExports["JsrString_FromId"])(a0);var _hiwire_intern=Module["_hiwire_intern"]=a0=>(_hiwire_intern=Module["_hiwire_intern"]=wasmExports["hiwire_intern"])(a0);var __python2js=Module["__python2js"]=(a0,a1)=>(__python2js=Module["__python2js"]=wasmExports["_python2js"])(a0,a1);var _PySequence_GetItem=Module["_PySequence_GetItem"]=(a0,a1)=>(_PySequence_GetItem=Module["_PySequence_GetItem"]=wasmExports["PySequence_GetItem"])(a0,a1);var _PyObject_CheckBuffer=Module["_PyObject_CheckBuffer"]=a0=>(_PyObject_CheckBuffer=Module["_PyObject_CheckBuffer"]=wasmExports["PyObject_CheckBuffer"])(a0);var _PyFloat_AsDouble=Module["_PyFloat_AsDouble"]=a0=>(_PyFloat_AsDouble=Module["_PyFloat_AsDouble"]=wasmExports["PyFloat_AsDouble"])(a0);var _python2js__default_converter=Module["_python2js__default_converter"]=(a0,a1)=>(_python2js__default_converter=Module["_python2js__default_converter"]=wasmExports["python2js__default_converter"])(a0,a1);var _python2js__eager_converter=Module["_python2js__eager_converter"]=(a0,a1)=>(_python2js__eager_converter=Module["_python2js__eager_converter"]=wasmExports["python2js__eager_converter"])(a0,a1);var _PyLong_AsLongAndOverflow=Module["_PyLong_AsLongAndOverflow"]=(a0,a1)=>(_PyLong_AsLongAndOverflow=Module["_PyLong_AsLongAndOverflow"]=wasmExports["PyLong_AsLongAndOverflow"])(a0,a1);var __PyLong_NumBits=Module["__PyLong_NumBits"]=a0=>(__PyLong_NumBits=Module["__PyLong_NumBits"]=wasmExports["_PyLong_NumBits"])(a0);var __PyLong_AsByteArray=Module["__PyLong_AsByteArray"]=(a0,a1,a2,a3,a4)=>(__PyLong_AsByteArray=Module["__PyLong_AsByteArray"]=wasmExports["_PyLong_AsByteArray"])(a0,a1,a2,a3,a4);var _py_version_minor=Module["_py_version_minor"]=()=>(_py_version_minor=Module["_py_version_minor"]=wasmExports["py_version_minor"])();var _py_version_micro=Module["_py_version_micro"]=()=>(_py_version_micro=Module["_py_version_micro"]=wasmExports["py_version_micro"])();var _saveAsyncioState=Module["_saveAsyncioState"]=a0=>(_saveAsyncioState=Module["_saveAsyncioState"]=wasmExports["saveAsyncioState"])(a0);var _PyObject_Hash=Module["_PyObject_Hash"]=a0=>(_PyObject_Hash=Module["_PyObject_Hash"]=wasmExports["PyObject_Hash"])(a0);var __PyDict_GetItem_KnownHash=Module["__PyDict_GetItem_KnownHash"]=(a0,a1,a2)=>(__PyDict_GetItem_KnownHash=Module["__PyDict_GetItem_KnownHash"]=wasmExports["_PyDict_GetItem_KnownHash"])(a0,a1,a2);var _restoreAsyncioState=Module["_restoreAsyncioState"]=a0=>(_restoreAsyncioState=Module["_restoreAsyncioState"]=wasmExports["restoreAsyncioState"])(a0);var _captureThreadState=Module["_captureThreadState"]=()=>(_captureThreadState=Module["_captureThreadState"]=wasmExports["captureThreadState"])();var _PyInterpreterState_Get=Module["_PyInterpreterState_Get"]=()=>(_PyInterpreterState_Get=Module["_PyInterpreterState_Get"]=wasmExports["PyInterpreterState_Get"])();var _PyThreadState_New=Module["_PyThreadState_New"]=a0=>(_PyThreadState_New=Module["_PyThreadState_New"]=wasmExports["PyThreadState_New"])(a0);var _restoreThreadState=Module["_restoreThreadState"]=a0=>(_restoreThreadState=Module["_restoreThreadState"]=wasmExports["restoreThreadState"])(a0);var _PyThreadState_Delete=Module["_PyThreadState_Delete"]=a0=>(_PyThreadState_Delete=Module["_PyThreadState_Delete"]=wasmExports["PyThreadState_Delete"])(a0);var _PyThreadState_Get=Module["_PyThreadState_Get"]=()=>(_PyThreadState_Get=Module["_PyThreadState_Get"]=wasmExports["PyThreadState_Get"])();var _restore_cframe=Module["_restore_cframe"]=a0=>(_restore_cframe=Module["_restore_cframe"]=wasmExports["restore_cframe"])(a0);var _PyObject_GetArenaAllocator=Module["_PyObject_GetArenaAllocator"]=a0=>(_PyObject_GetArenaAllocator=Module["_PyObject_GetArenaAllocator"]=wasmExports["PyObject_GetArenaAllocator"])(a0);var _print_stdout=Module["_print_stdout"]=a0=>(_print_stdout=Module["_print_stdout"]=wasmExports["print_stdout"])(a0);var _fiprintf=Module["_fiprintf"]=(a0,a1,a2)=>(_fiprintf=Module["_fiprintf"]=wasmExports["fiprintf"])(a0,a1,a2);var _print_stderr=Module["_print_stderr"]=a0=>(_print_stderr=Module["_print_stderr"]=wasmExports["print_stderr"])(a0);var _main=Module["_main"]=(a0,a1)=>(_main=Module["_main"]=wasmExports["__main_argc_argv"])(a0,a1);var _PyImport_AppendInittab=Module["_PyImport_AppendInittab"]=(a0,a1)=>(_PyImport_AppendInittab=Module["_PyImport_AppendInittab"]=wasmExports["PyImport_AppendInittab"])(a0,a1);var _PyPreConfig_InitPythonConfig=Module["_PyPreConfig_InitPythonConfig"]=a0=>(_PyPreConfig_InitPythonConfig=Module["_PyPreConfig_InitPythonConfig"]=wasmExports["PyPreConfig_InitPythonConfig"])(a0);var _Py_PreInitializeFromBytesArgs=Module["_Py_PreInitializeFromBytesArgs"]=(a0,a1,a2,a3)=>(_Py_PreInitializeFromBytesArgs=Module["_Py_PreInitializeFromBytesArgs"]=wasmExports["Py_PreInitializeFromBytesArgs"])(a0,a1,a2,a3);var _PyStatus_Exception=Module["_PyStatus_Exception"]=a0=>(_PyStatus_Exception=Module["_PyStatus_Exception"]=wasmExports["PyStatus_Exception"])(a0);var _PyConfig_InitPythonConfig=Module["_PyConfig_InitPythonConfig"]=a0=>(_PyConfig_InitPythonConfig=Module["_PyConfig_InitPythonConfig"]=wasmExports["PyConfig_InitPythonConfig"])(a0);var _PyConfig_SetBytesArgv=Module["_PyConfig_SetBytesArgv"]=(a0,a1,a2,a3)=>(_PyConfig_SetBytesArgv=Module["_PyConfig_SetBytesArgv"]=wasmExports["PyConfig_SetBytesArgv"])(a0,a1,a2,a3);var _PyConfig_SetBytesString=Module["_PyConfig_SetBytesString"]=(a0,a1,a2,a3)=>(_PyConfig_SetBytesString=Module["_PyConfig_SetBytesString"]=wasmExports["PyConfig_SetBytesString"])(a0,a1,a2,a3);var _Py_InitializeFromConfig=Module["_Py_InitializeFromConfig"]=(a0,a1)=>(_Py_InitializeFromConfig=Module["_Py_InitializeFromConfig"]=wasmExports["Py_InitializeFromConfig"])(a0,a1);var _PyConfig_Clear=Module["_PyConfig_Clear"]=a0=>(_PyConfig_Clear=Module["_PyConfig_Clear"]=wasmExports["PyConfig_Clear"])(a0);var _Py_ExitStatusException=Module["_Py_ExitStatusException"]=a0=>(_Py_ExitStatusException=Module["_Py_ExitStatusException"]=wasmExports["Py_ExitStatusException"])(a0);var _run_main=Module["_run_main"]=()=>(_run_main=Module["_run_main"]=wasmExports["run_main"])();var _run_main_promising=Module["_run_main_promising"]=a0=>(_run_main_promising=Module["_run_main_promising"]=wasmExports["run_main_promising"])(a0);var _Py_GetBuildInfo=Module["_Py_GetBuildInfo"]=()=>(_Py_GetBuildInfo=Module["_Py_GetBuildInfo"]=wasmExports["Py_GetBuildInfo"])();var _PyOS_snprintf=Module["_PyOS_snprintf"]=(a0,a1,a2,a3)=>(_PyOS_snprintf=Module["_PyOS_snprintf"]=wasmExports["PyOS_snprintf"])(a0,a1,a2,a3);var __Py_gitversion=Module["__Py_gitversion"]=()=>(__Py_gitversion=Module["__Py_gitversion"]=wasmExports["_Py_gitversion"])();var __Py_gitidentifier=Module["__Py_gitidentifier"]=()=>(__Py_gitidentifier=Module["__Py_gitidentifier"]=wasmExports["_Py_gitidentifier"])();var __PyToken_OneChar=Module["__PyToken_OneChar"]=a0=>(__PyToken_OneChar=Module["__PyToken_OneChar"]=wasmExports["_PyToken_OneChar"])(a0);var __PyToken_TwoChars=Module["__PyToken_TwoChars"]=(a0,a1)=>(__PyToken_TwoChars=Module["__PyToken_TwoChars"]=wasmExports["_PyToken_TwoChars"])(a0,a1);var __PyToken_ThreeChars=Module["__PyToken_ThreeChars"]=(a0,a1,a2)=>(__PyToken_ThreeChars=Module["__PyToken_ThreeChars"]=wasmExports["_PyToken_ThreeChars"])(a0,a1,a2);var _strlen=Module["_strlen"]=a0=>(_strlen=Module["_strlen"]=wasmExports["strlen"])(a0);var _PyUnicode_DecodeUTF8=Module["_PyUnicode_DecodeUTF8"]=(a0,a1,a2)=>(_PyUnicode_DecodeUTF8=Module["_PyUnicode_DecodeUTF8"]=wasmExports["PyUnicode_DecodeUTF8"])(a0,a1,a2);var _PyUnicode_Substring=Module["_PyUnicode_Substring"]=(a0,a1,a2)=>(_PyUnicode_Substring=Module["_PyUnicode_Substring"]=wasmExports["PyUnicode_Substring"])(a0,a1,a2);var __PyImport_GetModuleAttrString=Module["__PyImport_GetModuleAttrString"]=(a0,a1)=>(__PyImport_GetModuleAttrString=Module["__PyImport_GetModuleAttrString"]=wasmExports["_PyImport_GetModuleAttrString"])(a0,a1);var __PyUnicode_EqualToASCIIString=Module["__PyUnicode_EqualToASCIIString"]=(a0,a1)=>(__PyUnicode_EqualToASCIIString=Module["__PyUnicode_EqualToASCIIString"]=wasmExports["_PyUnicode_EqualToASCIIString"])(a0,a1);var __PyArena_Malloc=Module["__PyArena_Malloc"]=(a0,a1)=>(__PyArena_Malloc=Module["__PyArena_Malloc"]=wasmExports["_PyArena_Malloc"])(a0,a1);var _strncpy=Module["_strncpy"]=(a0,a1,a2)=>(_strncpy=Module["_strncpy"]=wasmExports["strncpy"])(a0,a1,a2);var _PyMem_Realloc=Module["_PyMem_Realloc"]=(a0,a1)=>(_PyMem_Realloc=Module["_PyMem_Realloc"]=wasmExports["PyMem_Realloc"])(a0,a1);var _PyMem_Calloc=Module["_PyMem_Calloc"]=(a0,a1)=>(_PyMem_Calloc=Module["_PyMem_Calloc"]=wasmExports["PyMem_Calloc"])(a0,a1);var __PyArena_AddPyObject=Module["__PyArena_AddPyObject"]=(a0,a1)=>(__PyArena_AddPyObject=Module["__PyArena_AddPyObject"]=wasmExports["_PyArena_AddPyObject"])(a0,a1);var _PyBytes_AsString=Module["_PyBytes_AsString"]=a0=>(_PyBytes_AsString=Module["_PyBytes_AsString"]=wasmExports["PyBytes_AsString"])(a0);var _PyUnicode_InternFromString=Module["_PyUnicode_InternFromString"]=a0=>(_PyUnicode_InternFromString=Module["_PyUnicode_InternFromString"]=wasmExports["PyUnicode_InternFromString"])(a0);var __PyObject_FastCall=Module["__PyObject_FastCall"]=(a0,a1,a2)=>(__PyObject_FastCall=Module["__PyObject_FastCall"]=wasmExports["_PyObject_FastCall"])(a0,a1,a2);var __PyType_Name=Module["__PyType_Name"]=a0=>(__PyType_Name=Module["__PyType_Name"]=wasmExports["_PyType_Name"])(a0);var __PyUnicode_InternImmortal=Module["__PyUnicode_InternImmortal"]=(a0,a1)=>(__PyUnicode_InternImmortal=Module["__PyUnicode_InternImmortal"]=wasmExports["_PyUnicode_InternImmortal"])(a0,a1);var _PyBytes_AsStringAndSize=Module["_PyBytes_AsStringAndSize"]=(a0,a1,a2)=>(_PyBytes_AsStringAndSize=Module["_PyBytes_AsStringAndSize"]=wasmExports["PyBytes_AsStringAndSize"])(a0,a1,a2);var _strchr=Module["_strchr"]=(a0,a1)=>(_strchr=Module["_strchr"]=wasmExports["strchr"])(a0,a1);var _PyUnicode_CompareWithASCIIString=Module["_PyUnicode_CompareWithASCIIString"]=(a0,a1)=>(_PyUnicode_CompareWithASCIIString=Module["_PyUnicode_CompareWithASCIIString"]=wasmExports["PyUnicode_CompareWithASCIIString"])(a0,a1);var ___errno_location=()=>(___errno_location=wasmExports["__errno_location"])();var _PyOS_strtoul=Module["_PyOS_strtoul"]=(a0,a1,a2)=>(_PyOS_strtoul=Module["_PyOS_strtoul"]=wasmExports["PyOS_strtoul"])(a0,a1,a2);var _PyLong_FromString=Module["_PyLong_FromString"]=(a0,a1,a2)=>(_PyLong_FromString=Module["_PyLong_FromString"]=wasmExports["PyLong_FromString"])(a0,a1,a2);var _PyOS_strtol=Module["_PyOS_strtol"]=(a0,a1,a2)=>(_PyOS_strtol=Module["_PyOS_strtol"]=wasmExports["PyOS_strtol"])(a0,a1,a2);var _PyOS_string_to_double=Module["_PyOS_string_to_double"]=(a0,a1,a2)=>(_PyOS_string_to_double=Module["_PyOS_string_to_double"]=wasmExports["PyOS_string_to_double"])(a0,a1,a2);var _PyComplex_FromCComplex=Module["_PyComplex_FromCComplex"]=a0=>(_PyComplex_FromCComplex=Module["_PyComplex_FromCComplex"]=wasmExports["PyComplex_FromCComplex"])(a0);var _PyFloat_FromDouble=Module["_PyFloat_FromDouble"]=a0=>(_PyFloat_FromDouble=Module["_PyFloat_FromDouble"]=wasmExports["PyFloat_FromDouble"])(a0);var _Py_BuildValue=Module["_Py_BuildValue"]=(a0,a1)=>(_Py_BuildValue=Module["_Py_BuildValue"]=wasmExports["Py_BuildValue"])(a0,a1);var _PyUnicode_FromFormatV=Module["_PyUnicode_FromFormatV"]=(a0,a1)=>(_PyUnicode_FromFormatV=Module["_PyUnicode_FromFormatV"]=wasmExports["PyUnicode_FromFormatV"])(a0,a1);var __PyErr_ProgramDecodedTextObject=Module["__PyErr_ProgramDecodedTextObject"]=(a0,a1,a2)=>(__PyErr_ProgramDecodedTextObject=Module["__PyErr_ProgramDecodedTextObject"]=wasmExports["_PyErr_ProgramDecodedTextObject"])(a0,a1,a2);var _PyUnicode_FromStringAndSize=Module["_PyUnicode_FromStringAndSize"]=(a0,a1)=>(_PyUnicode_FromStringAndSize=Module["_PyUnicode_FromStringAndSize"]=wasmExports["PyUnicode_FromStringAndSize"])(a0,a1);var _strcpy=Module["_strcpy"]=(a0,a1)=>(_strcpy=Module["_strcpy"]=wasmExports["strcpy"])(a0,a1);var __PyUnicode_InternMortal=Module["__PyUnicode_InternMortal"]=(a0,a1)=>(__PyUnicode_InternMortal=Module["__PyUnicode_InternMortal"]=wasmExports["_PyUnicode_InternMortal"])(a0,a1);var _PyUnicode_GetLength=Module["_PyUnicode_GetLength"]=a0=>(_PyUnicode_GetLength=Module["_PyUnicode_GetLength"]=wasmExports["PyUnicode_GetLength"])(a0);var _PyBytes_FromString=Module["_PyBytes_FromString"]=a0=>(_PyBytes_FromString=Module["_PyBytes_FromString"]=wasmExports["PyBytes_FromString"])(a0);var _PyBytes_Concat=Module["_PyBytes_Concat"]=(a0,a1)=>(_PyBytes_Concat=Module["_PyBytes_Concat"]=wasmExports["PyBytes_Concat"])(a0,a1);var __PyUnicodeWriter_Init=Module["__PyUnicodeWriter_Init"]=a0=>(__PyUnicodeWriter_Init=Module["__PyUnicodeWriter_Init"]=wasmExports["_PyUnicodeWriter_Init"])(a0);var __PyUnicodeWriter_WriteStr=Module["__PyUnicodeWriter_WriteStr"]=(a0,a1)=>(__PyUnicodeWriter_WriteStr=Module["__PyUnicodeWriter_WriteStr"]=wasmExports["_PyUnicodeWriter_WriteStr"])(a0,a1);var __PyUnicodeWriter_Dealloc=Module["__PyUnicodeWriter_Dealloc"]=a0=>(__PyUnicodeWriter_Dealloc=Module["__PyUnicodeWriter_Dealloc"]=wasmExports["_PyUnicodeWriter_Dealloc"])(a0);var __PyUnicodeWriter_Finish=Module["__PyUnicodeWriter_Finish"]=a0=>(__PyUnicodeWriter_Finish=Module["__PyUnicodeWriter_Finish"]=wasmExports["_PyUnicodeWriter_Finish"])(a0);var _strpbrk=Module["_strpbrk"]=(a0,a1)=>(_strpbrk=Module["_strpbrk"]=wasmExports["strpbrk"])(a0,a1);var _PyUnicode_DecodeUTF8Stateful=Module["_PyUnicode_DecodeUTF8Stateful"]=(a0,a1,a2,a3)=>(_PyUnicode_DecodeUTF8Stateful=Module["_PyUnicode_DecodeUTF8Stateful"]=wasmExports["PyUnicode_DecodeUTF8Stateful"])(a0,a1,a2,a3);var _siprintf=Module["_siprintf"]=(a0,a1,a2)=>(_siprintf=Module["_siprintf"]=wasmExports["siprintf"])(a0,a1,a2);var __PyUnicode_DecodeUnicodeEscapeInternal=Module["__PyUnicode_DecodeUnicodeEscapeInternal"]=(a0,a1,a2,a3,a4)=>(__PyUnicode_DecodeUnicodeEscapeInternal=Module["__PyUnicode_DecodeUnicodeEscapeInternal"]=wasmExports["_PyUnicode_DecodeUnicodeEscapeInternal"])(a0,a1,a2,a3,a4);var __PyErr_BadInternalCall=Module["__PyErr_BadInternalCall"]=(a0,a1)=>(__PyErr_BadInternalCall=Module["__PyErr_BadInternalCall"]=wasmExports["_PyErr_BadInternalCall"])(a0,a1);var __PyBytes_DecodeEscape=Module["__PyBytes_DecodeEscape"]=(a0,a1,a2,a3)=>(__PyBytes_DecodeEscape=Module["__PyBytes_DecodeEscape"]=wasmExports["_PyBytes_DecodeEscape"])(a0,a1,a2,a3);var _PyErr_WarnExplicitObject=Module["_PyErr_WarnExplicitObject"]=(a0,a1,a2,a3,a4,a5)=>(_PyErr_WarnExplicitObject=Module["_PyErr_WarnExplicitObject"]=wasmExports["PyErr_WarnExplicitObject"])(a0,a1,a2,a3,a4,a5);var _PySys_Audit=Module["_PySys_Audit"]=(a0,a1,a2)=>(_PySys_Audit=Module["_PySys_Audit"]=wasmExports["PySys_Audit"])(a0,a1,a2);var _fflush=Module["_fflush"]=a0=>(_fflush=Module["_fflush"]=wasmExports["fflush"])(a0);var _fputs=Module["_fputs"]=(a0,a1)=>(_fputs=Module["_fputs"]=wasmExports["fputs"])(a0,a1);var _PyMem_RawFree=Module["_PyMem_RawFree"]=a0=>(_PyMem_RawFree=Module["_PyMem_RawFree"]=wasmExports["PyMem_RawFree"])(a0);var _PyEval_RestoreThread=Module["_PyEval_RestoreThread"]=a0=>(_PyEval_RestoreThread=Module["_PyEval_RestoreThread"]=wasmExports["PyEval_RestoreThread"])(a0);var _PyEval_SaveThread=Module["_PyEval_SaveThread"]=()=>(_PyEval_SaveThread=Module["_PyEval_SaveThread"]=wasmExports["PyEval_SaveThread"])();var _PyMem_RawRealloc=Module["_PyMem_RawRealloc"]=(a0,a1)=>(_PyMem_RawRealloc=Module["_PyMem_RawRealloc"]=wasmExports["PyMem_RawRealloc"])(a0,a1);var _clearerr=Module["_clearerr"]=a0=>(_clearerr=Module["_clearerr"]=wasmExports["clearerr"])(a0);var _fgets=Module["_fgets"]=(a0,a1,a2)=>(_fgets=Module["_fgets"]=wasmExports["fgets"])(a0,a1,a2);var _feof=Module["_feof"]=a0=>(_feof=Module["_feof"]=wasmExports["feof"])(a0);var __PyOS_InterruptOccurred=Module["__PyOS_InterruptOccurred"]=a0=>(__PyOS_InterruptOccurred=Module["__PyOS_InterruptOccurred"]=wasmExports["_PyOS_InterruptOccurred"])(a0);var _PyErr_CheckSignals=Module["_PyErr_CheckSignals"]=()=>(_PyErr_CheckSignals=Module["_PyErr_CheckSignals"]=wasmExports["PyErr_CheckSignals"])();var _PyOS_Readline=Module["_PyOS_Readline"]=(a0,a1,a2)=>(_PyOS_Readline=Module["_PyOS_Readline"]=wasmExports["PyOS_Readline"])(a0,a1,a2);var _PyThread_allocate_lock=Module["_PyThread_allocate_lock"]=()=>(_PyThread_allocate_lock=Module["_PyThread_allocate_lock"]=wasmExports["PyThread_allocate_lock"])();var _PyThread_acquire_lock=Module["_PyThread_acquire_lock"]=(a0,a1)=>(_PyThread_acquire_lock=Module["_PyThread_acquire_lock"]=wasmExports["PyThread_acquire_lock"])(a0,a1);var _isatty=Module["_isatty"]=a0=>(_isatty=Module["_isatty"]=wasmExports["isatty"])(a0);var _PyThread_release_lock=Module["_PyThread_release_lock"]=a0=>(_PyThread_release_lock=Module["_PyThread_release_lock"]=wasmExports["PyThread_release_lock"])(a0);var _PyUnicode_Decode=Module["_PyUnicode_Decode"]=(a0,a1,a2,a3)=>(_PyUnicode_Decode=Module["_PyUnicode_Decode"]=wasmExports["PyUnicode_Decode"])(a0,a1,a2,a3);var _PyUnicode_AsUTF8String=Module["_PyUnicode_AsUTF8String"]=a0=>(_PyUnicode_AsUTF8String=Module["_PyUnicode_AsUTF8String"]=wasmExports["PyUnicode_AsUTF8String"])(a0);var __Py_FatalErrorFunc=Module["__Py_FatalErrorFunc"]=(a0,a1)=>(__Py_FatalErrorFunc=Module["__Py_FatalErrorFunc"]=wasmExports["_Py_FatalErrorFunc"])(a0,a1);var __Py_dup=Module["__Py_dup"]=a0=>(__Py_dup=Module["__Py_dup"]=wasmExports["_Py_dup"])(a0);var _fdopen=Module["_fdopen"]=(a0,a1)=>(_fdopen=Module["_fdopen"]=wasmExports["fdopen"])(a0,a1);var _fclose=Module["_fclose"]=a0=>(_fclose=Module["_fclose"]=wasmExports["fclose"])(a0);var _memcmp=Module["_memcmp"]=(a0,a1,a2)=>(_memcmp=Module["_memcmp"]=wasmExports["memcmp"])(a0,a1,a2);var _tolower=Module["_tolower"]=a0=>(_tolower=Module["_tolower"]=wasmExports["tolower"])(a0);var __PyUnicode_ScanIdentifier=Module["__PyUnicode_ScanIdentifier"]=a0=>(__PyUnicode_ScanIdentifier=Module["__PyUnicode_ScanIdentifier"]=wasmExports["_PyUnicode_ScanIdentifier"])(a0);var __PyUnicode_IsPrintable=Module["__PyUnicode_IsPrintable"]=a0=>(__PyUnicode_IsPrintable=Module["__PyUnicode_IsPrintable"]=wasmExports["_PyUnicode_IsPrintable"])(a0);var _isxdigit=Module["_isxdigit"]=a0=>(_isxdigit=Module["_isxdigit"]=wasmExports["isxdigit"])(a0);var _PyObject_CallNoArgs=Module["_PyObject_CallNoArgs"]=a0=>(_PyObject_CallNoArgs=Module["_PyObject_CallNoArgs"]=wasmExports["PyObject_CallNoArgs"])(a0);var _getc=Module["_getc"]=a0=>(_getc=Module["_getc"]=wasmExports["getc"])(a0);var _ungetc=Module["_ungetc"]=(a0,a1)=>(_ungetc=Module["_ungetc"]=wasmExports["ungetc"])(a0,a1);var __Py_UniversalNewlineFgetsWithSize=Module["__Py_UniversalNewlineFgetsWithSize"]=(a0,a1,a2,a3,a4)=>(__Py_UniversalNewlineFgetsWithSize=Module["__Py_UniversalNewlineFgetsWithSize"]=wasmExports["_Py_UniversalNewlineFgetsWithSize"])(a0,a1,a2,a3,a4);var _memchr=Module["_memchr"]=(a0,a1,a2)=>(_memchr=Module["_memchr"]=wasmExports["memchr"])(a0,a1,a2);var _PyObject_Malloc=Module["_PyObject_Malloc"]=a0=>(_PyObject_Malloc=Module["_PyObject_Malloc"]=wasmExports["PyObject_Malloc"])(a0);var _PyObject_Free=Module["_PyObject_Free"]=a0=>(_PyObject_Free=Module["_PyObject_Free"]=wasmExports["PyObject_Free"])(a0);var _ftell=Module["_ftell"]=a0=>(_ftell=Module["_ftell"]=wasmExports["ftell"])(a0);var _lseek=Module["_lseek"]=(a0,a1,a2)=>(_lseek=Module["_lseek"]=wasmExports["lseek"])(a0,a1,a2);var _PyErr_SetFromErrnoWithFilename=Module["_PyErr_SetFromErrnoWithFilename"]=(a0,a1)=>(_PyErr_SetFromErrnoWithFilename=Module["_PyErr_SetFromErrnoWithFilename"]=wasmExports["PyErr_SetFromErrnoWithFilename"])(a0,a1);var __PyObject_CallFunction_SizeT=Module["__PyObject_CallFunction_SizeT"]=(a0,a1,a2)=>(__PyObject_CallFunction_SizeT=Module["__PyObject_CallFunction_SizeT"]=wasmExports["_PyObject_CallFunction_SizeT"])(a0,a1,a2);var _PyObject_GetAttr=Module["_PyObject_GetAttr"]=(a0,a1)=>(_PyObject_GetAttr=Module["_PyObject_GetAttr"]=wasmExports["PyObject_GetAttr"])(a0,a1);var __PyObject_MakeTpCall=Module["__PyObject_MakeTpCall"]=(a0,a1,a2,a3,a4)=>(__PyObject_MakeTpCall=Module["__PyObject_MakeTpCall"]=wasmExports["_PyObject_MakeTpCall"])(a0,a1,a2,a3,a4);var __Py_CheckFunctionResult=Module["__Py_CheckFunctionResult"]=(a0,a1,a2,a3)=>(__Py_CheckFunctionResult=Module["__Py_CheckFunctionResult"]=wasmExports["_Py_CheckFunctionResult"])(a0,a1,a2,a3);var _strcspn=Module["_strcspn"]=(a0,a1)=>(_strcspn=Module["_strcspn"]=wasmExports["strcspn"])(a0,a1);var __Py_BuildValue_SizeT=Module["__Py_BuildValue_SizeT"]=(a0,a1)=>(__Py_BuildValue_SizeT=Module["__Py_BuildValue_SizeT"]=wasmExports["_Py_BuildValue_SizeT"])(a0,a1);var _PyObject_Type=Module["_PyObject_Type"]=a0=>(_PyObject_Type=Module["_PyObject_Type"]=wasmExports["PyObject_Type"])(a0);var __PyErr_SetString=Module["__PyErr_SetString"]=(a0,a1,a2)=>(__PyErr_SetString=Module["__PyErr_SetString"]=wasmExports["_PyErr_SetString"])(a0,a1,a2);var _PyObject_Size=Module["_PyObject_Size"]=a0=>(_PyObject_Size=Module["_PyObject_Size"]=wasmExports["PyObject_Size"])(a0);var _PyMapping_Size=Module["_PyMapping_Size"]=a0=>(_PyMapping_Size=Module["_PyMapping_Size"]=wasmExports["PyMapping_Size"])(a0);var _PyObject_Length=Module["_PyObject_Length"]=a0=>(_PyObject_Length=Module["_PyObject_Length"]=wasmExports["PyObject_Length"])(a0);var __PyObject_HasLen=Module["__PyObject_HasLen"]=a0=>(__PyObject_HasLen=Module["__PyObject_HasLen"]=wasmExports["_PyObject_HasLen"])(a0);var _PyObject_LengthHint=Module["_PyObject_LengthHint"]=(a0,a1)=>(_PyObject_LengthHint=Module["_PyObject_LengthHint"]=wasmExports["PyObject_LengthHint"])(a0,a1);var __PyErr_ExceptionMatches=Module["__PyErr_ExceptionMatches"]=(a0,a1)=>(__PyErr_ExceptionMatches=Module["__PyErr_ExceptionMatches"]=wasmExports["_PyErr_ExceptionMatches"])(a0,a1);var __PyErr_Clear=Module["__PyErr_Clear"]=a0=>(__PyErr_Clear=Module["__PyErr_Clear"]=wasmExports["_PyErr_Clear"])(a0);var __PyObject_LookupSpecial=Module["__PyObject_LookupSpecial"]=(a0,a1)=>(__PyObject_LookupSpecial=Module["__PyObject_LookupSpecial"]=wasmExports["_PyObject_LookupSpecial"])(a0,a1);var _Py_GenericAlias=Module["_Py_GenericAlias"]=(a0,a1)=>(_Py_GenericAlias=Module["_Py_GenericAlias"]=wasmExports["Py_GenericAlias"])(a0,a1);var __PyObject_LookupAttr=Module["__PyObject_LookupAttr"]=(a0,a1,a2)=>(__PyObject_LookupAttr=Module["__PyObject_LookupAttr"]=wasmExports["_PyObject_LookupAttr"])(a0,a1,a2);var __PyErr_Format=Module["__PyErr_Format"]=(a0,a1,a2,a3)=>(__PyErr_Format=Module["__PyErr_Format"]=wasmExports["_PyErr_Format"])(a0,a1,a2,a3);var _PySequence_SetItem=Module["_PySequence_SetItem"]=(a0,a1,a2)=>(_PySequence_SetItem=Module["_PySequence_SetItem"]=wasmExports["PySequence_SetItem"])(a0,a1,a2);var _PySequence_DelItem=Module["_PySequence_DelItem"]=(a0,a1)=>(_PySequence_DelItem=Module["_PySequence_DelItem"]=wasmExports["PySequence_DelItem"])(a0,a1);var _PyObject_DelItemString=Module["_PyObject_DelItemString"]=(a0,a1)=>(_PyObject_DelItemString=Module["_PyObject_DelItemString"]=wasmExports["PyObject_DelItemString"])(a0,a1);var _PyObject_CheckReadBuffer=Module["_PyObject_CheckReadBuffer"]=a0=>(_PyObject_CheckReadBuffer=Module["_PyObject_CheckReadBuffer"]=wasmExports["PyObject_CheckReadBuffer"])(a0);var _PyObject_AsCharBuffer=Module["_PyObject_AsCharBuffer"]=(a0,a1,a2)=>(_PyObject_AsCharBuffer=Module["_PyObject_AsCharBuffer"]=wasmExports["PyObject_AsCharBuffer"])(a0,a1,a2);var _PyObject_AsReadBuffer=Module["_PyObject_AsReadBuffer"]=(a0,a1,a2)=>(_PyObject_AsReadBuffer=Module["_PyObject_AsReadBuffer"]=wasmExports["PyObject_AsReadBuffer"])(a0,a1,a2);var _PyObject_AsWriteBuffer=Module["_PyObject_AsWriteBuffer"]=(a0,a1,a2)=>(_PyObject_AsWriteBuffer=Module["_PyObject_AsWriteBuffer"]=wasmExports["PyObject_AsWriteBuffer"])(a0,a1,a2);var _PyBuffer_GetPointer=Module["_PyBuffer_GetPointer"]=(a0,a1)=>(_PyBuffer_GetPointer=Module["_PyBuffer_GetPointer"]=wasmExports["PyBuffer_GetPointer"])(a0,a1);var __Py_add_one_to_index_F=Module["__Py_add_one_to_index_F"]=(a0,a1,a2)=>(__Py_add_one_to_index_F=Module["__Py_add_one_to_index_F"]=wasmExports["_Py_add_one_to_index_F"])(a0,a1,a2);var __Py_add_one_to_index_C=Module["__Py_add_one_to_index_C"]=(a0,a1,a2)=>(__Py_add_one_to_index_C=Module["__Py_add_one_to_index_C"]=wasmExports["_Py_add_one_to_index_C"])(a0,a1,a2);var _PyBuffer_SizeFromFormat=Module["_PyBuffer_SizeFromFormat"]=a0=>(_PyBuffer_SizeFromFormat=Module["_PyBuffer_SizeFromFormat"]=wasmExports["PyBuffer_SizeFromFormat"])(a0);var _PyObject_CallFunctionObjArgs=Module["_PyObject_CallFunctionObjArgs"]=(a0,a1)=>(_PyObject_CallFunctionObjArgs=Module["_PyObject_CallFunctionObjArgs"]=wasmExports["PyObject_CallFunctionObjArgs"])(a0,a1);var _PyBuffer_FromContiguous=Module["_PyBuffer_FromContiguous"]=(a0,a1,a2,a3)=>(_PyBuffer_FromContiguous=Module["_PyBuffer_FromContiguous"]=wasmExports["PyBuffer_FromContiguous"])(a0,a1,a2,a3);var _memset=Module["_memset"]=(a0,a1,a2)=>(_memset=Module["_memset"]=wasmExports["memset"])(a0,a1,a2);var _PyObject_CopyData=Module["_PyObject_CopyData"]=(a0,a1)=>(_PyObject_CopyData=Module["_PyObject_CopyData"]=wasmExports["PyObject_CopyData"])(a0,a1);var _PyBuffer_FillInfo=Module["_PyBuffer_FillInfo"]=(a0,a1,a2,a3,a4,a5)=>(_PyBuffer_FillInfo=Module["_PyBuffer_FillInfo"]=wasmExports["PyBuffer_FillInfo"])(a0,a1,a2,a3,a4,a5);var _PyObject_Format=Module["_PyObject_Format"]=(a0,a1)=>(_PyObject_Format=Module["_PyObject_Format"]=wasmExports["PyObject_Format"])(a0,a1);var _PyUnicode_New=Module["_PyUnicode_New"]=(a0,a1)=>(_PyUnicode_New=Module["_PyUnicode_New"]=wasmExports["PyUnicode_New"])(a0,a1);var _PyNumber_Check=Module["_PyNumber_Check"]=a0=>(_PyNumber_Check=Module["_PyNumber_Check"]=wasmExports["PyNumber_Check"])(a0);var _PyNumber_Or=Module["_PyNumber_Or"]=(a0,a1)=>(_PyNumber_Or=Module["_PyNumber_Or"]=wasmExports["PyNumber_Or"])(a0,a1);var _PyNumber_Xor=Module["_PyNumber_Xor"]=(a0,a1)=>(_PyNumber_Xor=Module["_PyNumber_Xor"]=wasmExports["PyNumber_Xor"])(a0,a1);var _PyNumber_And=Module["_PyNumber_And"]=(a0,a1)=>(_PyNumber_And=Module["_PyNumber_And"]=wasmExports["PyNumber_And"])(a0,a1);var _PyNumber_Lshift=Module["_PyNumber_Lshift"]=(a0,a1)=>(_PyNumber_Lshift=Module["_PyNumber_Lshift"]=wasmExports["PyNumber_Lshift"])(a0,a1);var _PyNumber_Rshift=Module["_PyNumber_Rshift"]=(a0,a1)=>(_PyNumber_Rshift=Module["_PyNumber_Rshift"]=wasmExports["PyNumber_Rshift"])(a0,a1);var _PyNumber_Subtract=Module["_PyNumber_Subtract"]=(a0,a1)=>(_PyNumber_Subtract=Module["_PyNumber_Subtract"]=wasmExports["PyNumber_Subtract"])(a0,a1);var _PyNumber_Divmod=Module["_PyNumber_Divmod"]=(a0,a1)=>(_PyNumber_Divmod=Module["_PyNumber_Divmod"]=wasmExports["PyNumber_Divmod"])(a0,a1);var _PyNumber_Add=Module["_PyNumber_Add"]=(a0,a1)=>(_PyNumber_Add=Module["_PyNumber_Add"]=wasmExports["PyNumber_Add"])(a0,a1);var _PyNumber_Multiply=Module["_PyNumber_Multiply"]=(a0,a1)=>(_PyNumber_Multiply=Module["_PyNumber_Multiply"]=wasmExports["PyNumber_Multiply"])(a0,a1);var _PyNumber_MatrixMultiply=Module["_PyNumber_MatrixMultiply"]=(a0,a1)=>(_PyNumber_MatrixMultiply=Module["_PyNumber_MatrixMultiply"]=wasmExports["PyNumber_MatrixMultiply"])(a0,a1);var _PyNumber_FloorDivide=Module["_PyNumber_FloorDivide"]=(a0,a1)=>(_PyNumber_FloorDivide=Module["_PyNumber_FloorDivide"]=wasmExports["PyNumber_FloorDivide"])(a0,a1);var _PyNumber_TrueDivide=Module["_PyNumber_TrueDivide"]=(a0,a1)=>(_PyNumber_TrueDivide=Module["_PyNumber_TrueDivide"]=wasmExports["PyNumber_TrueDivide"])(a0,a1);var _PyNumber_Remainder=Module["_PyNumber_Remainder"]=(a0,a1)=>(_PyNumber_Remainder=Module["_PyNumber_Remainder"]=wasmExports["PyNumber_Remainder"])(a0,a1);var _PyNumber_Power=Module["_PyNumber_Power"]=(a0,a1,a2)=>(_PyNumber_Power=Module["_PyNumber_Power"]=wasmExports["PyNumber_Power"])(a0,a1,a2);var _PyNumber_InPlaceOr=Module["_PyNumber_InPlaceOr"]=(a0,a1)=>(_PyNumber_InPlaceOr=Module["_PyNumber_InPlaceOr"]=wasmExports["PyNumber_InPlaceOr"])(a0,a1);var _PyNumber_InPlaceXor=Module["_PyNumber_InPlaceXor"]=(a0,a1)=>(_PyNumber_InPlaceXor=Module["_PyNumber_InPlaceXor"]=wasmExports["PyNumber_InPlaceXor"])(a0,a1);var _PyNumber_InPlaceAnd=Module["_PyNumber_InPlaceAnd"]=(a0,a1)=>(_PyNumber_InPlaceAnd=Module["_PyNumber_InPlaceAnd"]=wasmExports["PyNumber_InPlaceAnd"])(a0,a1);var _PyNumber_InPlaceLshift=Module["_PyNumber_InPlaceLshift"]=(a0,a1)=>(_PyNumber_InPlaceLshift=Module["_PyNumber_InPlaceLshift"]=wasmExports["PyNumber_InPlaceLshift"])(a0,a1);var _PyNumber_InPlaceRshift=Module["_PyNumber_InPlaceRshift"]=(a0,a1)=>(_PyNumber_InPlaceRshift=Module["_PyNumber_InPlaceRshift"]=wasmExports["PyNumber_InPlaceRshift"])(a0,a1);var _PyNumber_InPlaceSubtract=Module["_PyNumber_InPlaceSubtract"]=(a0,a1)=>(_PyNumber_InPlaceSubtract=Module["_PyNumber_InPlaceSubtract"]=wasmExports["PyNumber_InPlaceSubtract"])(a0,a1);var _PyNumber_InPlaceMatrixMultiply=Module["_PyNumber_InPlaceMatrixMultiply"]=(a0,a1)=>(_PyNumber_InPlaceMatrixMultiply=Module["_PyNumber_InPlaceMatrixMultiply"]=wasmExports["PyNumber_InPlaceMatrixMultiply"])(a0,a1);var _PyNumber_InPlaceFloorDivide=Module["_PyNumber_InPlaceFloorDivide"]=(a0,a1)=>(_PyNumber_InPlaceFloorDivide=Module["_PyNumber_InPlaceFloorDivide"]=wasmExports["PyNumber_InPlaceFloorDivide"])(a0,a1);var _PyNumber_InPlaceTrueDivide=Module["_PyNumber_InPlaceTrueDivide"]=(a0,a1)=>(_PyNumber_InPlaceTrueDivide=Module["_PyNumber_InPlaceTrueDivide"]=wasmExports["PyNumber_InPlaceTrueDivide"])(a0,a1);var _PyNumber_InPlaceRemainder=Module["_PyNumber_InPlaceRemainder"]=(a0,a1)=>(_PyNumber_InPlaceRemainder=Module["_PyNumber_InPlaceRemainder"]=wasmExports["PyNumber_InPlaceRemainder"])(a0,a1);var _PyNumber_InPlaceAdd=Module["_PyNumber_InPlaceAdd"]=(a0,a1)=>(_PyNumber_InPlaceAdd=Module["_PyNumber_InPlaceAdd"]=wasmExports["PyNumber_InPlaceAdd"])(a0,a1);var _PyNumber_InPlaceMultiply=Module["_PyNumber_InPlaceMultiply"]=(a0,a1)=>(_PyNumber_InPlaceMultiply=Module["_PyNumber_InPlaceMultiply"]=wasmExports["PyNumber_InPlaceMultiply"])(a0,a1);var _PyNumber_InPlacePower=Module["_PyNumber_InPlacePower"]=(a0,a1,a2)=>(_PyNumber_InPlacePower=Module["_PyNumber_InPlacePower"]=wasmExports["PyNumber_InPlacePower"])(a0,a1,a2);var _PyNumber_Negative=Module["_PyNumber_Negative"]=a0=>(_PyNumber_Negative=Module["_PyNumber_Negative"]=wasmExports["PyNumber_Negative"])(a0);var _PyNumber_Positive=Module["_PyNumber_Positive"]=a0=>(_PyNumber_Positive=Module["_PyNumber_Positive"]=wasmExports["PyNumber_Positive"])(a0);var _PyNumber_Invert=Module["_PyNumber_Invert"]=a0=>(_PyNumber_Invert=Module["_PyNumber_Invert"]=wasmExports["PyNumber_Invert"])(a0);var _PyNumber_Absolute=Module["_PyNumber_Absolute"]=a0=>(_PyNumber_Absolute=Module["_PyNumber_Absolute"]=wasmExports["PyNumber_Absolute"])(a0);var _PyErr_WarnFormat=Module["_PyErr_WarnFormat"]=(a0,a1,a2,a3)=>(_PyErr_WarnFormat=Module["_PyErr_WarnFormat"]=wasmExports["PyErr_WarnFormat"])(a0,a1,a2,a3);var _PyNumber_Index=Module["_PyNumber_Index"]=a0=>(_PyNumber_Index=Module["_PyNumber_Index"]=wasmExports["PyNumber_Index"])(a0);var __PyLong_Copy=Module["__PyLong_Copy"]=a0=>(__PyLong_Copy=Module["__PyLong_Copy"]=wasmExports["_PyLong_Copy"])(a0);var _PyNumber_Long=Module["_PyNumber_Long"]=a0=>(_PyNumber_Long=Module["_PyNumber_Long"]=wasmExports["PyNumber_Long"])(a0);var _PyErr_WarnEx=Module["_PyErr_WarnEx"]=(a0,a1,a2)=>(_PyErr_WarnEx=Module["_PyErr_WarnEx"]=wasmExports["PyErr_WarnEx"])(a0,a1,a2);var _PyLong_FromUnicodeObject=Module["_PyLong_FromUnicodeObject"]=(a0,a1)=>(_PyLong_FromUnicodeObject=Module["_PyLong_FromUnicodeObject"]=wasmExports["PyLong_FromUnicodeObject"])(a0,a1);var __PyLong_FromBytes=Module["__PyLong_FromBytes"]=(a0,a1,a2)=>(__PyLong_FromBytes=Module["__PyLong_FromBytes"]=wasmExports["_PyLong_FromBytes"])(a0,a1,a2);var _PyNumber_Float=Module["_PyNumber_Float"]=a0=>(_PyNumber_Float=Module["_PyNumber_Float"]=wasmExports["PyNumber_Float"])(a0);var _PyLong_AsDouble=Module["_PyLong_AsDouble"]=a0=>(_PyLong_AsDouble=Module["_PyLong_AsDouble"]=wasmExports["PyLong_AsDouble"])(a0);var _PyFloat_FromString=Module["_PyFloat_FromString"]=a0=>(_PyFloat_FromString=Module["_PyFloat_FromString"]=wasmExports["PyFloat_FromString"])(a0);var _PyNumber_ToBase=Module["_PyNumber_ToBase"]=(a0,a1)=>(_PyNumber_ToBase=Module["_PyNumber_ToBase"]=wasmExports["PyNumber_ToBase"])(a0,a1);var __PyLong_Format=Module["__PyLong_Format"]=(a0,a1)=>(__PyLong_Format=Module["__PyLong_Format"]=wasmExports["_PyLong_Format"])(a0,a1);var _PySequence_Check=Module["_PySequence_Check"]=a0=>(_PySequence_Check=Module["_PySequence_Check"]=wasmExports["PySequence_Check"])(a0);var _PySequence_Length=Module["_PySequence_Length"]=a0=>(_PySequence_Length=Module["_PySequence_Length"]=wasmExports["PySequence_Length"])(a0);var _PySequence_Concat=Module["_PySequence_Concat"]=(a0,a1)=>(_PySequence_Concat=Module["_PySequence_Concat"]=wasmExports["PySequence_Concat"])(a0,a1);var _PySequence_Repeat=Module["_PySequence_Repeat"]=(a0,a1)=>(_PySequence_Repeat=Module["_PySequence_Repeat"]=wasmExports["PySequence_Repeat"])(a0,a1);var _PySequence_InPlaceConcat=Module["_PySequence_InPlaceConcat"]=(a0,a1)=>(_PySequence_InPlaceConcat=Module["_PySequence_InPlaceConcat"]=wasmExports["PySequence_InPlaceConcat"])(a0,a1);var _PySequence_InPlaceRepeat=Module["_PySequence_InPlaceRepeat"]=(a0,a1)=>(_PySequence_InPlaceRepeat=Module["_PySequence_InPlaceRepeat"]=wasmExports["PySequence_InPlaceRepeat"])(a0,a1);var __PySlice_FromIndices=Module["__PySlice_FromIndices"]=(a0,a1)=>(__PySlice_FromIndices=Module["__PySlice_FromIndices"]=wasmExports["_PySlice_FromIndices"])(a0,a1);var _PySequence_DelSlice=Module["_PySequence_DelSlice"]=(a0,a1,a2)=>(_PySequence_DelSlice=Module["_PySequence_DelSlice"]=wasmExports["PySequence_DelSlice"])(a0,a1,a2);var _PySequence_Tuple=Module["_PySequence_Tuple"]=a0=>(_PySequence_Tuple=Module["_PySequence_Tuple"]=wasmExports["PySequence_Tuple"])(a0);var _PyList_AsTuple=Module["_PyList_AsTuple"]=a0=>(_PyList_AsTuple=Module["_PyList_AsTuple"]=wasmExports["PyList_AsTuple"])(a0);var __PyTuple_Resize=Module["__PyTuple_Resize"]=(a0,a1)=>(__PyTuple_Resize=Module["__PyTuple_Resize"]=wasmExports["_PyTuple_Resize"])(a0,a1);var _PySeqIter_New=Module["_PySeqIter_New"]=a0=>(_PySeqIter_New=Module["_PySeqIter_New"]=wasmExports["PySeqIter_New"])(a0);var _PySequence_List=Module["_PySequence_List"]=a0=>(_PySequence_List=Module["_PySequence_List"]=wasmExports["PySequence_List"])(a0);var __PySequence_IterSearch=Module["__PySequence_IterSearch"]=(a0,a1,a2)=>(__PySequence_IterSearch=Module["__PySequence_IterSearch"]=wasmExports["_PySequence_IterSearch"])(a0,a1,a2);var _PySequence_Count=Module["_PySequence_Count"]=(a0,a1)=>(_PySequence_Count=Module["_PySequence_Count"]=wasmExports["PySequence_Count"])(a0,a1);var _PySequence_In=Module["_PySequence_In"]=(a0,a1)=>(_PySequence_In=Module["_PySequence_In"]=wasmExports["PySequence_In"])(a0,a1);var _PySequence_Index=Module["_PySequence_Index"]=(a0,a1)=>(_PySequence_Index=Module["_PySequence_Index"]=wasmExports["PySequence_Index"])(a0,a1);var _PyMapping_Check=Module["_PyMapping_Check"]=a0=>(_PyMapping_Check=Module["_PyMapping_Check"]=wasmExports["PyMapping_Check"])(a0);var _PyMapping_Length=Module["_PyMapping_Length"]=a0=>(_PyMapping_Length=Module["_PyMapping_Length"]=wasmExports["PyMapping_Length"])(a0);var _PyMapping_GetItemString=Module["_PyMapping_GetItemString"]=(a0,a1)=>(_PyMapping_GetItemString=Module["_PyMapping_GetItemString"]=wasmExports["PyMapping_GetItemString"])(a0,a1);var _PyMapping_SetItemString=Module["_PyMapping_SetItemString"]=(a0,a1,a2)=>(_PyMapping_SetItemString=Module["_PyMapping_SetItemString"]=wasmExports["PyMapping_SetItemString"])(a0,a1,a2);var _PyMapping_HasKeyString=Module["_PyMapping_HasKeyString"]=(a0,a1)=>(_PyMapping_HasKeyString=Module["_PyMapping_HasKeyString"]=wasmExports["PyMapping_HasKeyString"])(a0,a1);var _PyMapping_HasKey=Module["_PyMapping_HasKey"]=(a0,a1)=>(_PyMapping_HasKey=Module["_PyMapping_HasKey"]=wasmExports["PyMapping_HasKey"])(a0,a1);var _PyMapping_Keys=Module["_PyMapping_Keys"]=a0=>(_PyMapping_Keys=Module["_PyMapping_Keys"]=wasmExports["PyMapping_Keys"])(a0);var _PyDict_Keys=Module["_PyDict_Keys"]=a0=>(_PyDict_Keys=Module["_PyDict_Keys"]=wasmExports["PyDict_Keys"])(a0);var _PyMapping_Items=Module["_PyMapping_Items"]=a0=>(_PyMapping_Items=Module["_PyMapping_Items"]=wasmExports["PyMapping_Items"])(a0);var _PyDict_Items=Module["_PyDict_Items"]=a0=>(_PyDict_Items=Module["_PyDict_Items"]=wasmExports["PyDict_Items"])(a0);var _PyMapping_Values=Module["_PyMapping_Values"]=a0=>(_PyMapping_Values=Module["_PyMapping_Values"]=wasmExports["PyMapping_Values"])(a0);var _PyDict_Values=Module["_PyDict_Values"]=a0=>(_PyDict_Values=Module["_PyDict_Values"]=wasmExports["PyDict_Values"])(a0);var __Py_CheckRecursiveCall=Module["__Py_CheckRecursiveCall"]=(a0,a1)=>(__Py_CheckRecursiveCall=Module["__Py_CheckRecursiveCall"]=wasmExports["_Py_CheckRecursiveCall"])(a0,a1);var _PyObject_IsTrue=Module["_PyObject_IsTrue"]=a0=>(_PyObject_IsTrue=Module["_PyObject_IsTrue"]=wasmExports["PyObject_IsTrue"])(a0);var __PyObject_RealIsInstance=Module["__PyObject_RealIsInstance"]=(a0,a1)=>(__PyObject_RealIsInstance=Module["__PyObject_RealIsInstance"]=wasmExports["_PyObject_RealIsInstance"])(a0,a1);var __PyObject_RealIsSubclass=Module["__PyObject_RealIsSubclass"]=(a0,a1)=>(__PyObject_RealIsSubclass=Module["__PyObject_RealIsSubclass"]=wasmExports["_PyObject_RealIsSubclass"])(a0,a1);var _PyIter_Check=Module["_PyIter_Check"]=a0=>(_PyIter_Check=Module["_PyIter_Check"]=wasmExports["PyIter_Check"])(a0);var _PyObject_GetAIter=Module["_PyObject_GetAIter"]=a0=>(_PyObject_GetAIter=Module["_PyObject_GetAIter"]=wasmExports["PyObject_GetAIter"])(a0);var _PyAIter_Check=Module["_PyAIter_Check"]=a0=>(_PyAIter_Check=Module["_PyAIter_Check"]=wasmExports["PyAIter_Check"])(a0);var __PySequence_BytesToCharpArray=Module["__PySequence_BytesToCharpArray"]=a0=>(__PySequence_BytesToCharpArray=Module["__PySequence_BytesToCharpArray"]=wasmExports["_PySequence_BytesToCharpArray"])(a0);var __Py_FreeCharPArray=Module["__Py_FreeCharPArray"]=a0=>(__Py_FreeCharPArray=Module["__Py_FreeCharPArray"]=wasmExports["_Py_FreeCharPArray"])(a0);var _PyBool_FromLong=Module["_PyBool_FromLong"]=a0=>(_PyBool_FromLong=Module["_PyBool_FromLong"]=wasmExports["PyBool_FromLong"])(a0);var __PyArg_NoKeywords=Module["__PyArg_NoKeywords"]=(a0,a1)=>(__PyArg_NoKeywords=Module["__PyArg_NoKeywords"]=wasmExports["_PyArg_NoKeywords"])(a0,a1);var __PyArg_NoKwnames=Module["__PyArg_NoKwnames"]=(a0,a1)=>(__PyArg_NoKwnames=Module["__PyArg_NoKwnames"]=wasmExports["_PyArg_NoKwnames"])(a0,a1);var _memrchr=Module["_memrchr"]=(a0,a1,a2)=>(_memrchr=Module["_memrchr"]=wasmExports["memrchr"])(a0,a1,a2);var __PyEval_SliceIndex=Module["__PyEval_SliceIndex"]=(a0,a1)=>(__PyEval_SliceIndex=Module["__PyEval_SliceIndex"]=wasmExports["_PyEval_SliceIndex"])(a0,a1);var _PyByteArray_FromObject=Module["_PyByteArray_FromObject"]=a0=>(_PyByteArray_FromObject=Module["_PyByteArray_FromObject"]=wasmExports["PyByteArray_FromObject"])(a0);var _PyByteArray_FromStringAndSize=Module["_PyByteArray_FromStringAndSize"]=(a0,a1)=>(_PyByteArray_FromStringAndSize=Module["_PyByteArray_FromStringAndSize"]=wasmExports["PyByteArray_FromStringAndSize"])(a0,a1);var __PyObject_New=Module["__PyObject_New"]=a0=>(__PyObject_New=Module["__PyObject_New"]=wasmExports["_PyObject_New"])(a0);var _PyByteArray_Size=Module["_PyByteArray_Size"]=a0=>(_PyByteArray_Size=Module["_PyByteArray_Size"]=wasmExports["PyByteArray_Size"])(a0);var _PyByteArray_AsString=Module["_PyByteArray_AsString"]=a0=>(_PyByteArray_AsString=Module["_PyByteArray_AsString"]=wasmExports["PyByteArray_AsString"])(a0);var _PyByteArray_Resize=Module["_PyByteArray_Resize"]=(a0,a1)=>(_PyByteArray_Resize=Module["_PyByteArray_Resize"]=wasmExports["PyByteArray_Resize"])(a0,a1);var _PyObject_Realloc=Module["_PyObject_Realloc"]=(a0,a1)=>(_PyObject_Realloc=Module["_PyObject_Realloc"]=wasmExports["PyObject_Realloc"])(a0,a1);var _PyByteArray_Concat=Module["_PyByteArray_Concat"]=(a0,a1)=>(_PyByteArray_Concat=Module["_PyByteArray_Concat"]=wasmExports["PyByteArray_Concat"])(a0,a1);var __Py_GetConfig=Module["__Py_GetConfig"]=()=>(__Py_GetConfig=Module["__Py_GetConfig"]=wasmExports["_Py_GetConfig"])();var __PyObject_GC_New=Module["__PyObject_GC_New"]=a0=>(__PyObject_GC_New=Module["__PyObject_GC_New"]=wasmExports["_PyObject_GC_New"])(a0);var __PyArg_UnpackKeywords=Module["__PyArg_UnpackKeywords"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(__PyArg_UnpackKeywords=Module["__PyArg_UnpackKeywords"]=wasmExports["_PyArg_UnpackKeywords"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var __PyArg_BadArgument=Module["__PyArg_BadArgument"]=(a0,a1,a2,a3)=>(__PyArg_BadArgument=Module["__PyArg_BadArgument"]=wasmExports["_PyArg_BadArgument"])(a0,a1,a2,a3);var _PyUnicode_AsEncodedString=Module["_PyUnicode_AsEncodedString"]=(a0,a1,a2)=>(_PyUnicode_AsEncodedString=Module["_PyUnicode_AsEncodedString"]=wasmExports["PyUnicode_AsEncodedString"])(a0,a1,a2);var _PyBuffer_ToContiguous=Module["_PyBuffer_ToContiguous"]=(a0,a1,a2,a3)=>(_PyBuffer_ToContiguous=Module["_PyBuffer_ToContiguous"]=wasmExports["PyBuffer_ToContiguous"])(a0,a1,a2,a3);var _PyObject_GC_Del=Module["_PyObject_GC_Del"]=a0=>(_PyObject_GC_Del=Module["_PyObject_GC_Del"]=wasmExports["PyObject_GC_Del"])(a0);var __PyBytes_FormatEx=Module["__PyBytes_FormatEx"]=(a0,a1,a2,a3)=>(__PyBytes_FormatEx=Module["__PyBytes_FormatEx"]=wasmExports["_PyBytes_FormatEx"])(a0,a1,a2,a3);var __PyBytes_Repeat=Module["__PyBytes_Repeat"]=(a0,a1,a2,a3)=>(__PyBytes_Repeat=Module["__PyBytes_Repeat"]=wasmExports["_PyBytes_Repeat"])(a0,a1,a2,a3);var _memmove=Module["_memmove"]=(a0,a1,a2)=>(_memmove=Module["_memmove"]=wasmExports["memmove"])(a0,a1,a2);var __PyObject_GetState=Module["__PyObject_GetState"]=a0=>(__PyObject_GetState=Module["__PyObject_GetState"]=wasmExports["_PyObject_GetState"])(a0);var _PyUnicode_DecodeLatin1=Module["_PyUnicode_DecodeLatin1"]=(a0,a1,a2)=>(_PyUnicode_DecodeLatin1=Module["_PyUnicode_DecodeLatin1"]=wasmExports["PyUnicode_DecodeLatin1"])(a0,a1,a2);var __PyLong_AsInt=Module["__PyLong_AsInt"]=a0=>(__PyLong_AsInt=Module["__PyLong_AsInt"]=wasmExports["_PyLong_AsInt"])(a0);var _PyLong_FromSize_t=Module["_PyLong_FromSize_t"]=a0=>(_PyLong_FromSize_t=Module["_PyLong_FromSize_t"]=wasmExports["PyLong_FromSize_t"])(a0);var _PyUnicode_GetDefaultEncoding=Module["_PyUnicode_GetDefaultEncoding"]=()=>(_PyUnicode_GetDefaultEncoding=Module["_PyUnicode_GetDefaultEncoding"]=wasmExports["PyUnicode_GetDefaultEncoding"])();var _PyUnicode_FromEncodedObject=Module["_PyUnicode_FromEncodedObject"]=(a0,a1,a2)=>(_PyUnicode_FromEncodedObject=Module["_PyUnicode_FromEncodedObject"]=wasmExports["PyUnicode_FromEncodedObject"])(a0,a1,a2);var __PyBytes_FromHex=Module["__PyBytes_FromHex"]=(a0,a1)=>(__PyBytes_FromHex=Module["__PyBytes_FromHex"]=wasmExports["_PyBytes_FromHex"])(a0,a1);var __Py_strhex_with_sep=Module["__Py_strhex_with_sep"]=(a0,a1,a2,a3)=>(__Py_strhex_with_sep=Module["__Py_strhex_with_sep"]=wasmExports["_Py_strhex_with_sep"])(a0,a1,a2,a3);var _PyList_Append=Module["_PyList_Append"]=(a0,a1)=>(_PyList_Append=Module["_PyList_Append"]=wasmExports["PyList_Append"])(a0,a1);var _PyList_Reverse=Module["_PyList_Reverse"]=a0=>(_PyList_Reverse=Module["_PyList_Reverse"]=wasmExports["PyList_Reverse"])(a0);var __PyEval_GetBuiltin=Module["__PyEval_GetBuiltin"]=a0=>(__PyEval_GetBuiltin=Module["__PyEval_GetBuiltin"]=wasmExports["_PyEval_GetBuiltin"])(a0);var _PyObject_GenericGetAttr=Module["_PyObject_GenericGetAttr"]=(a0,a1)=>(_PyObject_GenericGetAttr=Module["_PyObject_GenericGetAttr"]=wasmExports["PyObject_GenericGetAttr"])(a0,a1);var _PyType_GenericAlloc=Module["_PyType_GenericAlloc"]=(a0,a1)=>(_PyType_GenericAlloc=Module["_PyType_GenericAlloc"]=wasmExports["PyType_GenericAlloc"])(a0,a1);var _PyObject_Calloc=Module["_PyObject_Calloc"]=(a0,a1)=>(_PyObject_Calloc=Module["_PyObject_Calloc"]=wasmExports["PyObject_Calloc"])(a0,a1);var __Py_NewReference=Module["__Py_NewReference"]=a0=>(__Py_NewReference=Module["__Py_NewReference"]=wasmExports["_Py_NewReference"])(a0);var _PyBytes_FromFormatV=Module["_PyBytes_FromFormatV"]=(a0,a1)=>(_PyBytes_FromFormatV=Module["_PyBytes_FromFormatV"]=wasmExports["PyBytes_FromFormatV"])(a0,a1);var __PyBytesWriter_Resize=Module["__PyBytesWriter_Resize"]=(a0,a1,a2)=>(__PyBytesWriter_Resize=Module["__PyBytesWriter_Resize"]=wasmExports["_PyBytesWriter_Resize"])(a0,a1,a2);var __PyBytesWriter_Finish=Module["__PyBytesWriter_Finish"]=(a0,a1)=>(__PyBytesWriter_Finish=Module["__PyBytesWriter_Finish"]=wasmExports["_PyBytesWriter_Finish"])(a0,a1);var __PyBytesWriter_Init=Module["__PyBytesWriter_Init"]=a0=>(__PyBytesWriter_Init=Module["__PyBytesWriter_Init"]=wasmExports["_PyBytesWriter_Init"])(a0);var __PyBytesWriter_Alloc=Module["__PyBytesWriter_Alloc"]=(a0,a1)=>(__PyBytesWriter_Alloc=Module["__PyBytesWriter_Alloc"]=wasmExports["_PyBytesWriter_Alloc"])(a0,a1);var __PyBytesWriter_WriteBytes=Module["__PyBytesWriter_WriteBytes"]=(a0,a1,a2,a3)=>(__PyBytesWriter_WriteBytes=Module["__PyBytesWriter_WriteBytes"]=wasmExports["_PyBytesWriter_WriteBytes"])(a0,a1,a2,a3);var __PyBytes_Resize=Module["__PyBytes_Resize"]=(a0,a1)=>(__PyBytes_Resize=Module["__PyBytes_Resize"]=wasmExports["_PyBytes_Resize"])(a0,a1);var __PyBytesWriter_Dealloc=Module["__PyBytesWriter_Dealloc"]=a0=>(__PyBytesWriter_Dealloc=Module["__PyBytesWriter_Dealloc"]=wasmExports["_PyBytesWriter_Dealloc"])(a0);var _PyBytes_FromFormat=Module["_PyBytes_FromFormat"]=(a0,a1)=>(_PyBytes_FromFormat=Module["_PyBytes_FromFormat"]=wasmExports["PyBytes_FromFormat"])(a0,a1);var _PyObject_ASCII=Module["_PyObject_ASCII"]=a0=>(_PyObject_ASCII=Module["_PyObject_ASCII"]=wasmExports["PyObject_ASCII"])(a0);var __PyLong_FormatBytesWriter=Module["__PyLong_FormatBytesWriter"]=(a0,a1,a2,a3,a4)=>(__PyLong_FormatBytesWriter=Module["__PyLong_FormatBytesWriter"]=wasmExports["_PyLong_FormatBytesWriter"])(a0,a1,a2,a3,a4);var __PyUnicode_FormatLong=Module["__PyUnicode_FormatLong"]=(a0,a1,a2,a3)=>(__PyUnicode_FormatLong=Module["__PyUnicode_FormatLong"]=wasmExports["_PyUnicode_FormatLong"])(a0,a1,a2,a3);var _PyOS_double_to_string=Module["_PyOS_double_to_string"]=(a0,a1,a2,a3,a4)=>(_PyOS_double_to_string=Module["_PyOS_double_to_string"]=wasmExports["PyOS_double_to_string"])(a0,a1,a2,a3,a4);var __PyBytesWriter_Prepare=Module["__PyBytesWriter_Prepare"]=(a0,a1,a2)=>(__PyBytesWriter_Prepare=Module["__PyBytesWriter_Prepare"]=wasmExports["_PyBytesWriter_Prepare"])(a0,a1,a2);var _PyBytes_DecodeEscape=Module["_PyBytes_DecodeEscape"]=(a0,a1,a2,a3,a4)=>(_PyBytes_DecodeEscape=Module["_PyBytes_DecodeEscape"]=wasmExports["PyBytes_DecodeEscape"])(a0,a1,a2,a3,a4);var _PyBytes_Size=Module["_PyBytes_Size"]=a0=>(_PyBytes_Size=Module["_PyBytes_Size"]=wasmExports["PyBytes_Size"])(a0);var __PyBytes_Find=Module["__PyBytes_Find"]=(a0,a1,a2,a3,a4)=>(__PyBytes_Find=Module["__PyBytes_Find"]=wasmExports["_PyBytes_Find"])(a0,a1,a2,a3,a4);var __PyBytes_ReverseFind=Module["__PyBytes_ReverseFind"]=(a0,a1,a2,a3,a4)=>(__PyBytes_ReverseFind=Module["__PyBytes_ReverseFind"]=wasmExports["_PyBytes_ReverseFind"])(a0,a1,a2,a3,a4);var _PyBytes_Repr=Module["_PyBytes_Repr"]=(a0,a1)=>(_PyBytes_Repr=Module["_PyBytes_Repr"]=wasmExports["PyBytes_Repr"])(a0,a1);var __PyBytes_Join=Module["__PyBytes_Join"]=(a0,a1)=>(__PyBytes_Join=Module["__PyBytes_Join"]=wasmExports["_PyBytes_Join"])(a0,a1);var _PyBytes_FromObject=Module["_PyBytes_FromObject"]=a0=>(_PyBytes_FromObject=Module["_PyBytes_FromObject"]=wasmExports["PyBytes_FromObject"])(a0);var _PyErr_BadArgument=Module["_PyErr_BadArgument"]=()=>(_PyErr_BadArgument=Module["_PyErr_BadArgument"]=wasmExports["PyErr_BadArgument"])();var __Py_NewReferenceNoTotal=Module["__Py_NewReferenceNoTotal"]=a0=>(__Py_NewReferenceNoTotal=Module["__Py_NewReferenceNoTotal"]=wasmExports["_Py_NewReferenceNoTotal"])(a0);var _PyBytes_ConcatAndDel=Module["_PyBytes_ConcatAndDel"]=(a0,a1)=>(_PyBytes_ConcatAndDel=Module["_PyBytes_ConcatAndDel"]=wasmExports["PyBytes_ConcatAndDel"])(a0,a1);var __PyErr_FormatFromCauseTstate=Module["__PyErr_FormatFromCauseTstate"]=(a0,a1,a2,a3)=>(__PyErr_FormatFromCauseTstate=Module["__PyErr_FormatFromCauseTstate"]=wasmExports["_PyErr_FormatFromCauseTstate"])(a0,a1,a2,a3);var __Py_FatalErrorFormat=Module["__Py_FatalErrorFormat"]=(a0,a1,a2)=>(__Py_FatalErrorFormat=Module["__Py_FatalErrorFormat"]=wasmExports["_Py_FatalErrorFormat"])(a0,a1,a2);var __PyObject_FastCallDictTstate=Module["__PyObject_FastCallDictTstate"]=(a0,a1,a2,a3,a4)=>(__PyObject_FastCallDictTstate=Module["__PyObject_FastCallDictTstate"]=wasmExports["_PyObject_FastCallDictTstate"])(a0,a1,a2,a3,a4);var _PyVectorcall_Function=Module["_PyVectorcall_Function"]=a0=>(_PyVectorcall_Function=Module["_PyVectorcall_Function"]=wasmExports["PyVectorcall_Function"])(a0);var __PyErr_NoMemory=Module["__PyErr_NoMemory"]=a0=>(__PyErr_NoMemory=Module["__PyErr_NoMemory"]=wasmExports["_PyErr_NoMemory"])(a0);var _PyDict_Next=Module["_PyDict_Next"]=(a0,a1,a2,a3)=>(_PyDict_Next=Module["_PyDict_Next"]=wasmExports["PyDict_Next"])(a0,a1,a2,a3);var _PyObject_VectorcallDict=Module["_PyObject_VectorcallDict"]=(a0,a1,a2,a3)=>(_PyObject_VectorcallDict=Module["_PyObject_VectorcallDict"]=wasmExports["PyObject_VectorcallDict"])(a0,a1,a2,a3);var _PyModule_GetNameObject=Module["_PyModule_GetNameObject"]=a0=>(_PyModule_GetNameObject=Module["_PyModule_GetNameObject"]=wasmExports["PyModule_GetNameObject"])(a0);var _PyCallable_Check=Module["_PyCallable_Check"]=a0=>(_PyCallable_Check=Module["_PyCallable_Check"]=wasmExports["PyCallable_Check"])(a0);var __PyStack_AsDict=Module["__PyStack_AsDict"]=(a0,a1)=>(__PyStack_AsDict=Module["__PyStack_AsDict"]=wasmExports["_PyStack_AsDict"])(a0,a1);var __PyObject_Call=Module["__PyObject_Call"]=(a0,a1,a2,a3)=>(__PyObject_Call=Module["__PyObject_Call"]=wasmExports["_PyObject_Call"])(a0,a1,a2,a3);var _PyObject_Call=Module["_PyObject_Call"]=(a0,a1,a2)=>(_PyObject_Call=Module["_PyObject_Call"]=wasmExports["PyObject_Call"])(a0,a1,a2);var _PyCFunction_Call=Module["_PyCFunction_Call"]=(a0,a1,a2)=>(_PyCFunction_Call=Module["_PyCFunction_Call"]=wasmExports["PyCFunction_Call"])(a0,a1,a2);var __PyFunction_Vectorcall=Module["__PyFunction_Vectorcall"]=(a0,a1,a2,a3)=>(__PyFunction_Vectorcall=Module["__PyFunction_Vectorcall"]=wasmExports["_PyFunction_Vectorcall"])(a0,a1,a2,a3);var _PyEval_CallObjectWithKeywords=Module["_PyEval_CallObjectWithKeywords"]=(a0,a1,a2)=>(_PyEval_CallObjectWithKeywords=Module["_PyEval_CallObjectWithKeywords"]=wasmExports["PyEval_CallObjectWithKeywords"])(a0,a1,a2);var _PyObject_CallObject=Module["_PyObject_CallObject"]=(a0,a1)=>(_PyObject_CallObject=Module["_PyObject_CallObject"]=wasmExports["PyObject_CallObject"])(a0,a1);var __PyObject_Call_Prepend=Module["__PyObject_Call_Prepend"]=(a0,a1,a2,a3,a4)=>(__PyObject_Call_Prepend=Module["__PyObject_Call_Prepend"]=wasmExports["_PyObject_Call_Prepend"])(a0,a1,a2,a3,a4);var _PyObject_CallFunction=Module["_PyObject_CallFunction"]=(a0,a1,a2)=>(_PyObject_CallFunction=Module["_PyObject_CallFunction"]=wasmExports["PyObject_CallFunction"])(a0,a1,a2);var __Py_VaBuildStack_SizeT=Module["__Py_VaBuildStack_SizeT"]=(a0,a1,a2,a3,a4)=>(__Py_VaBuildStack_SizeT=Module["__Py_VaBuildStack_SizeT"]=wasmExports["_Py_VaBuildStack_SizeT"])(a0,a1,a2,a3,a4);var __Py_VaBuildStack=Module["__Py_VaBuildStack"]=(a0,a1,a2,a3,a4)=>(__Py_VaBuildStack=Module["__Py_VaBuildStack"]=wasmExports["_Py_VaBuildStack"])(a0,a1,a2,a3,a4);var _PyEval_CallFunction=Module["_PyEval_CallFunction"]=(a0,a1,a2)=>(_PyEval_CallFunction=Module["_PyEval_CallFunction"]=wasmExports["PyEval_CallFunction"])(a0,a1,a2);var _PyObject_CallMethod=Module["_PyObject_CallMethod"]=(a0,a1,a2,a3)=>(_PyObject_CallMethod=Module["_PyObject_CallMethod"]=wasmExports["PyObject_CallMethod"])(a0,a1,a2,a3);var _PyEval_CallMethod=Module["_PyEval_CallMethod"]=(a0,a1,a2,a3)=>(_PyEval_CallMethod=Module["_PyEval_CallMethod"]=wasmExports["PyEval_CallMethod"])(a0,a1,a2,a3);var __PyObject_CallMethod=Module["__PyObject_CallMethod"]=(a0,a1,a2,a3)=>(__PyObject_CallMethod=Module["__PyObject_CallMethod"]=wasmExports["_PyObject_CallMethod"])(a0,a1,a2,a3);var __PyObject_CallMethodId=Module["__PyObject_CallMethodId"]=(a0,a1,a2,a3)=>(__PyObject_CallMethodId=Module["__PyObject_CallMethodId"]=wasmExports["_PyObject_CallMethodId"])(a0,a1,a2,a3);var __PyObject_CallMethod_SizeT=Module["__PyObject_CallMethod_SizeT"]=(a0,a1,a2,a3)=>(__PyObject_CallMethod_SizeT=Module["__PyObject_CallMethod_SizeT"]=wasmExports["_PyObject_CallMethod_SizeT"])(a0,a1,a2,a3);var __PyObject_CallMethodId_SizeT=Module["__PyObject_CallMethodId_SizeT"]=(a0,a1,a2,a3)=>(__PyObject_CallMethodId_SizeT=Module["__PyObject_CallMethodId_SizeT"]=wasmExports["_PyObject_CallMethodId_SizeT"])(a0,a1,a2,a3);var _PyObject_CallMethodObjArgs=Module["_PyObject_CallMethodObjArgs"]=(a0,a1,a2)=>(_PyObject_CallMethodObjArgs=Module["_PyObject_CallMethodObjArgs"]=wasmExports["PyObject_CallMethodObjArgs"])(a0,a1,a2);var _PyVectorcall_NARGS=Module["_PyVectorcall_NARGS"]=a0=>(_PyVectorcall_NARGS=Module["_PyVectorcall_NARGS"]=wasmExports["PyVectorcall_NARGS"])(a0);var _PyCapsule_New=Module["_PyCapsule_New"]=(a0,a1,a2)=>(_PyCapsule_New=Module["_PyCapsule_New"]=wasmExports["PyCapsule_New"])(a0,a1,a2);var _PyCapsule_IsValid=Module["_PyCapsule_IsValid"]=(a0,a1)=>(_PyCapsule_IsValid=Module["_PyCapsule_IsValid"]=wasmExports["PyCapsule_IsValid"])(a0,a1);var _PyCapsule_GetPointer=Module["_PyCapsule_GetPointer"]=(a0,a1)=>(_PyCapsule_GetPointer=Module["_PyCapsule_GetPointer"]=wasmExports["PyCapsule_GetPointer"])(a0,a1);var _PyCapsule_GetName=Module["_PyCapsule_GetName"]=a0=>(_PyCapsule_GetName=Module["_PyCapsule_GetName"]=wasmExports["PyCapsule_GetName"])(a0);var _PyCapsule_GetDestructor=Module["_PyCapsule_GetDestructor"]=a0=>(_PyCapsule_GetDestructor=Module["_PyCapsule_GetDestructor"]=wasmExports["PyCapsule_GetDestructor"])(a0);var _PyCapsule_GetContext=Module["_PyCapsule_GetContext"]=a0=>(_PyCapsule_GetContext=Module["_PyCapsule_GetContext"]=wasmExports["PyCapsule_GetContext"])(a0);var _PyCapsule_SetPointer=Module["_PyCapsule_SetPointer"]=(a0,a1)=>(_PyCapsule_SetPointer=Module["_PyCapsule_SetPointer"]=wasmExports["PyCapsule_SetPointer"])(a0,a1);var _PyCapsule_SetName=Module["_PyCapsule_SetName"]=(a0,a1)=>(_PyCapsule_SetName=Module["_PyCapsule_SetName"]=wasmExports["PyCapsule_SetName"])(a0,a1);var _PyCapsule_SetDestructor=Module["_PyCapsule_SetDestructor"]=(a0,a1)=>(_PyCapsule_SetDestructor=Module["_PyCapsule_SetDestructor"]=wasmExports["PyCapsule_SetDestructor"])(a0,a1);var _PyCapsule_SetContext=Module["_PyCapsule_SetContext"]=(a0,a1)=>(_PyCapsule_SetContext=Module["_PyCapsule_SetContext"]=wasmExports["PyCapsule_SetContext"])(a0,a1);var _PyCapsule_Import=Module["_PyCapsule_Import"]=(a0,a1)=>(_PyCapsule_Import=Module["_PyCapsule_Import"]=wasmExports["PyCapsule_Import"])(a0,a1);var _PyCell_New=Module["_PyCell_New"]=a0=>(_PyCell_New=Module["_PyCell_New"]=wasmExports["PyCell_New"])(a0);var _PyCell_Get=Module["_PyCell_Get"]=a0=>(_PyCell_Get=Module["_PyCell_Get"]=wasmExports["PyCell_Get"])(a0);var _PyCell_Set=Module["_PyCell_Set"]=(a0,a1)=>(_PyCell_Set=Module["_PyCell_Set"]=wasmExports["PyCell_Set"])(a0,a1);var _PyObject_RichCompare=Module["_PyObject_RichCompare"]=(a0,a1,a2)=>(_PyObject_RichCompare=Module["_PyObject_RichCompare"]=wasmExports["PyObject_RichCompare"])(a0,a1,a2);var _PyMethod_Function=Module["_PyMethod_Function"]=a0=>(_PyMethod_Function=Module["_PyMethod_Function"]=wasmExports["PyMethod_Function"])(a0);var _PyMethod_Self=Module["_PyMethod_Self"]=a0=>(_PyMethod_Self=Module["_PyMethod_Self"]=wasmExports["PyMethod_Self"])(a0);var _PyMethod_New=Module["_PyMethod_New"]=(a0,a1)=>(_PyMethod_New=Module["_PyMethod_New"]=wasmExports["PyMethod_New"])(a0,a1);var _PyObject_ClearWeakRefs=Module["_PyObject_ClearWeakRefs"]=a0=>(_PyObject_ClearWeakRefs=Module["_PyObject_ClearWeakRefs"]=wasmExports["PyObject_ClearWeakRefs"])(a0);var __Py_HashPointer=Module["__Py_HashPointer"]=a0=>(__Py_HashPointer=Module["__Py_HashPointer"]=wasmExports["_Py_HashPointer"])(a0);var __PyType_GetDict=Module["__PyType_GetDict"]=a0=>(__PyType_GetDict=Module["__PyType_GetDict"]=wasmExports["_PyType_GetDict"])(a0);var __PyType_Lookup=Module["__PyType_Lookup"]=(a0,a1)=>(__PyType_Lookup=Module["__PyType_Lookup"]=wasmExports["_PyType_Lookup"])(a0,a1);var _PyInstanceMethod_New=Module["_PyInstanceMethod_New"]=a0=>(_PyInstanceMethod_New=Module["_PyInstanceMethod_New"]=wasmExports["PyInstanceMethod_New"])(a0);var _PyInstanceMethod_Function=Module["_PyInstanceMethod_Function"]=a0=>(_PyInstanceMethod_Function=Module["_PyInstanceMethod_Function"]=wasmExports["PyInstanceMethod_Function"])(a0);var _PyCode_AddWatcher=Module["_PyCode_AddWatcher"]=a0=>(_PyCode_AddWatcher=Module["_PyCode_AddWatcher"]=wasmExports["PyCode_AddWatcher"])(a0);var _PyCode_ClearWatcher=Module["_PyCode_ClearWatcher"]=a0=>(_PyCode_ClearWatcher=Module["_PyCode_ClearWatcher"]=wasmExports["PyCode_ClearWatcher"])(a0);var __PyCode_Validate=Module["__PyCode_Validate"]=a0=>(__PyCode_Validate=Module["__PyCode_Validate"]=wasmExports["_PyCode_Validate"])(a0);var __PyCode_New=Module["__PyCode_New"]=a0=>(__PyCode_New=Module["__PyCode_New"]=wasmExports["_PyCode_New"])(a0);var __PyObject_NewVar=Module["__PyObject_NewVar"]=(a0,a1)=>(__PyObject_NewVar=Module["__PyObject_NewVar"]=wasmExports["_PyObject_NewVar"])(a0,a1);var _PyFrozenSet_New=Module["_PyFrozenSet_New"]=a0=>(_PyFrozenSet_New=Module["_PyFrozenSet_New"]=wasmExports["PyFrozenSet_New"])(a0);var _PyUnstable_Code_NewWithPosOnlyArgs=Module["_PyUnstable_Code_NewWithPosOnlyArgs"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17)=>(_PyUnstable_Code_NewWithPosOnlyArgs=Module["_PyUnstable_Code_NewWithPosOnlyArgs"]=wasmExports["PyUnstable_Code_NewWithPosOnlyArgs"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17);var _PyUnicode_Compare=Module["_PyUnicode_Compare"]=(a0,a1)=>(_PyUnicode_Compare=Module["_PyUnicode_Compare"]=wasmExports["PyUnicode_Compare"])(a0,a1);var _PyUnstable_Code_New=Module["_PyUnstable_Code_New"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)=>(_PyUnstable_Code_New=Module["_PyUnstable_Code_New"]=wasmExports["PyUnstable_Code_New"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16);var _PyCode_NewEmpty=Module["_PyCode_NewEmpty"]=(a0,a1,a2)=>(_PyCode_NewEmpty=Module["_PyCode_NewEmpty"]=wasmExports["PyCode_NewEmpty"])(a0,a1,a2);var _PyUnicode_DecodeFSDefault=Module["_PyUnicode_DecodeFSDefault"]=a0=>(_PyUnicode_DecodeFSDefault=Module["_PyUnicode_DecodeFSDefault"]=wasmExports["PyUnicode_DecodeFSDefault"])(a0);var _PyCode_Addr2Line=Module["_PyCode_Addr2Line"]=(a0,a1)=>(_PyCode_Addr2Line=Module["_PyCode_Addr2Line"]=wasmExports["PyCode_Addr2Line"])(a0,a1);var __PyCode_CheckLineNumber=Module["__PyCode_CheckLineNumber"]=(a0,a1)=>(__PyCode_CheckLineNumber=Module["__PyCode_CheckLineNumber"]=wasmExports["_PyCode_CheckLineNumber"])(a0,a1);var _PyCode_Addr2Location=Module["_PyCode_Addr2Location"]=(a0,a1,a2,a3,a4,a5)=>(_PyCode_Addr2Location=Module["_PyCode_Addr2Location"]=wasmExports["PyCode_Addr2Location"])(a0,a1,a2,a3,a4,a5);var _PyUnstable_Code_GetExtra=Module["_PyUnstable_Code_GetExtra"]=(a0,a1,a2)=>(_PyUnstable_Code_GetExtra=Module["_PyUnstable_Code_GetExtra"]=wasmExports["PyUnstable_Code_GetExtra"])(a0,a1,a2);var _PyUnstable_Code_SetExtra=Module["_PyUnstable_Code_SetExtra"]=(a0,a1,a2)=>(_PyUnstable_Code_SetExtra=Module["_PyUnstable_Code_SetExtra"]=wasmExports["PyUnstable_Code_SetExtra"])(a0,a1,a2);var _PyCode_GetVarnames=Module["_PyCode_GetVarnames"]=a0=>(_PyCode_GetVarnames=Module["_PyCode_GetVarnames"]=wasmExports["PyCode_GetVarnames"])(a0);var _PyCode_GetCellvars=Module["_PyCode_GetCellvars"]=a0=>(_PyCode_GetCellvars=Module["_PyCode_GetCellvars"]=wasmExports["PyCode_GetCellvars"])(a0);var _PyCode_GetFreevars=Module["_PyCode_GetFreevars"]=a0=>(_PyCode_GetFreevars=Module["_PyCode_GetFreevars"]=wasmExports["PyCode_GetFreevars"])(a0);var _PyCode_GetCode=Module["_PyCode_GetCode"]=a0=>(_PyCode_GetCode=Module["_PyCode_GetCode"]=wasmExports["PyCode_GetCode"])(a0);var __PyCode_ConstantKey=Module["__PyCode_ConstantKey"]=a0=>(__PyCode_ConstantKey=Module["__PyCode_ConstantKey"]=wasmExports["_PyCode_ConstantKey"])(a0);var _PyComplex_AsCComplex=Module["_PyComplex_AsCComplex"]=(a0,a1)=>(_PyComplex_AsCComplex=Module["_PyComplex_AsCComplex"]=wasmExports["PyComplex_AsCComplex"])(a0,a1);var __PySet_NextEntry=Module["__PySet_NextEntry"]=(a0,a1,a2,a3)=>(__PySet_NextEntry=Module["__PySet_NextEntry"]=wasmExports["_PySet_NextEntry"])(a0,a1,a2,a3);var _PyLong_FromVoidPtr=Module["_PyLong_FromVoidPtr"]=a0=>(_PyLong_FromVoidPtr=Module["_PyLong_FromVoidPtr"]=wasmExports["PyLong_FromVoidPtr"])(a0);var __PyUnicode_FromASCII=Module["__PyUnicode_FromASCII"]=(a0,a1)=>(__PyUnicode_FromASCII=Module["__PyUnicode_FromASCII"]=wasmExports["_PyUnicode_FromASCII"])(a0,a1);var _PyErr_WriteUnraisable=Module["_PyErr_WriteUnraisable"]=a0=>(_PyErr_WriteUnraisable=Module["_PyErr_WriteUnraisable"]=wasmExports["PyErr_WriteUnraisable"])(a0);var __PyUnicode_Copy=Module["__PyUnicode_Copy"]=a0=>(__PyUnicode_Copy=Module["__PyUnicode_Copy"]=wasmExports["_PyUnicode_Copy"])(a0);var __Py_c_sum=Module["__Py_c_sum"]=(a0,a1,a2)=>(__Py_c_sum=Module["__Py_c_sum"]=wasmExports["_Py_c_sum"])(a0,a1,a2);var __Py_c_diff=Module["__Py_c_diff"]=(a0,a1,a2)=>(__Py_c_diff=Module["__Py_c_diff"]=wasmExports["_Py_c_diff"])(a0,a1,a2);var __Py_c_neg=Module["__Py_c_neg"]=(a0,a1)=>(__Py_c_neg=Module["__Py_c_neg"]=wasmExports["_Py_c_neg"])(a0,a1);var __Py_c_prod=Module["__Py_c_prod"]=(a0,a1,a2)=>(__Py_c_prod=Module["__Py_c_prod"]=wasmExports["_Py_c_prod"])(a0,a1,a2);var __Py_c_quot=Module["__Py_c_quot"]=(a0,a1,a2)=>(__Py_c_quot=Module["__Py_c_quot"]=wasmExports["_Py_c_quot"])(a0,a1,a2);var __Py_c_pow=Module["__Py_c_pow"]=(a0,a1,a2)=>(__Py_c_pow=Module["__Py_c_pow"]=wasmExports["_Py_c_pow"])(a0,a1,a2);var _hypot=Module["_hypot"]=(a0,a1)=>(_hypot=Module["_hypot"]=wasmExports["hypot"])(a0,a1);var _atan2=Module["_atan2"]=(a0,a1)=>(_atan2=Module["_atan2"]=wasmExports["atan2"])(a0,a1);var _pow=Module["_pow"]=(a0,a1)=>(_pow=Module["_pow"]=wasmExports["pow"])(a0,a1);var _log=Module["_log"]=a0=>(_log=Module["_log"]=wasmExports["log"])(a0);var _exp=Module["_exp"]=a0=>(_exp=Module["_exp"]=wasmExports["exp"])(a0);var _sin=Module["_sin"]=a0=>(_sin=Module["_sin"]=wasmExports["sin"])(a0);var _cos=Module["_cos"]=a0=>(_cos=Module["_cos"]=wasmExports["cos"])(a0);var __Py_c_abs=Module["__Py_c_abs"]=a0=>(__Py_c_abs=Module["__Py_c_abs"]=wasmExports["_Py_c_abs"])(a0);var _PyComplex_FromDoubles=Module["_PyComplex_FromDoubles"]=(a0,a1)=>(_PyComplex_FromDoubles=Module["_PyComplex_FromDoubles"]=wasmExports["PyComplex_FromDoubles"])(a0,a1);var _PyComplex_RealAsDouble=Module["_PyComplex_RealAsDouble"]=a0=>(_PyComplex_RealAsDouble=Module["_PyComplex_RealAsDouble"]=wasmExports["PyComplex_RealAsDouble"])(a0);var _PyComplex_ImagAsDouble=Module["_PyComplex_ImagAsDouble"]=a0=>(_PyComplex_ImagAsDouble=Module["_PyComplex_ImagAsDouble"]=wasmExports["PyComplex_ImagAsDouble"])(a0);var __Py_HashDouble=Module["__Py_HashDouble"]=(a0,a1)=>(__Py_HashDouble=Module["__Py_HashDouble"]=wasmExports["_Py_HashDouble"])(a0,a1);var __PyUnicode_TransformDecimalAndSpaceToASCII=Module["__PyUnicode_TransformDecimalAndSpaceToASCII"]=a0=>(__PyUnicode_TransformDecimalAndSpaceToASCII=Module["__PyUnicode_TransformDecimalAndSpaceToASCII"]=wasmExports["_PyUnicode_TransformDecimalAndSpaceToASCII"])(a0);var __Py_string_to_number_with_underscores=Module["__Py_string_to_number_with_underscores"]=(a0,a1,a2,a3,a4,a5)=>(__Py_string_to_number_with_underscores=Module["__Py_string_to_number_with_underscores"]=wasmExports["_Py_string_to_number_with_underscores"])(a0,a1,a2,a3,a4,a5);var _PyCMethod_New=Module["_PyCMethod_New"]=(a0,a1,a2,a3)=>(_PyCMethod_New=Module["_PyCMethod_New"]=wasmExports["PyCMethod_New"])(a0,a1,a2,a3);var _PyMember_GetOne=Module["_PyMember_GetOne"]=(a0,a1)=>(_PyMember_GetOne=Module["_PyMember_GetOne"]=wasmExports["PyMember_GetOne"])(a0,a1);var _PyMember_SetOne=Module["_PyMember_SetOne"]=(a0,a1,a2)=>(_PyMember_SetOne=Module["_PyMember_SetOne"]=wasmExports["PyMember_SetOne"])(a0,a1,a2);var _PyTuple_GetSlice=Module["_PyTuple_GetSlice"]=(a0,a1,a2)=>(_PyTuple_GetSlice=Module["_PyTuple_GetSlice"]=wasmExports["PyTuple_GetSlice"])(a0,a1,a2);var _PyDescr_NewMethod=Module["_PyDescr_NewMethod"]=(a0,a1)=>(_PyDescr_NewMethod=Module["_PyDescr_NewMethod"]=wasmExports["PyDescr_NewMethod"])(a0,a1);var __PyObject_FunctionStr=Module["__PyObject_FunctionStr"]=a0=>(__PyObject_FunctionStr=Module["__PyObject_FunctionStr"]=wasmExports["_PyObject_FunctionStr"])(a0);var _PyDescr_NewClassMethod=Module["_PyDescr_NewClassMethod"]=(a0,a1)=>(_PyDescr_NewClassMethod=Module["_PyDescr_NewClassMethod"]=wasmExports["PyDescr_NewClassMethod"])(a0,a1);var _PyDescr_NewMember=Module["_PyDescr_NewMember"]=(a0,a1)=>(_PyDescr_NewMember=Module["_PyDescr_NewMember"]=wasmExports["PyDescr_NewMember"])(a0,a1);var _PyDescr_NewGetSet=Module["_PyDescr_NewGetSet"]=(a0,a1)=>(_PyDescr_NewGetSet=Module["_PyDescr_NewGetSet"]=wasmExports["PyDescr_NewGetSet"])(a0,a1);var _PyDescr_NewWrapper=Module["_PyDescr_NewWrapper"]=(a0,a1,a2)=>(_PyDescr_NewWrapper=Module["_PyDescr_NewWrapper"]=wasmExports["PyDescr_NewWrapper"])(a0,a1,a2);var _PyDescr_IsData=Module["_PyDescr_IsData"]=a0=>(_PyDescr_IsData=Module["_PyDescr_IsData"]=wasmExports["PyDescr_IsData"])(a0);var _PyDictProxy_New=Module["_PyDictProxy_New"]=a0=>(_PyDictProxy_New=Module["_PyDictProxy_New"]=wasmExports["PyDictProxy_New"])(a0);var __PyTrash_cond=Module["__PyTrash_cond"]=(a0,a1)=>(__PyTrash_cond=Module["__PyTrash_cond"]=wasmExports["_PyTrash_cond"])(a0,a1);var __PyThreadState_UncheckedGet=Module["__PyThreadState_UncheckedGet"]=()=>(__PyThreadState_UncheckedGet=Module["__PyThreadState_UncheckedGet"]=wasmExports["_PyThreadState_UncheckedGet"])();var __PyTrash_begin=Module["__PyTrash_begin"]=(a0,a1)=>(__PyTrash_begin=Module["__PyTrash_begin"]=wasmExports["_PyTrash_begin"])(a0,a1);var __PyTrash_end=Module["__PyTrash_end"]=a0=>(__PyTrash_end=Module["__PyTrash_end"]=wasmExports["_PyTrash_end"])(a0);var _PyWrapper_New=Module["_PyWrapper_New"]=(a0,a1)=>(_PyWrapper_New=Module["_PyWrapper_New"]=wasmExports["PyWrapper_New"])(a0,a1);var _PyType_GetQualName=Module["_PyType_GetQualName"]=a0=>(_PyType_GetQualName=Module["_PyType_GetQualName"]=wasmExports["PyType_GetQualName"])(a0);var __PyType_GetDocFromInternalDoc=Module["__PyType_GetDocFromInternalDoc"]=(a0,a1)=>(__PyType_GetDocFromInternalDoc=Module["__PyType_GetDocFromInternalDoc"]=wasmExports["_PyType_GetDocFromInternalDoc"])(a0,a1);var __PyType_GetTextSignatureFromInternalDoc=Module["__PyType_GetTextSignatureFromInternalDoc"]=(a0,a1)=>(__PyType_GetTextSignatureFromInternalDoc=Module["__PyType_GetTextSignatureFromInternalDoc"]=wasmExports["_PyType_GetTextSignatureFromInternalDoc"])(a0,a1);var _PyDict_Contains=Module["_PyDict_Contains"]=(a0,a1)=>(_PyDict_Contains=Module["_PyDict_Contains"]=wasmExports["PyDict_Contains"])(a0,a1);var __PyArg_UnpackStack=Module["__PyArg_UnpackStack"]=(a0,a1,a2,a3,a4,a5)=>(__PyArg_UnpackStack=Module["__PyArg_UnpackStack"]=wasmExports["_PyArg_UnpackStack"])(a0,a1,a2,a3,a4,a5);var __PyObject_IsAbstract=Module["__PyObject_IsAbstract"]=a0=>(__PyObject_IsAbstract=Module["__PyObject_IsAbstract"]=wasmExports["_PyObject_IsAbstract"])(a0);var _PyException_GetCause=Module["_PyException_GetCause"]=a0=>(_PyException_GetCause=Module["_PyException_GetCause"]=wasmExports["PyException_GetCause"])(a0);var _PyException_SetCause=Module["_PyException_SetCause"]=(a0,a1)=>(_PyException_SetCause=Module["_PyException_SetCause"]=wasmExports["PyException_SetCause"])(a0,a1);var _PyException_GetContext=Module["_PyException_GetContext"]=a0=>(_PyException_GetContext=Module["_PyException_GetContext"]=wasmExports["PyException_GetContext"])(a0);var _PyException_SetContext=Module["_PyException_SetContext"]=(a0,a1)=>(_PyException_SetContext=Module["_PyException_SetContext"]=wasmExports["PyException_SetContext"])(a0,a1);var _PyException_GetArgs=Module["_PyException_GetArgs"]=a0=>(_PyException_GetArgs=Module["_PyException_GetArgs"]=wasmExports["PyException_GetArgs"])(a0);var _PyException_SetArgs=Module["_PyException_SetArgs"]=(a0,a1)=>(_PyException_SetArgs=Module["_PyException_SetArgs"]=wasmExports["PyException_SetArgs"])(a0,a1);var _PyExceptionClass_Name=Module["_PyExceptionClass_Name"]=a0=>(_PyExceptionClass_Name=Module["_PyExceptionClass_Name"]=wasmExports["PyExceptionClass_Name"])(a0);var __PyExc_CreateExceptionGroup=Module["__PyExc_CreateExceptionGroup"]=(a0,a1)=>(__PyExc_CreateExceptionGroup=Module["__PyExc_CreateExceptionGroup"]=wasmExports["_PyExc_CreateExceptionGroup"])(a0,a1);var __PyExc_PrepReraiseStar=Module["__PyExc_PrepReraiseStar"]=(a0,a1)=>(__PyExc_PrepReraiseStar=Module["__PyExc_PrepReraiseStar"]=wasmExports["_PyExc_PrepReraiseStar"])(a0,a1);var _PyUnstable_Exc_PrepReraiseStar=Module["_PyUnstable_Exc_PrepReraiseStar"]=(a0,a1)=>(_PyUnstable_Exc_PrepReraiseStar=Module["_PyUnstable_Exc_PrepReraiseStar"]=wasmExports["PyUnstable_Exc_PrepReraiseStar"])(a0,a1);var _PyUnicodeEncodeError_GetEncoding=Module["_PyUnicodeEncodeError_GetEncoding"]=a0=>(_PyUnicodeEncodeError_GetEncoding=Module["_PyUnicodeEncodeError_GetEncoding"]=wasmExports["PyUnicodeEncodeError_GetEncoding"])(a0);var _PyUnicodeDecodeError_GetEncoding=Module["_PyUnicodeDecodeError_GetEncoding"]=a0=>(_PyUnicodeDecodeError_GetEncoding=Module["_PyUnicodeDecodeError_GetEncoding"]=wasmExports["PyUnicodeDecodeError_GetEncoding"])(a0);var _PyUnicodeEncodeError_GetObject=Module["_PyUnicodeEncodeError_GetObject"]=a0=>(_PyUnicodeEncodeError_GetObject=Module["_PyUnicodeEncodeError_GetObject"]=wasmExports["PyUnicodeEncodeError_GetObject"])(a0);var _PyUnicodeDecodeError_GetObject=Module["_PyUnicodeDecodeError_GetObject"]=a0=>(_PyUnicodeDecodeError_GetObject=Module["_PyUnicodeDecodeError_GetObject"]=wasmExports["PyUnicodeDecodeError_GetObject"])(a0);var _PyUnicodeTranslateError_GetObject=Module["_PyUnicodeTranslateError_GetObject"]=a0=>(_PyUnicodeTranslateError_GetObject=Module["_PyUnicodeTranslateError_GetObject"]=wasmExports["PyUnicodeTranslateError_GetObject"])(a0);var _PyUnicodeEncodeError_GetStart=Module["_PyUnicodeEncodeError_GetStart"]=(a0,a1)=>(_PyUnicodeEncodeError_GetStart=Module["_PyUnicodeEncodeError_GetStart"]=wasmExports["PyUnicodeEncodeError_GetStart"])(a0,a1);var _PyUnicodeDecodeError_GetStart=Module["_PyUnicodeDecodeError_GetStart"]=(a0,a1)=>(_PyUnicodeDecodeError_GetStart=Module["_PyUnicodeDecodeError_GetStart"]=wasmExports["PyUnicodeDecodeError_GetStart"])(a0,a1);var _PyUnicodeTranslateError_GetStart=Module["_PyUnicodeTranslateError_GetStart"]=(a0,a1)=>(_PyUnicodeTranslateError_GetStart=Module["_PyUnicodeTranslateError_GetStart"]=wasmExports["PyUnicodeTranslateError_GetStart"])(a0,a1);var _PyUnicodeEncodeError_SetStart=Module["_PyUnicodeEncodeError_SetStart"]=(a0,a1)=>(_PyUnicodeEncodeError_SetStart=Module["_PyUnicodeEncodeError_SetStart"]=wasmExports["PyUnicodeEncodeError_SetStart"])(a0,a1);var _PyUnicodeDecodeError_SetStart=Module["_PyUnicodeDecodeError_SetStart"]=(a0,a1)=>(_PyUnicodeDecodeError_SetStart=Module["_PyUnicodeDecodeError_SetStart"]=wasmExports["PyUnicodeDecodeError_SetStart"])(a0,a1);var _PyUnicodeTranslateError_SetStart=Module["_PyUnicodeTranslateError_SetStart"]=(a0,a1)=>(_PyUnicodeTranslateError_SetStart=Module["_PyUnicodeTranslateError_SetStart"]=wasmExports["PyUnicodeTranslateError_SetStart"])(a0,a1);var _PyUnicodeEncodeError_GetEnd=Module["_PyUnicodeEncodeError_GetEnd"]=(a0,a1)=>(_PyUnicodeEncodeError_GetEnd=Module["_PyUnicodeEncodeError_GetEnd"]=wasmExports["PyUnicodeEncodeError_GetEnd"])(a0,a1);var _PyUnicodeDecodeError_GetEnd=Module["_PyUnicodeDecodeError_GetEnd"]=(a0,a1)=>(_PyUnicodeDecodeError_GetEnd=Module["_PyUnicodeDecodeError_GetEnd"]=wasmExports["PyUnicodeDecodeError_GetEnd"])(a0,a1);var _PyUnicodeTranslateError_GetEnd=Module["_PyUnicodeTranslateError_GetEnd"]=(a0,a1)=>(_PyUnicodeTranslateError_GetEnd=Module["_PyUnicodeTranslateError_GetEnd"]=wasmExports["PyUnicodeTranslateError_GetEnd"])(a0,a1);var _PyUnicodeEncodeError_SetEnd=Module["_PyUnicodeEncodeError_SetEnd"]=(a0,a1)=>(_PyUnicodeEncodeError_SetEnd=Module["_PyUnicodeEncodeError_SetEnd"]=wasmExports["PyUnicodeEncodeError_SetEnd"])(a0,a1);var _PyUnicodeDecodeError_SetEnd=Module["_PyUnicodeDecodeError_SetEnd"]=(a0,a1)=>(_PyUnicodeDecodeError_SetEnd=Module["_PyUnicodeDecodeError_SetEnd"]=wasmExports["PyUnicodeDecodeError_SetEnd"])(a0,a1);var _PyUnicodeTranslateError_SetEnd=Module["_PyUnicodeTranslateError_SetEnd"]=(a0,a1)=>(_PyUnicodeTranslateError_SetEnd=Module["_PyUnicodeTranslateError_SetEnd"]=wasmExports["PyUnicodeTranslateError_SetEnd"])(a0,a1);var _PyUnicodeEncodeError_GetReason=Module["_PyUnicodeEncodeError_GetReason"]=a0=>(_PyUnicodeEncodeError_GetReason=Module["_PyUnicodeEncodeError_GetReason"]=wasmExports["PyUnicodeEncodeError_GetReason"])(a0);var _PyUnicodeDecodeError_GetReason=Module["_PyUnicodeDecodeError_GetReason"]=a0=>(_PyUnicodeDecodeError_GetReason=Module["_PyUnicodeDecodeError_GetReason"]=wasmExports["PyUnicodeDecodeError_GetReason"])(a0);var _PyUnicodeTranslateError_GetReason=Module["_PyUnicodeTranslateError_GetReason"]=a0=>(_PyUnicodeTranslateError_GetReason=Module["_PyUnicodeTranslateError_GetReason"]=wasmExports["PyUnicodeTranslateError_GetReason"])(a0);var _PyUnicodeEncodeError_SetReason=Module["_PyUnicodeEncodeError_SetReason"]=(a0,a1)=>(_PyUnicodeEncodeError_SetReason=Module["_PyUnicodeEncodeError_SetReason"]=wasmExports["PyUnicodeEncodeError_SetReason"])(a0,a1);var _PyUnicodeDecodeError_SetReason=Module["_PyUnicodeDecodeError_SetReason"]=(a0,a1)=>(_PyUnicodeDecodeError_SetReason=Module["_PyUnicodeDecodeError_SetReason"]=wasmExports["PyUnicodeDecodeError_SetReason"])(a0,a1);var _PyUnicodeTranslateError_SetReason=Module["_PyUnicodeTranslateError_SetReason"]=(a0,a1)=>(_PyUnicodeTranslateError_SetReason=Module["_PyUnicodeTranslateError_SetReason"]=wasmExports["PyUnicodeTranslateError_SetReason"])(a0,a1);var _PyUnicodeDecodeError_Create=Module["_PyUnicodeDecodeError_Create"]=(a0,a1,a2,a3,a4,a5)=>(_PyUnicodeDecodeError_Create=Module["_PyUnicodeDecodeError_Create"]=wasmExports["PyUnicodeDecodeError_Create"])(a0,a1,a2,a3,a4,a5);var __PyUnicodeTranslateError_Create=Module["__PyUnicodeTranslateError_Create"]=(a0,a1,a2,a3)=>(__PyUnicodeTranslateError_Create=Module["__PyUnicodeTranslateError_Create"]=wasmExports["_PyUnicodeTranslateError_Create"])(a0,a1,a2,a3);var _PyModule_GetDict=Module["_PyModule_GetDict"]=a0=>(_PyModule_GetDict=Module["_PyModule_GetDict"]=wasmExports["PyModule_GetDict"])(a0);var _PyErr_NewException=Module["_PyErr_NewException"]=(a0,a1,a2)=>(_PyErr_NewException=Module["_PyErr_NewException"]=wasmExports["PyErr_NewException"])(a0,a1,a2);var __PyException_AddNote=Module["__PyException_AddNote"]=(a0,a1)=>(__PyException_AddNote=Module["__PyException_AddNote"]=wasmExports["_PyException_AddNote"])(a0,a1);var _PySet_Add=Module["_PySet_Add"]=(a0,a1)=>(_PySet_Add=Module["_PySet_Add"]=wasmExports["PySet_Add"])(a0,a1);var _PySet_Contains=Module["_PySet_Contains"]=(a0,a1)=>(_PySet_Contains=Module["_PySet_Contains"]=wasmExports["PySet_Contains"])(a0,a1);var _PyTuple_Size=Module["_PyTuple_Size"]=a0=>(_PyTuple_Size=Module["_PyTuple_Size"]=wasmExports["PyTuple_Size"])(a0);var _PyDict_Copy=Module["_PyDict_Copy"]=a0=>(_PyDict_Copy=Module["_PyDict_Copy"]=wasmExports["PyDict_Copy"])(a0);var _PyUnicode_ReadChar=Module["_PyUnicode_ReadChar"]=(a0,a1)=>(_PyUnicode_ReadChar=Module["_PyUnicode_ReadChar"]=wasmExports["PyUnicode_ReadChar"])(a0,a1);var _PyObject_GenericGetDict=Module["_PyObject_GenericGetDict"]=(a0,a1)=>(_PyObject_GenericGetDict=Module["_PyObject_GenericGetDict"]=wasmExports["PyObject_GenericGetDict"])(a0,a1);var _PyObject_GenericSetDict=Module["_PyObject_GenericSetDict"]=(a0,a1,a2)=>(_PyObject_GenericSetDict=Module["_PyObject_GenericSetDict"]=wasmExports["PyObject_GenericSetDict"])(a0,a1,a2);var _PyList_SetSlice=Module["_PyList_SetSlice"]=(a0,a1,a2,a3)=>(_PyList_SetSlice=Module["_PyList_SetSlice"]=wasmExports["PyList_SetSlice"])(a0,a1,a2,a3);var __PyUnicodeWriter_WriteASCIIString=Module["__PyUnicodeWriter_WriteASCIIString"]=(a0,a1,a2)=>(__PyUnicodeWriter_WriteASCIIString=Module["__PyUnicodeWriter_WriteASCIIString"]=wasmExports["_PyUnicodeWriter_WriteASCIIString"])(a0,a1,a2);var _PyObject_GC_Track=Module["_PyObject_GC_Track"]=a0=>(_PyObject_GC_Track=Module["_PyObject_GC_Track"]=wasmExports["PyObject_GC_Track"])(a0);var __PyGen_Finalize=Module["__PyGen_Finalize"]=a0=>(__PyGen_Finalize=Module["__PyGen_Finalize"]=wasmExports["_PyGen_Finalize"])(a0);var _PyObject_CallFinalizerFromDealloc=Module["_PyObject_CallFinalizerFromDealloc"]=a0=>(_PyObject_CallFinalizerFromDealloc=Module["_PyObject_CallFinalizerFromDealloc"]=wasmExports["PyObject_CallFinalizerFromDealloc"])(a0);var __PyObject_GC_NewVar=Module["__PyObject_GC_NewVar"]=(a0,a1)=>(__PyObject_GC_NewVar=Module["__PyObject_GC_NewVar"]=wasmExports["_PyObject_GC_NewVar"])(a0,a1);var _PyUnstable_InterpreterFrame_GetLine=Module["_PyUnstable_InterpreterFrame_GetLine"]=a0=>(_PyUnstable_InterpreterFrame_GetLine=Module["_PyUnstable_InterpreterFrame_GetLine"]=wasmExports["PyUnstable_InterpreterFrame_GetLine"])(a0);var _PyGen_NewWithQualName=Module["_PyGen_NewWithQualName"]=(a0,a1,a2)=>(_PyGen_NewWithQualName=Module["_PyGen_NewWithQualName"]=wasmExports["PyGen_NewWithQualName"])(a0,a1,a2);var _PyGen_New=Module["_PyGen_New"]=a0=>(_PyGen_New=Module["_PyGen_New"]=wasmExports["PyGen_New"])(a0);var _PyCoro_New=Module["_PyCoro_New"]=(a0,a1,a2)=>(_PyCoro_New=Module["_PyCoro_New"]=wasmExports["PyCoro_New"])(a0,a1,a2);var _PyAsyncGen_New=Module["_PyAsyncGen_New"]=(a0,a1,a2)=>(_PyAsyncGen_New=Module["_PyAsyncGen_New"]=wasmExports["PyAsyncGen_New"])(a0,a1,a2);var __PyErr_ChainStackItem=Module["__PyErr_ChainStackItem"]=a0=>(__PyErr_ChainStackItem=Module["__PyErr_ChainStackItem"]=wasmExports["_PyErr_ChainStackItem"])(a0);var __PyEval_EvalFrameDefault=Module["__PyEval_EvalFrameDefault"]=(a0,a1,a2)=>(__PyEval_EvalFrameDefault=Module["__PyEval_EvalFrameDefault"]=wasmExports["_PyEval_EvalFrameDefault"])(a0,a1,a2);var _PyFile_FromFd=Module["_PyFile_FromFd"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(_PyFile_FromFd=Module["_PyFile_FromFd"]=wasmExports["PyFile_FromFd"])(a0,a1,a2,a3,a4,a5,a6,a7);var _PyFile_GetLine=Module["_PyFile_GetLine"]=(a0,a1)=>(_PyFile_GetLine=Module["_PyFile_GetLine"]=wasmExports["PyFile_GetLine"])(a0,a1);var _PyFile_WriteObject=Module["_PyFile_WriteObject"]=(a0,a1,a2)=>(_PyFile_WriteObject=Module["_PyFile_WriteObject"]=wasmExports["PyFile_WriteObject"])(a0,a1,a2);var _PyFile_WriteString=Module["_PyFile_WriteString"]=(a0,a1)=>(_PyFile_WriteString=Module["_PyFile_WriteString"]=wasmExports["PyFile_WriteString"])(a0,a1);var _PyObject_AsFileDescriptor=Module["_PyObject_AsFileDescriptor"]=a0=>(_PyObject_AsFileDescriptor=Module["_PyObject_AsFileDescriptor"]=wasmExports["PyObject_AsFileDescriptor"])(a0);var __PyLong_FileDescriptor_Converter=Module["__PyLong_FileDescriptor_Converter"]=(a0,a1)=>(__PyLong_FileDescriptor_Converter=Module["__PyLong_FileDescriptor_Converter"]=wasmExports["_PyLong_FileDescriptor_Converter"])(a0,a1);var _flockfile=Module["_flockfile"]=a0=>(_flockfile=Module["_flockfile"]=wasmExports["flockfile"])(a0);var _getc_unlocked=Module["_getc_unlocked"]=a0=>(_getc_unlocked=Module["_getc_unlocked"]=wasmExports["getc_unlocked"])(a0);var _funlockfile=Module["_funlockfile"]=a0=>(_funlockfile=Module["_funlockfile"]=wasmExports["funlockfile"])(a0);var _Py_UniversalNewlineFgets=Module["_Py_UniversalNewlineFgets"]=(a0,a1,a2,a3)=>(_Py_UniversalNewlineFgets=Module["_Py_UniversalNewlineFgets"]=wasmExports["Py_UniversalNewlineFgets"])(a0,a1,a2,a3);var _PyFile_NewStdPrinter=Module["_PyFile_NewStdPrinter"]=a0=>(_PyFile_NewStdPrinter=Module["_PyFile_NewStdPrinter"]=wasmExports["PyFile_NewStdPrinter"])(a0);var _PyFile_SetOpenCodeHook=Module["_PyFile_SetOpenCodeHook"]=(a0,a1)=>(_PyFile_SetOpenCodeHook=Module["_PyFile_SetOpenCodeHook"]=wasmExports["PyFile_SetOpenCodeHook"])(a0,a1);var _Py_IsInitialized=Module["_Py_IsInitialized"]=()=>(_Py_IsInitialized=Module["_Py_IsInitialized"]=wasmExports["Py_IsInitialized"])();var _PyFile_OpenCodeObject=Module["_PyFile_OpenCodeObject"]=a0=>(_PyFile_OpenCodeObject=Module["_PyFile_OpenCodeObject"]=wasmExports["PyFile_OpenCodeObject"])(a0);var _PyFile_OpenCode=Module["_PyFile_OpenCode"]=a0=>(_PyFile_OpenCode=Module["_PyFile_OpenCode"]=wasmExports["PyFile_OpenCode"])(a0);var __PyUnicode_AsUTF8String=Module["__PyUnicode_AsUTF8String"]=(a0,a1)=>(__PyUnicode_AsUTF8String=Module["__PyUnicode_AsUTF8String"]=wasmExports["_PyUnicode_AsUTF8String"])(a0,a1);var __Py_write=Module["__Py_write"]=(a0,a1,a2)=>(__Py_write=Module["__Py_write"]=wasmExports["_Py_write"])(a0,a1,a2);var _PyFloat_GetMax=Module["_PyFloat_GetMax"]=()=>(_PyFloat_GetMax=Module["_PyFloat_GetMax"]=wasmExports["PyFloat_GetMax"])();var _PyFloat_GetMin=Module["_PyFloat_GetMin"]=()=>(_PyFloat_GetMin=Module["_PyFloat_GetMin"]=wasmExports["PyFloat_GetMin"])();var _PyFloat_GetInfo=Module["_PyFloat_GetInfo"]=()=>(_PyFloat_GetInfo=Module["_PyFloat_GetInfo"]=wasmExports["PyFloat_GetInfo"])();var _PyStructSequence_New=Module["_PyStructSequence_New"]=a0=>(_PyStructSequence_New=Module["_PyStructSequence_New"]=wasmExports["PyStructSequence_New"])(a0);var __PyLong_Sign=Module["__PyLong_Sign"]=a0=>(__PyLong_Sign=Module["__PyLong_Sign"]=wasmExports["_PyLong_Sign"])(a0);var _frexp=Module["_frexp"]=(a0,a1)=>(_frexp=Module["_frexp"]=wasmExports["frexp"])(a0,a1);var _modf=Module["_modf"]=(a0,a1)=>(_modf=Module["_modf"]=wasmExports["modf"])(a0,a1);var _PyLong_FromDouble=Module["_PyLong_FromDouble"]=a0=>(_PyLong_FromDouble=Module["_PyLong_FromDouble"]=wasmExports["PyLong_FromDouble"])(a0);var __PyLong_Lshift=Module["__PyLong_Lshift"]=(a0,a1)=>(__PyLong_Lshift=Module["__PyLong_Lshift"]=wasmExports["_PyLong_Lshift"])(a0,a1);var __PyFloat_DebugMallocStats=Module["__PyFloat_DebugMallocStats"]=a0=>(__PyFloat_DebugMallocStats=Module["__PyFloat_DebugMallocStats"]=wasmExports["_PyFloat_DebugMallocStats"])(a0);var __PyDebugAllocatorStats=Module["__PyDebugAllocatorStats"]=(a0,a1,a2,a3)=>(__PyDebugAllocatorStats=Module["__PyDebugAllocatorStats"]=wasmExports["_PyDebugAllocatorStats"])(a0,a1,a2,a3);var _PyFloat_Pack2=Module["_PyFloat_Pack2"]=(a0,a1,a2)=>(_PyFloat_Pack2=Module["_PyFloat_Pack2"]=wasmExports["PyFloat_Pack2"])(a0,a1,a2);var _ldexp=Module["_ldexp"]=(a0,a1)=>(_ldexp=Module["_ldexp"]=wasmExports["ldexp"])(a0,a1);var _PyFloat_Pack4=Module["_PyFloat_Pack4"]=(a0,a1,a2)=>(_PyFloat_Pack4=Module["_PyFloat_Pack4"]=wasmExports["PyFloat_Pack4"])(a0,a1,a2);var _PyFloat_Pack8=Module["_PyFloat_Pack8"]=(a0,a1,a2)=>(_PyFloat_Pack8=Module["_PyFloat_Pack8"]=wasmExports["PyFloat_Pack8"])(a0,a1,a2);var _PyFloat_Unpack2=Module["_PyFloat_Unpack2"]=(a0,a1)=>(_PyFloat_Unpack2=Module["_PyFloat_Unpack2"]=wasmExports["PyFloat_Unpack2"])(a0,a1);var _PyFloat_Unpack4=Module["_PyFloat_Unpack4"]=(a0,a1)=>(_PyFloat_Unpack4=Module["_PyFloat_Unpack4"]=wasmExports["PyFloat_Unpack4"])(a0,a1);var _PyFloat_Unpack8=Module["_PyFloat_Unpack8"]=(a0,a1)=>(_PyFloat_Unpack8=Module["_PyFloat_Unpack8"]=wasmExports["PyFloat_Unpack8"])(a0,a1);var _fmod=Module["_fmod"]=(a0,a1)=>(_fmod=Module["_fmod"]=wasmExports["fmod"])(a0,a1);var _PyErr_SetFromErrno=Module["_PyErr_SetFromErrno"]=a0=>(_PyErr_SetFromErrno=Module["_PyErr_SetFromErrno"]=wasmExports["PyErr_SetFromErrno"])(a0);var _round=Module["_round"]=a0=>(_round=Module["_round"]=wasmExports["round"])(a0);var __Py_dg_dtoa=Module["__Py_dg_dtoa"]=(a0,a1,a2,a3,a4,a5)=>(__Py_dg_dtoa=Module["__Py_dg_dtoa"]=wasmExports["_Py_dg_dtoa"])(a0,a1,a2,a3,a4,a5);var __Py_dg_strtod=Module["__Py_dg_strtod"]=(a0,a1)=>(__Py_dg_strtod=Module["__Py_dg_strtod"]=wasmExports["_Py_dg_strtod"])(a0,a1);var __Py_dg_freedtoa=Module["__Py_dg_freedtoa"]=a0=>(__Py_dg_freedtoa=Module["__Py_dg_freedtoa"]=wasmExports["_Py_dg_freedtoa"])(a0);var __Py_parse_inf_or_nan=Module["__Py_parse_inf_or_nan"]=(a0,a1)=>(__Py_parse_inf_or_nan=Module["__Py_parse_inf_or_nan"]=wasmExports["_Py_parse_inf_or_nan"])(a0,a1);var _strtol=Module["_strtol"]=(a0,a1,a2)=>(_strtol=Module["_strtol"]=wasmExports["strtol"])(a0,a1,a2);var __PyFloat_FormatAdvancedWriter=Module["__PyFloat_FormatAdvancedWriter"]=(a0,a1,a2,a3,a4)=>(__PyFloat_FormatAdvancedWriter=Module["__PyFloat_FormatAdvancedWriter"]=wasmExports["_PyFloat_FormatAdvancedWriter"])(a0,a1,a2,a3,a4);var _PyFrame_GetLineNumber=Module["_PyFrame_GetLineNumber"]=a0=>(_PyFrame_GetLineNumber=Module["_PyFrame_GetLineNumber"]=wasmExports["PyFrame_GetLineNumber"])(a0);var _PyFrame_New=Module["_PyFrame_New"]=(a0,a1,a2,a3)=>(_PyFrame_New=Module["_PyFrame_New"]=wasmExports["PyFrame_New"])(a0,a1,a2,a3);var _PyDict_Size=Module["_PyDict_Size"]=a0=>(_PyDict_Size=Module["_PyDict_Size"]=wasmExports["PyDict_Size"])(a0);var _PyDict_Merge=Module["_PyDict_Merge"]=(a0,a1,a2)=>(_PyDict_Merge=Module["_PyDict_Merge"]=wasmExports["PyDict_Merge"])(a0,a1,a2);var _PyFrame_GetVar=Module["_PyFrame_GetVar"]=(a0,a1)=>(_PyFrame_GetVar=Module["_PyFrame_GetVar"]=wasmExports["PyFrame_GetVar"])(a0,a1);var __PyUnicode_Equal=Module["__PyUnicode_Equal"]=(a0,a1)=>(__PyUnicode_Equal=Module["__PyUnicode_Equal"]=wasmExports["_PyUnicode_Equal"])(a0,a1);var _PyFrame_GetVarString=Module["_PyFrame_GetVarString"]=(a0,a1)=>(_PyFrame_GetVarString=Module["_PyFrame_GetVarString"]=wasmExports["PyFrame_GetVarString"])(a0,a1);var _PyFrame_FastToLocalsWithError=Module["_PyFrame_FastToLocalsWithError"]=a0=>(_PyFrame_FastToLocalsWithError=Module["_PyFrame_FastToLocalsWithError"]=wasmExports["PyFrame_FastToLocalsWithError"])(a0);var _PyFrame_FastToLocals=Module["_PyFrame_FastToLocals"]=a0=>(_PyFrame_FastToLocals=Module["_PyFrame_FastToLocals"]=wasmExports["PyFrame_FastToLocals"])(a0);var _PyFrame_LocalsToFast=Module["_PyFrame_LocalsToFast"]=(a0,a1)=>(_PyFrame_LocalsToFast=Module["_PyFrame_LocalsToFast"]=wasmExports["PyFrame_LocalsToFast"])(a0,a1);var __PyFrame_IsEntryFrame=Module["__PyFrame_IsEntryFrame"]=a0=>(__PyFrame_IsEntryFrame=Module["__PyFrame_IsEntryFrame"]=wasmExports["_PyFrame_IsEntryFrame"])(a0);var _PyFrame_GetCode=Module["_PyFrame_GetCode"]=a0=>(_PyFrame_GetCode=Module["_PyFrame_GetCode"]=wasmExports["PyFrame_GetCode"])(a0);var _PyFrame_GetBack=Module["_PyFrame_GetBack"]=a0=>(_PyFrame_GetBack=Module["_PyFrame_GetBack"]=wasmExports["PyFrame_GetBack"])(a0);var _PyFrame_GetLocals=Module["_PyFrame_GetLocals"]=a0=>(_PyFrame_GetLocals=Module["_PyFrame_GetLocals"]=wasmExports["PyFrame_GetLocals"])(a0);var _PyFrame_GetGlobals=Module["_PyFrame_GetGlobals"]=a0=>(_PyFrame_GetGlobals=Module["_PyFrame_GetGlobals"]=wasmExports["PyFrame_GetGlobals"])(a0);var _PyFrame_GetBuiltins=Module["_PyFrame_GetBuiltins"]=a0=>(_PyFrame_GetBuiltins=Module["_PyFrame_GetBuiltins"]=wasmExports["PyFrame_GetBuiltins"])(a0);var _PyFrame_GetLasti=Module["_PyFrame_GetLasti"]=a0=>(_PyFrame_GetLasti=Module["_PyFrame_GetLasti"]=wasmExports["PyFrame_GetLasti"])(a0);var _PyFrame_GetGenerator=Module["_PyFrame_GetGenerator"]=a0=>(_PyFrame_GetGenerator=Module["_PyFrame_GetGenerator"]=wasmExports["PyFrame_GetGenerator"])(a0);var _PyCompile_OpcodeStackEffect=Module["_PyCompile_OpcodeStackEffect"]=(a0,a1)=>(_PyCompile_OpcodeStackEffect=Module["_PyCompile_OpcodeStackEffect"]=wasmExports["PyCompile_OpcodeStackEffect"])(a0,a1);var _PyFunction_AddWatcher=Module["_PyFunction_AddWatcher"]=a0=>(_PyFunction_AddWatcher=Module["_PyFunction_AddWatcher"]=wasmExports["PyFunction_AddWatcher"])(a0);var _PyFunction_ClearWatcher=Module["_PyFunction_ClearWatcher"]=a0=>(_PyFunction_ClearWatcher=Module["_PyFunction_ClearWatcher"]=wasmExports["PyFunction_ClearWatcher"])(a0);var _PyFunction_NewWithQualName=Module["_PyFunction_NewWithQualName"]=(a0,a1,a2)=>(_PyFunction_NewWithQualName=Module["_PyFunction_NewWithQualName"]=wasmExports["PyFunction_NewWithQualName"])(a0,a1,a2);var _PyFunction_New=Module["_PyFunction_New"]=(a0,a1)=>(_PyFunction_New=Module["_PyFunction_New"]=wasmExports["PyFunction_New"])(a0,a1);var _PyFunction_GetCode=Module["_PyFunction_GetCode"]=a0=>(_PyFunction_GetCode=Module["_PyFunction_GetCode"]=wasmExports["PyFunction_GetCode"])(a0);var _PyFunction_GetGlobals=Module["_PyFunction_GetGlobals"]=a0=>(_PyFunction_GetGlobals=Module["_PyFunction_GetGlobals"]=wasmExports["PyFunction_GetGlobals"])(a0);var _PyFunction_GetModule=Module["_PyFunction_GetModule"]=a0=>(_PyFunction_GetModule=Module["_PyFunction_GetModule"]=wasmExports["PyFunction_GetModule"])(a0);var _PyFunction_GetDefaults=Module["_PyFunction_GetDefaults"]=a0=>(_PyFunction_GetDefaults=Module["_PyFunction_GetDefaults"]=wasmExports["PyFunction_GetDefaults"])(a0);var _PyFunction_SetDefaults=Module["_PyFunction_SetDefaults"]=(a0,a1)=>(_PyFunction_SetDefaults=Module["_PyFunction_SetDefaults"]=wasmExports["PyFunction_SetDefaults"])(a0,a1);var _PyFunction_SetVectorcall=Module["_PyFunction_SetVectorcall"]=(a0,a1)=>(_PyFunction_SetVectorcall=Module["_PyFunction_SetVectorcall"]=wasmExports["PyFunction_SetVectorcall"])(a0,a1);var _PyFunction_GetKwDefaults=Module["_PyFunction_GetKwDefaults"]=a0=>(_PyFunction_GetKwDefaults=Module["_PyFunction_GetKwDefaults"]=wasmExports["PyFunction_GetKwDefaults"])(a0);var _PyFunction_SetKwDefaults=Module["_PyFunction_SetKwDefaults"]=(a0,a1)=>(_PyFunction_SetKwDefaults=Module["_PyFunction_SetKwDefaults"]=wasmExports["PyFunction_SetKwDefaults"])(a0,a1);var _PyFunction_GetClosure=Module["_PyFunction_GetClosure"]=a0=>(_PyFunction_GetClosure=Module["_PyFunction_GetClosure"]=wasmExports["PyFunction_GetClosure"])(a0);var _PyFunction_SetClosure=Module["_PyFunction_SetClosure"]=(a0,a1)=>(_PyFunction_SetClosure=Module["_PyFunction_SetClosure"]=wasmExports["PyFunction_SetClosure"])(a0,a1);var _PyFunction_GetAnnotations=Module["_PyFunction_GetAnnotations"]=a0=>(_PyFunction_GetAnnotations=Module["_PyFunction_GetAnnotations"]=wasmExports["PyFunction_GetAnnotations"])(a0);var _PyFunction_SetAnnotations=Module["_PyFunction_SetAnnotations"]=(a0,a1)=>(_PyFunction_SetAnnotations=Module["_PyFunction_SetAnnotations"]=wasmExports["PyFunction_SetAnnotations"])(a0,a1);var _PyClassMethod_New=Module["_PyClassMethod_New"]=a0=>(_PyClassMethod_New=Module["_PyClassMethod_New"]=wasmExports["PyClassMethod_New"])(a0);var _PyStaticMethod_New=Module["_PyStaticMethod_New"]=a0=>(_PyStaticMethod_New=Module["_PyStaticMethod_New"]=wasmExports["PyStaticMethod_New"])(a0);var __PyInterpreterState_LookUpID=Module["__PyInterpreterState_LookUpID"]=a0=>(__PyInterpreterState_LookUpID=Module["__PyInterpreterState_LookUpID"]=wasmExports["_PyInterpreterState_LookUpID"])(a0);var __PyInterpreterState_IDDecref=Module["__PyInterpreterState_IDDecref"]=a0=>(__PyInterpreterState_IDDecref=Module["__PyInterpreterState_IDDecref"]=wasmExports["_PyInterpreterState_IDDecref"])(a0);var _PyLong_FromLongLong=Module["_PyLong_FromLongLong"]=a0=>(_PyLong_FromLongLong=Module["_PyLong_FromLongLong"]=wasmExports["PyLong_FromLongLong"])(a0);var _PyLong_AsLongLongAndOverflow=Module["_PyLong_AsLongLongAndOverflow"]=(a0,a1)=>(_PyLong_AsLongLongAndOverflow=Module["_PyLong_AsLongLongAndOverflow"]=wasmExports["PyLong_AsLongLongAndOverflow"])(a0,a1);var _PyArg_ParseTupleAndKeywords=Module["_PyArg_ParseTupleAndKeywords"]=(a0,a1,a2,a3,a4)=>(_PyArg_ParseTupleAndKeywords=Module["_PyArg_ParseTupleAndKeywords"]=wasmExports["PyArg_ParseTupleAndKeywords"])(a0,a1,a2,a3,a4);var __PyInterpreterState_IDIncref=Module["__PyInterpreterState_IDIncref"]=a0=>(__PyInterpreterState_IDIncref=Module["__PyInterpreterState_IDIncref"]=wasmExports["_PyInterpreterState_IDIncref"])(a0);var __PyInterpreterID_New=Module["__PyInterpreterID_New"]=a0=>(__PyInterpreterID_New=Module["__PyInterpreterID_New"]=wasmExports["_PyInterpreterID_New"])(a0);var __PyInterpreterState_GetIDObject=Module["__PyInterpreterState_GetIDObject"]=a0=>(__PyInterpreterState_GetIDObject=Module["__PyInterpreterState_GetIDObject"]=wasmExports["_PyInterpreterState_GetIDObject"])(a0);var __PyInterpreterState_IDInitref=Module["__PyInterpreterState_IDInitref"]=a0=>(__PyInterpreterState_IDInitref=Module["__PyInterpreterState_IDInitref"]=wasmExports["_PyInterpreterState_IDInitref"])(a0);var _PyInterpreterState_GetID=Module["_PyInterpreterState_GetID"]=a0=>(_PyInterpreterState_GetID=Module["_PyInterpreterState_GetID"]=wasmExports["PyInterpreterState_GetID"])(a0);var __PyInterpreterID_LookUp=Module["__PyInterpreterID_LookUp"]=a0=>(__PyInterpreterID_LookUp=Module["__PyInterpreterID_LookUp"]=wasmExports["_PyInterpreterID_LookUp"])(a0);var _PyLong_AsLongLong=Module["_PyLong_AsLongLong"]=a0=>(_PyLong_AsLongLong=Module["_PyLong_AsLongLong"]=wasmExports["PyLong_AsLongLong"])(a0);var _PyCallIter_New=Module["_PyCallIter_New"]=(a0,a1)=>(_PyCallIter_New=Module["_PyCallIter_New"]=wasmExports["PyCallIter_New"])(a0,a1);var __PyList_DebugMallocStats=Module["__PyList_DebugMallocStats"]=a0=>(__PyList_DebugMallocStats=Module["__PyList_DebugMallocStats"]=wasmExports["_PyList_DebugMallocStats"])(a0);var _PyList_SetItem=Module["_PyList_SetItem"]=(a0,a1,a2)=>(_PyList_SetItem=Module["_PyList_SetItem"]=wasmExports["PyList_SetItem"])(a0,a1,a2);var _PyList_Insert=Module["_PyList_Insert"]=(a0,a1,a2)=>(_PyList_Insert=Module["_PyList_Insert"]=wasmExports["PyList_Insert"])(a0,a1,a2);var _PyList_GetSlice=Module["_PyList_GetSlice"]=(a0,a1,a2)=>(_PyList_GetSlice=Module["_PyList_GetSlice"]=wasmExports["PyList_GetSlice"])(a0,a1,a2);var _Py_ReprEnter=Module["_Py_ReprEnter"]=a0=>(_Py_ReprEnter=Module["_Py_ReprEnter"]=wasmExports["Py_ReprEnter"])(a0);var __PyUnicodeWriter_WriteChar=Module["__PyUnicodeWriter_WriteChar"]=(a0,a1)=>(__PyUnicodeWriter_WriteChar=Module["__PyUnicodeWriter_WriteChar"]=wasmExports["_PyUnicodeWriter_WriteChar"])(a0,a1);var _Py_ReprLeave=Module["_Py_ReprLeave"]=a0=>(_Py_ReprLeave=Module["_Py_ReprLeave"]=wasmExports["Py_ReprLeave"])(a0);var __PyEval_SliceIndexNotNone=Module["__PyEval_SliceIndexNotNone"]=(a0,a1)=>(__PyEval_SliceIndexNotNone=Module["__PyEval_SliceIndexNotNone"]=wasmExports["_PyEval_SliceIndexNotNone"])(a0,a1);var _PyObject_HashNotImplemented=Module["_PyObject_HashNotImplemented"]=a0=>(_PyObject_HashNotImplemented=Module["_PyObject_HashNotImplemented"]=wasmExports["PyObject_HashNotImplemented"])(a0);var __PyLong_New=Module["__PyLong_New"]=a0=>(__PyLong_New=Module["__PyLong_New"]=wasmExports["_PyLong_New"])(a0);var __PyLong_FromDigits=Module["__PyLong_FromDigits"]=(a0,a1,a2)=>(__PyLong_FromDigits=Module["__PyLong_FromDigits"]=wasmExports["_PyLong_FromDigits"])(a0,a1,a2);var _PyLong_FromUnsignedLong=Module["_PyLong_FromUnsignedLong"]=a0=>(_PyLong_FromUnsignedLong=Module["_PyLong_FromUnsignedLong"]=wasmExports["PyLong_FromUnsignedLong"])(a0);var _PyLong_FromUnsignedLongLong=Module["_PyLong_FromUnsignedLongLong"]=a0=>(_PyLong_FromUnsignedLongLong=Module["_PyLong_FromUnsignedLongLong"]=wasmExports["PyLong_FromUnsignedLongLong"])(a0);var _PyLong_AsUnsignedLong=Module["_PyLong_AsUnsignedLong"]=a0=>(_PyLong_AsUnsignedLong=Module["_PyLong_AsUnsignedLong"]=wasmExports["PyLong_AsUnsignedLong"])(a0);var _PyLong_AsSize_t=Module["_PyLong_AsSize_t"]=a0=>(_PyLong_AsSize_t=Module["_PyLong_AsSize_t"]=wasmExports["PyLong_AsSize_t"])(a0);var _PyLong_AsUnsignedLongMask=Module["_PyLong_AsUnsignedLongMask"]=a0=>(_PyLong_AsUnsignedLongMask=Module["_PyLong_AsUnsignedLongMask"]=wasmExports["PyLong_AsUnsignedLongMask"])(a0);var __PyLong_FromByteArray=Module["__PyLong_FromByteArray"]=(a0,a1,a2,a3)=>(__PyLong_FromByteArray=Module["__PyLong_FromByteArray"]=wasmExports["_PyLong_FromByteArray"])(a0,a1,a2,a3);var _PyLong_AsVoidPtr=Module["_PyLong_AsVoidPtr"]=a0=>(_PyLong_AsVoidPtr=Module["_PyLong_AsVoidPtr"]=wasmExports["PyLong_AsVoidPtr"])(a0);var _PyLong_AsUnsignedLongLong=Module["_PyLong_AsUnsignedLongLong"]=a0=>(_PyLong_AsUnsignedLongLong=Module["_PyLong_AsUnsignedLongLong"]=wasmExports["PyLong_AsUnsignedLongLong"])(a0);var _PyLong_AsUnsignedLongLongMask=Module["_PyLong_AsUnsignedLongLongMask"]=a0=>(_PyLong_AsUnsignedLongLongMask=Module["_PyLong_AsUnsignedLongLongMask"]=wasmExports["PyLong_AsUnsignedLongLongMask"])(a0);var __PyLong_UnsignedShort_Converter=Module["__PyLong_UnsignedShort_Converter"]=(a0,a1)=>(__PyLong_UnsignedShort_Converter=Module["__PyLong_UnsignedShort_Converter"]=wasmExports["_PyLong_UnsignedShort_Converter"])(a0,a1);var __PyLong_UnsignedInt_Converter=Module["__PyLong_UnsignedInt_Converter"]=(a0,a1)=>(__PyLong_UnsignedInt_Converter=Module["__PyLong_UnsignedInt_Converter"]=wasmExports["_PyLong_UnsignedInt_Converter"])(a0,a1);var __PyLong_UnsignedLong_Converter=Module["__PyLong_UnsignedLong_Converter"]=(a0,a1)=>(__PyLong_UnsignedLong_Converter=Module["__PyLong_UnsignedLong_Converter"]=wasmExports["_PyLong_UnsignedLong_Converter"])(a0,a1);var __PyLong_UnsignedLongLong_Converter=Module["__PyLong_UnsignedLongLong_Converter"]=(a0,a1)=>(__PyLong_UnsignedLongLong_Converter=Module["__PyLong_UnsignedLongLong_Converter"]=wasmExports["_PyLong_UnsignedLongLong_Converter"])(a0,a1);var __PyLong_Size_t_Converter=Module["__PyLong_Size_t_Converter"]=(a0,a1)=>(__PyLong_Size_t_Converter=Module["__PyLong_Size_t_Converter"]=wasmExports["_PyLong_Size_t_Converter"])(a0,a1);var __PyUnicodeWriter_PrepareInternal=Module["__PyUnicodeWriter_PrepareInternal"]=(a0,a1,a2)=>(__PyUnicodeWriter_PrepareInternal=Module["__PyUnicodeWriter_PrepareInternal"]=wasmExports["_PyUnicodeWriter_PrepareInternal"])(a0,a1,a2);var __PyLong_FormatWriter=Module["__PyLong_FormatWriter"]=(a0,a1,a2,a3)=>(__PyLong_FormatWriter=Module["__PyLong_FormatWriter"]=wasmExports["_PyLong_FormatWriter"])(a0,a1,a2,a3);var __PyLong_Frexp=Module["__PyLong_Frexp"]=(a0,a1)=>(__PyLong_Frexp=Module["__PyLong_Frexp"]=wasmExports["_PyLong_Frexp"])(a0,a1);var __PyLong_Rshift=Module["__PyLong_Rshift"]=(a0,a1)=>(__PyLong_Rshift=Module["__PyLong_Rshift"]=wasmExports["_PyLong_Rshift"])(a0,a1);var __PyLong_GCD=Module["__PyLong_GCD"]=(a0,a1)=>(__PyLong_GCD=Module["__PyLong_GCD"]=wasmExports["_PyLong_GCD"])(a0,a1);var __PyLong_DivmodNear=Module["__PyLong_DivmodNear"]=(a0,a1)=>(__PyLong_DivmodNear=Module["__PyLong_DivmodNear"]=wasmExports["_PyLong_DivmodNear"])(a0,a1);var _PyLong_GetInfo=Module["_PyLong_GetInfo"]=()=>(_PyLong_GetInfo=Module["_PyLong_GetInfo"]=wasmExports["PyLong_GetInfo"])();var _PyUnstable_Long_IsCompact=Module["_PyUnstable_Long_IsCompact"]=a0=>(_PyUnstable_Long_IsCompact=Module["_PyUnstable_Long_IsCompact"]=wasmExports["PyUnstable_Long_IsCompact"])(a0);var _PyUnstable_Long_CompactValue=Module["_PyUnstable_Long_CompactValue"]=a0=>(_PyUnstable_Long_CompactValue=Module["_PyUnstable_Long_CompactValue"]=wasmExports["PyUnstable_Long_CompactValue"])(a0);var _PyObject_Bytes=Module["_PyObject_Bytes"]=a0=>(_PyObject_Bytes=Module["_PyObject_Bytes"]=wasmExports["PyObject_Bytes"])(a0);var __PyLong_FormatAdvancedWriter=Module["__PyLong_FormatAdvancedWriter"]=(a0,a1,a2,a3,a4)=>(__PyLong_FormatAdvancedWriter=Module["__PyLong_FormatAdvancedWriter"]=wasmExports["_PyLong_FormatAdvancedWriter"])(a0,a1,a2,a3,a4);var __PyDict_DebugMallocStats=Module["__PyDict_DebugMallocStats"]=a0=>(__PyDict_DebugMallocStats=Module["__PyDict_DebugMallocStats"]=wasmExports["_PyDict_DebugMallocStats"])(a0);var __PyDict_CheckConsistency=Module["__PyDict_CheckConsistency"]=(a0,a1)=>(__PyDict_CheckConsistency=Module["__PyDict_CheckConsistency"]=wasmExports["_PyDict_CheckConsistency"])(a0,a1);var __PyObject_AssertFailed=Module["__PyObject_AssertFailed"]=(a0,a1,a2,a3,a4,a5)=>(__PyObject_AssertFailed=Module["__PyObject_AssertFailed"]=wasmExports["_PyObject_AssertFailed"])(a0,a1,a2,a3,a4,a5);var __PyDict_HasOnlyStringKeys=Module["__PyDict_HasOnlyStringKeys"]=a0=>(__PyDict_HasOnlyStringKeys=Module["__PyDict_HasOnlyStringKeys"]=wasmExports["_PyDict_HasOnlyStringKeys"])(a0);var __PyDict_Next=Module["__PyDict_Next"]=(a0,a1,a2,a3,a4)=>(__PyDict_Next=Module["__PyDict_Next"]=wasmExports["_PyDict_Next"])(a0,a1,a2,a3,a4);var __PyDict_MaybeUntrack=Module["__PyDict_MaybeUntrack"]=a0=>(__PyDict_MaybeUntrack=Module["__PyDict_MaybeUntrack"]=wasmExports["_PyDict_MaybeUntrack"])(a0);var _PyObject_IS_GC=Module["_PyObject_IS_GC"]=a0=>(_PyObject_IS_GC=Module["_PyObject_IS_GC"]=wasmExports["PyObject_IS_GC"])(a0);var __PyDict_NewPresized=Module["__PyDict_NewPresized"]=a0=>(__PyDict_NewPresized=Module["__PyDict_NewPresized"]=wasmExports["_PyDict_NewPresized"])(a0);var _PyDict_GetItem=Module["_PyDict_GetItem"]=(a0,a1)=>(_PyDict_GetItem=Module["_PyDict_GetItem"]=wasmExports["PyDict_GetItem"])(a0,a1);var __PyDict_GetItemWithError=Module["__PyDict_GetItemWithError"]=(a0,a1)=>(__PyDict_GetItemWithError=Module["__PyDict_GetItemWithError"]=wasmExports["_PyDict_GetItemWithError"])(a0,a1);var __PyDict_GetItemIdWithError=Module["__PyDict_GetItemIdWithError"]=(a0,a1)=>(__PyDict_GetItemIdWithError=Module["__PyDict_GetItemIdWithError"]=wasmExports["_PyDict_GetItemIdWithError"])(a0,a1);var __PyDict_GetItemStringWithError=Module["__PyDict_GetItemStringWithError"]=(a0,a1)=>(__PyDict_GetItemStringWithError=Module["__PyDict_GetItemStringWithError"]=wasmExports["_PyDict_GetItemStringWithError"])(a0,a1);var __PyDict_SetItem_KnownHash=Module["__PyDict_SetItem_KnownHash"]=(a0,a1,a2,a3)=>(__PyDict_SetItem_KnownHash=Module["__PyDict_SetItem_KnownHash"]=wasmExports["_PyDict_SetItem_KnownHash"])(a0,a1,a2,a3);var _PyDict_DelItem=Module["_PyDict_DelItem"]=(a0,a1)=>(_PyDict_DelItem=Module["_PyDict_DelItem"]=wasmExports["PyDict_DelItem"])(a0,a1);var __PyDict_DelItem_KnownHash=Module["__PyDict_DelItem_KnownHash"]=(a0,a1,a2)=>(__PyDict_DelItem_KnownHash=Module["__PyDict_DelItem_KnownHash"]=wasmExports["_PyDict_DelItem_KnownHash"])(a0,a1,a2);var __PyErr_SetKeyError=Module["__PyErr_SetKeyError"]=a0=>(__PyErr_SetKeyError=Module["__PyErr_SetKeyError"]=wasmExports["_PyErr_SetKeyError"])(a0);var __PyDict_DelItemIf=Module["__PyDict_DelItemIf"]=(a0,a1,a2)=>(__PyDict_DelItemIf=Module["__PyDict_DelItemIf"]=wasmExports["_PyDict_DelItemIf"])(a0,a1,a2);var _PyDict_Clear=Module["_PyDict_Clear"]=a0=>(_PyDict_Clear=Module["_PyDict_Clear"]=wasmExports["PyDict_Clear"])(a0);var __PyDict_Pop=Module["__PyDict_Pop"]=(a0,a1,a2)=>(__PyDict_Pop=Module["__PyDict_Pop"]=wasmExports["_PyDict_Pop"])(a0,a1,a2);var _PyDict_MergeFromSeq2=Module["_PyDict_MergeFromSeq2"]=(a0,a1,a2)=>(_PyDict_MergeFromSeq2=Module["_PyDict_MergeFromSeq2"]=wasmExports["PyDict_MergeFromSeq2"])(a0,a1,a2);var _PyDict_SetDefault=Module["_PyDict_SetDefault"]=(a0,a1,a2)=>(_PyDict_SetDefault=Module["_PyDict_SetDefault"]=wasmExports["PyDict_SetDefault"])(a0,a1,a2);var _PyDict_Update=Module["_PyDict_Update"]=(a0,a1)=>(_PyDict_Update=Module["_PyDict_Update"]=wasmExports["PyDict_Update"])(a0,a1);var __PyDict_MergeEx=Module["__PyDict_MergeEx"]=(a0,a1,a2)=>(__PyDict_MergeEx=Module["__PyDict_MergeEx"]=wasmExports["_PyDict_MergeEx"])(a0,a1,a2);var __PyDict_SizeOf=Module["__PyDict_SizeOf"]=a0=>(__PyDict_SizeOf=Module["__PyDict_SizeOf"]=wasmExports["_PyDict_SizeOf"])(a0);var __PyDict_Contains_KnownHash=Module["__PyDict_Contains_KnownHash"]=(a0,a1,a2)=>(__PyDict_Contains_KnownHash=Module["__PyDict_Contains_KnownHash"]=wasmExports["_PyDict_Contains_KnownHash"])(a0,a1,a2);var __PyDict_ContainsId=Module["__PyDict_ContainsId"]=(a0,a1)=>(__PyDict_ContainsId=Module["__PyDict_ContainsId"]=wasmExports["_PyDict_ContainsId"])(a0,a1);var _PyArg_ValidateKeywordArguments=Module["_PyArg_ValidateKeywordArguments"]=a0=>(_PyArg_ValidateKeywordArguments=Module["_PyArg_ValidateKeywordArguments"]=wasmExports["PyArg_ValidateKeywordArguments"])(a0);var _PyDict_GetItemString=Module["_PyDict_GetItemString"]=(a0,a1)=>(_PyDict_GetItemString=Module["_PyDict_GetItemString"]=wasmExports["PyDict_GetItemString"])(a0,a1);var __PyDict_SetItemId=Module["__PyDict_SetItemId"]=(a0,a1,a2)=>(__PyDict_SetItemId=Module["__PyDict_SetItemId"]=wasmExports["_PyDict_SetItemId"])(a0,a1,a2);var __PyDict_DelItemId=Module["__PyDict_DelItemId"]=(a0,a1)=>(__PyDict_DelItemId=Module["__PyDict_DelItemId"]=wasmExports["_PyDict_DelItemId"])(a0,a1);var _PyDict_DelItemString=Module["_PyDict_DelItemString"]=(a0,a1)=>(_PyDict_DelItemString=Module["_PyDict_DelItemString"]=wasmExports["PyDict_DelItemString"])(a0,a1);var __PyDictView_New=Module["__PyDictView_New"]=(a0,a1)=>(__PyDictView_New=Module["__PyDictView_New"]=wasmExports["_PyDictView_New"])(a0,a1);var __PyDictView_Intersect=Module["__PyDictView_Intersect"]=(a0,a1)=>(__PyDictView_Intersect=Module["__PyDictView_Intersect"]=wasmExports["_PyDictView_Intersect"])(a0,a1);var __PyObject_VisitManagedDict=Module["__PyObject_VisitManagedDict"]=(a0,a1,a2)=>(__PyObject_VisitManagedDict=Module["__PyObject_VisitManagedDict"]=wasmExports["_PyObject_VisitManagedDict"])(a0,a1,a2);var __PyObject_ClearManagedDict=Module["__PyObject_ClearManagedDict"]=a0=>(__PyObject_ClearManagedDict=Module["__PyObject_ClearManagedDict"]=wasmExports["_PyObject_ClearManagedDict"])(a0);var _PyDict_Watch=Module["_PyDict_Watch"]=(a0,a1)=>(_PyDict_Watch=Module["_PyDict_Watch"]=wasmExports["PyDict_Watch"])(a0,a1);var _PyDict_Unwatch=Module["_PyDict_Unwatch"]=(a0,a1)=>(_PyDict_Unwatch=Module["_PyDict_Unwatch"]=wasmExports["PyDict_Unwatch"])(a0,a1);var _PyDict_AddWatcher=Module["_PyDict_AddWatcher"]=a0=>(_PyDict_AddWatcher=Module["_PyDict_AddWatcher"]=wasmExports["PyDict_AddWatcher"])(a0);var _PyDict_ClearWatcher=Module["_PyDict_ClearWatcher"]=a0=>(_PyDict_ClearWatcher=Module["_PyDict_ClearWatcher"]=wasmExports["PyDict_ClearWatcher"])(a0);var _PyODict_New=Module["_PyODict_New"]=()=>(_PyODict_New=Module["_PyODict_New"]=wasmExports["PyODict_New"])();var _PyODict_SetItem=Module["_PyODict_SetItem"]=(a0,a1,a2)=>(_PyODict_SetItem=Module["_PyODict_SetItem"]=wasmExports["PyODict_SetItem"])(a0,a1,a2);var __PyErr_ChainExceptions1=Module["__PyErr_ChainExceptions1"]=a0=>(__PyErr_ChainExceptions1=Module["__PyErr_ChainExceptions1"]=wasmExports["_PyErr_ChainExceptions1"])(a0);var _PyODict_DelItem=Module["_PyODict_DelItem"]=(a0,a1)=>(_PyODict_DelItem=Module["_PyODict_DelItem"]=wasmExports["PyODict_DelItem"])(a0,a1);var _PyMemoryView_FromMemory=Module["_PyMemoryView_FromMemory"]=(a0,a1,a2)=>(_PyMemoryView_FromMemory=Module["_PyMemoryView_FromMemory"]=wasmExports["PyMemoryView_FromMemory"])(a0,a1,a2);var _PyMemoryView_FromBuffer=Module["_PyMemoryView_FromBuffer"]=a0=>(_PyMemoryView_FromBuffer=Module["_PyMemoryView_FromBuffer"]=wasmExports["PyMemoryView_FromBuffer"])(a0);var _PyMemoryView_GetContiguous=Module["_PyMemoryView_GetContiguous"]=(a0,a1,a2)=>(_PyMemoryView_GetContiguous=Module["_PyMemoryView_GetContiguous"]=wasmExports["PyMemoryView_GetContiguous"])(a0,a1,a2);var _PyUnicode_AsASCIIString=Module["_PyUnicode_AsASCIIString"]=a0=>(_PyUnicode_AsASCIIString=Module["_PyUnicode_AsASCIIString"]=wasmExports["PyUnicode_AsASCIIString"])(a0);var _PyCFunction_New=Module["_PyCFunction_New"]=(a0,a1)=>(_PyCFunction_New=Module["_PyCFunction_New"]=wasmExports["PyCFunction_New"])(a0,a1);var _PyCFunction_NewEx=Module["_PyCFunction_NewEx"]=(a0,a1,a2)=>(_PyCFunction_NewEx=Module["_PyCFunction_NewEx"]=wasmExports["PyCFunction_NewEx"])(a0,a1,a2);var _PyCFunction_GetFunction=Module["_PyCFunction_GetFunction"]=a0=>(_PyCFunction_GetFunction=Module["_PyCFunction_GetFunction"]=wasmExports["PyCFunction_GetFunction"])(a0);var _PyCFunction_GetSelf=Module["_PyCFunction_GetSelf"]=a0=>(_PyCFunction_GetSelf=Module["_PyCFunction_GetSelf"]=wasmExports["PyCFunction_GetSelf"])(a0);var _PyCFunction_GetFlags=Module["_PyCFunction_GetFlags"]=a0=>(_PyCFunction_GetFlags=Module["_PyCFunction_GetFlags"]=wasmExports["PyCFunction_GetFlags"])(a0);var _PyModuleDef_Init=Module["_PyModuleDef_Init"]=a0=>(_PyModuleDef_Init=Module["_PyModuleDef_Init"]=wasmExports["PyModuleDef_Init"])(a0);var _PyModule_NewObject=Module["_PyModule_NewObject"]=a0=>(_PyModule_NewObject=Module["_PyModule_NewObject"]=wasmExports["PyModule_NewObject"])(a0);var _PyModule_New=Module["_PyModule_New"]=a0=>(_PyModule_New=Module["_PyModule_New"]=wasmExports["PyModule_New"])(a0);var __PyImport_IsInitialized=Module["__PyImport_IsInitialized"]=a0=>(__PyImport_IsInitialized=Module["__PyImport_IsInitialized"]=wasmExports["_PyImport_IsInitialized"])(a0);var __PyModule_CreateInitialized=Module["__PyModule_CreateInitialized"]=(a0,a1)=>(__PyModule_CreateInitialized=Module["__PyModule_CreateInitialized"]=wasmExports["_PyModule_CreateInitialized"])(a0,a1);var _PyModule_SetDocString=Module["_PyModule_SetDocString"]=(a0,a1)=>(_PyModule_SetDocString=Module["_PyModule_SetDocString"]=wasmExports["PyModule_SetDocString"])(a0,a1);var _PyModule_FromDefAndSpec2=Module["_PyModule_FromDefAndSpec2"]=(a0,a1,a2)=>(_PyModule_FromDefAndSpec2=Module["_PyModule_FromDefAndSpec2"]=wasmExports["PyModule_FromDefAndSpec2"])(a0,a1,a2);var __PyImport_CheckSubinterpIncompatibleExtensionAllowed=Module["__PyImport_CheckSubinterpIncompatibleExtensionAllowed"]=a0=>(__PyImport_CheckSubinterpIncompatibleExtensionAllowed=Module["__PyImport_CheckSubinterpIncompatibleExtensionAllowed"]=wasmExports["_PyImport_CheckSubinterpIncompatibleExtensionAllowed"])(a0);var _PyModule_ExecDef=Module["_PyModule_ExecDef"]=(a0,a1)=>(_PyModule_ExecDef=Module["_PyModule_ExecDef"]=wasmExports["PyModule_ExecDef"])(a0,a1);var _PyModule_GetName=Module["_PyModule_GetName"]=a0=>(_PyModule_GetName=Module["_PyModule_GetName"]=wasmExports["PyModule_GetName"])(a0);var _PyModule_GetFilenameObject=Module["_PyModule_GetFilenameObject"]=a0=>(_PyModule_GetFilenameObject=Module["_PyModule_GetFilenameObject"]=wasmExports["PyModule_GetFilenameObject"])(a0);var _PyModule_GetFilename=Module["_PyModule_GetFilename"]=a0=>(_PyModule_GetFilename=Module["_PyModule_GetFilename"]=wasmExports["PyModule_GetFilename"])(a0);var _PyModule_GetDef=Module["_PyModule_GetDef"]=a0=>(_PyModule_GetDef=Module["_PyModule_GetDef"]=wasmExports["PyModule_GetDef"])(a0);var _PyModule_GetState=Module["_PyModule_GetState"]=a0=>(_PyModule_GetState=Module["_PyModule_GetState"]=wasmExports["PyModule_GetState"])(a0);var __PyModule_Clear=Module["__PyModule_Clear"]=a0=>(__PyModule_Clear=Module["__PyModule_Clear"]=wasmExports["_PyModule_Clear"])(a0);var __PyModule_ClearDict=Module["__PyModule_ClearDict"]=a0=>(__PyModule_ClearDict=Module["__PyModule_ClearDict"]=wasmExports["_PyModule_ClearDict"])(a0);var __PyModuleSpec_IsInitializing=Module["__PyModuleSpec_IsInitializing"]=a0=>(__PyModuleSpec_IsInitializing=Module["__PyModuleSpec_IsInitializing"]=wasmExports["_PyModuleSpec_IsInitializing"])(a0);var _PySys_FormatStderr=Module["_PySys_FormatStderr"]=(a0,a1)=>(_PySys_FormatStderr=Module["_PySys_FormatStderr"]=wasmExports["PySys_FormatStderr"])(a0,a1);var _PyUnicode_Join=Module["_PyUnicode_Join"]=(a0,a1)=>(_PyUnicode_Join=Module["_PyUnicode_Join"]=wasmExports["PyUnicode_Join"])(a0,a1);var __PyNamespace_New=Module["__PyNamespace_New"]=a0=>(__PyNamespace_New=Module["__PyNamespace_New"]=wasmExports["_PyNamespace_New"])(a0);var __PyObject_CheckConsistency=Module["__PyObject_CheckConsistency"]=(a0,a1)=>(__PyObject_CheckConsistency=Module["__PyObject_CheckConsistency"]=wasmExports["_PyObject_CheckConsistency"])(a0,a1);var __PyType_CheckConsistency=Module["__PyType_CheckConsistency"]=a0=>(__PyType_CheckConsistency=Module["__PyType_CheckConsistency"]=wasmExports["_PyType_CheckConsistency"])(a0);var __PyUnicode_CheckConsistency=Module["__PyUnicode_CheckConsistency"]=(a0,a1)=>(__PyUnicode_CheckConsistency=Module["__PyUnicode_CheckConsistency"]=wasmExports["_PyUnicode_CheckConsistency"])(a0,a1);var __PyObject_IsFreed=Module["__PyObject_IsFreed"]=a0=>(__PyObject_IsFreed=Module["__PyObject_IsFreed"]=wasmExports["_PyObject_IsFreed"])(a0);var _fwrite=Module["_fwrite"]=(a0,a1,a2,a3)=>(_fwrite=Module["_fwrite"]=wasmExports["fwrite"])(a0,a1,a2,a3);var _fputc=Module["_fputc"]=(a0,a1)=>(_fputc=Module["_fputc"]=wasmExports["fputc"])(a0,a1);var __PyObject_Dump=Module["__PyObject_Dump"]=a0=>(__PyObject_Dump=Module["__PyObject_Dump"]=wasmExports["_PyObject_Dump"])(a0);var _Py_IncRef=Module["_Py_IncRef"]=a0=>(_Py_IncRef=Module["_Py_IncRef"]=wasmExports["Py_IncRef"])(a0);var _Py_DecRef=Module["_Py_DecRef"]=a0=>(_Py_DecRef=Module["_Py_DecRef"]=wasmExports["Py_DecRef"])(a0);var __Py_IncRef=Module["__Py_IncRef"]=a0=>(__Py_IncRef=Module["__Py_IncRef"]=wasmExports["_Py_IncRef"])(a0);var __Py_DecRef=Module["__Py_DecRef"]=a0=>(__Py_DecRef=Module["__Py_DecRef"]=wasmExports["_Py_DecRef"])(a0);var _PyObject_Init=Module["_PyObject_Init"]=(a0,a1)=>(_PyObject_Init=Module["_PyObject_Init"]=wasmExports["PyObject_Init"])(a0,a1);var _PyObject_InitVar=Module["_PyObject_InitVar"]=(a0,a1,a2)=>(_PyObject_InitVar=Module["_PyObject_InitVar"]=wasmExports["PyObject_InitVar"])(a0,a1,a2);var _PyObject_CallFinalizer=Module["_PyObject_CallFinalizer"]=a0=>(_PyObject_CallFinalizer=Module["_PyObject_CallFinalizer"]=wasmExports["PyObject_CallFinalizer"])(a0);var _PyObject_Print=Module["_PyObject_Print"]=(a0,a1,a2)=>(_PyObject_Print=Module["_PyObject_Print"]=wasmExports["PyObject_Print"])(a0,a1,a2);var _ferror=Module["_ferror"]=a0=>(_ferror=Module["_ferror"]=wasmExports["ferror"])(a0);var __Py_BreakPoint=Module["__Py_BreakPoint"]=()=>(__Py_BreakPoint=Module["__Py_BreakPoint"]=wasmExports["_Py_BreakPoint"])();var _PyGILState_Ensure=Module["_PyGILState_Ensure"]=()=>(_PyGILState_Ensure=Module["_PyGILState_Ensure"]=wasmExports["PyGILState_Ensure"])();var _PyGILState_Release=Module["_PyGILState_Release"]=a0=>(_PyGILState_Release=Module["_PyGILState_Release"]=wasmExports["PyGILState_Release"])(a0);var __PyUnicode_AsASCIIString=Module["__PyUnicode_AsASCIIString"]=(a0,a1)=>(__PyUnicode_AsASCIIString=Module["__PyUnicode_AsASCIIString"]=wasmExports["_PyUnicode_AsASCIIString"])(a0,a1);var _PyUnicode_DecodeASCII=Module["_PyUnicode_DecodeASCII"]=(a0,a1,a2)=>(_PyUnicode_DecodeASCII=Module["_PyUnicode_DecodeASCII"]=wasmExports["PyUnicode_DecodeASCII"])(a0,a1,a2);var _PyObject_HasAttrString=Module["_PyObject_HasAttrString"]=(a0,a1)=>(_PyObject_HasAttrString=Module["_PyObject_HasAttrString"]=wasmExports["PyObject_HasAttrString"])(a0,a1);var __PyObject_SetAttrId=Module["__PyObject_SetAttrId"]=(a0,a1,a2)=>(__PyObject_SetAttrId=Module["__PyObject_SetAttrId"]=wasmExports["_PyObject_SetAttrId"])(a0,a1,a2);var __PyObject_LookupAttrId=Module["__PyObject_LookupAttrId"]=(a0,a1,a2)=>(__PyObject_LookupAttrId=Module["__PyObject_LookupAttrId"]=wasmExports["_PyObject_LookupAttrId"])(a0,a1,a2);var __PyObject_GetDictPtr=Module["__PyObject_GetDictPtr"]=a0=>(__PyObject_GetDictPtr=Module["__PyObject_GetDictPtr"]=wasmExports["_PyObject_GetDictPtr"])(a0);var __PyObject_GenericSetAttrWithDict=Module["__PyObject_GenericSetAttrWithDict"]=(a0,a1,a2,a3)=>(__PyObject_GenericSetAttrWithDict=Module["__PyObject_GenericSetAttrWithDict"]=wasmExports["_PyObject_GenericSetAttrWithDict"])(a0,a1,a2,a3);var _PyObject_Not=Module["_PyObject_Not"]=a0=>(_PyObject_Not=Module["_PyObject_Not"]=wasmExports["PyObject_Not"])(a0);var __PyObject_DebugTypeStats=Module["__PyObject_DebugTypeStats"]=a0=>(__PyObject_DebugTypeStats=Module["__PyObject_DebugTypeStats"]=wasmExports["_PyObject_DebugTypeStats"])(a0);var __PyTuple_DebugMallocStats=Module["__PyTuple_DebugMallocStats"]=a0=>(__PyTuple_DebugMallocStats=Module["__PyTuple_DebugMallocStats"]=wasmExports["_PyTuple_DebugMallocStats"])(a0);var _PyThreadState_GetDict=Module["_PyThreadState_GetDict"]=()=>(_PyThreadState_GetDict=Module["_PyThreadState_GetDict"]=wasmExports["PyThreadState_GetDict"])();var _PyThread_tss_get=Module["_PyThread_tss_get"]=a0=>(_PyThread_tss_get=Module["_PyThread_tss_get"]=wasmExports["PyThread_tss_get"])(a0);var _PyMem_RawMalloc=Module["_PyMem_RawMalloc"]=a0=>(_PyMem_RawMalloc=Module["_PyMem_RawMalloc"]=wasmExports["PyMem_RawMalloc"])(a0);var _PyThread_tss_set=Module["_PyThread_tss_set"]=(a0,a1)=>(_PyThread_tss_set=Module["_PyThread_tss_set"]=wasmExports["PyThread_tss_set"])(a0,a1);var _PyThread_tss_is_created=Module["_PyThread_tss_is_created"]=a0=>(_PyThread_tss_is_created=Module["_PyThread_tss_is_created"]=wasmExports["PyThread_tss_is_created"])(a0);var _PyObject_GET_WEAKREFS_LISTPTR=Module["_PyObject_GET_WEAKREFS_LISTPTR"]=a0=>(_PyObject_GET_WEAKREFS_LISTPTR=Module["_PyObject_GET_WEAKREFS_LISTPTR"]=wasmExports["PyObject_GET_WEAKREFS_LISTPTR"])(a0);var _Py_NewRef=Module["_Py_NewRef"]=a0=>(_Py_NewRef=Module["_Py_NewRef"]=wasmExports["Py_NewRef"])(a0);var _Py_XNewRef=Module["_Py_XNewRef"]=a0=>(_Py_XNewRef=Module["_Py_XNewRef"]=wasmExports["Py_XNewRef"])(a0);var _Py_Is=Module["_Py_Is"]=(a0,a1)=>(_Py_Is=Module["_Py_Is"]=wasmExports["Py_Is"])(a0,a1);var _Py_IsNone=Module["_Py_IsNone"]=a0=>(_Py_IsNone=Module["_Py_IsNone"]=wasmExports["Py_IsNone"])(a0);var _Py_IsTrue=Module["_Py_IsTrue"]=a0=>(_Py_IsTrue=Module["_Py_IsTrue"]=wasmExports["Py_IsTrue"])(a0);var _Py_IsFalse=Module["_Py_IsFalse"]=a0=>(_Py_IsFalse=Module["_Py_IsFalse"]=wasmExports["Py_IsFalse"])(a0);var _calloc=Module["_calloc"]=(a0,a1)=>(_calloc=Module["_calloc"]=wasmExports["calloc"])(a0,a1);var _realloc=Module["_realloc"]=(a0,a1)=>(_realloc=Module["_realloc"]=wasmExports["realloc"])(a0,a1);var __PyMem_SetDefaultAllocator=Module["__PyMem_SetDefaultAllocator"]=(a0,a1)=>(__PyMem_SetDefaultAllocator=Module["__PyMem_SetDefaultAllocator"]=wasmExports["_PyMem_SetDefaultAllocator"])(a0,a1);var __PyMem_GetAllocatorName=Module["__PyMem_GetAllocatorName"]=(a0,a1)=>(__PyMem_GetAllocatorName=Module["__PyMem_GetAllocatorName"]=wasmExports["_PyMem_GetAllocatorName"])(a0,a1);var __PyMem_SetupAllocators=Module["__PyMem_SetupAllocators"]=a0=>(__PyMem_SetupAllocators=Module["__PyMem_SetupAllocators"]=wasmExports["_PyMem_SetupAllocators"])(a0);var __PyMem_GetCurrentAllocatorName=Module["__PyMem_GetCurrentAllocatorName"]=()=>(__PyMem_GetCurrentAllocatorName=Module["__PyMem_GetCurrentAllocatorName"]=wasmExports["_PyMem_GetCurrentAllocatorName"])();var _PyMem_SetupDebugHooks=Module["_PyMem_SetupDebugHooks"]=()=>(_PyMem_SetupDebugHooks=Module["_PyMem_SetupDebugHooks"]=wasmExports["PyMem_SetupDebugHooks"])();var _PyMem_GetAllocator=Module["_PyMem_GetAllocator"]=(a0,a1)=>(_PyMem_GetAllocator=Module["_PyMem_GetAllocator"]=wasmExports["PyMem_GetAllocator"])(a0,a1);var _PyMem_SetAllocator=Module["_PyMem_SetAllocator"]=(a0,a1)=>(_PyMem_SetAllocator=Module["_PyMem_SetAllocator"]=wasmExports["PyMem_SetAllocator"])(a0,a1);var _PyObject_SetArenaAllocator=Module["_PyObject_SetArenaAllocator"]=a0=>(_PyObject_SetArenaAllocator=Module["_PyObject_SetArenaAllocator"]=wasmExports["PyObject_SetArenaAllocator"])(a0);var _PyMem_RawCalloc=Module["_PyMem_RawCalloc"]=(a0,a1)=>(_PyMem_RawCalloc=Module["_PyMem_RawCalloc"]=wasmExports["PyMem_RawCalloc"])(a0,a1);var __PyMem_RawWcsdup=Module["__PyMem_RawWcsdup"]=a0=>(__PyMem_RawWcsdup=Module["__PyMem_RawWcsdup"]=wasmExports["_PyMem_RawWcsdup"])(a0);var _wcslen=Module["_wcslen"]=a0=>(_wcslen=Module["_wcslen"]=wasmExports["wcslen"])(a0);var __PyMem_RawStrdup=Module["__PyMem_RawStrdup"]=a0=>(__PyMem_RawStrdup=Module["__PyMem_RawStrdup"]=wasmExports["_PyMem_RawStrdup"])(a0);var __PyMem_Strdup=Module["__PyMem_Strdup"]=a0=>(__PyMem_Strdup=Module["__PyMem_Strdup"]=wasmExports["_PyMem_Strdup"])(a0);var _PyPickleBuffer_FromObject=Module["_PyPickleBuffer_FromObject"]=a0=>(_PyPickleBuffer_FromObject=Module["_PyPickleBuffer_FromObject"]=wasmExports["PyPickleBuffer_FromObject"])(a0);var _PyPickleBuffer_GetBuffer=Module["_PyPickleBuffer_GetBuffer"]=a0=>(_PyPickleBuffer_GetBuffer=Module["_PyPickleBuffer_GetBuffer"]=wasmExports["PyPickleBuffer_GetBuffer"])(a0);var _PyPickleBuffer_Release=Module["_PyPickleBuffer_Release"]=a0=>(_PyPickleBuffer_Release=Module["_PyPickleBuffer_Release"]=wasmExports["PyPickleBuffer_Release"])(a0);var __PySlice_GetLongIndices=Module["__PySlice_GetLongIndices"]=(a0,a1,a2,a3,a4)=>(__PySlice_GetLongIndices=Module["__PySlice_GetLongIndices"]=wasmExports["_PySlice_GetLongIndices"])(a0,a1,a2,a3,a4);var _PySet_Size=Module["_PySet_Size"]=a0=>(_PySet_Size=Module["_PySet_Size"]=wasmExports["PySet_Size"])(a0);var _PySet_Clear=Module["_PySet_Clear"]=a0=>(_PySet_Clear=Module["_PySet_Clear"]=wasmExports["PySet_Clear"])(a0);var _PySet_Pop=Module["_PySet_Pop"]=a0=>(_PySet_Pop=Module["_PySet_Pop"]=wasmExports["PySet_Pop"])(a0);var _PySlice_New=Module["_PySlice_New"]=(a0,a1,a2)=>(_PySlice_New=Module["_PySlice_New"]=wasmExports["PySlice_New"])(a0,a1,a2);var _PySlice_GetIndices=Module["_PySlice_GetIndices"]=(a0,a1,a2,a3,a4)=>(_PySlice_GetIndices=Module["_PySlice_GetIndices"]=wasmExports["PySlice_GetIndices"])(a0,a1,a2,a3,a4);var _PySlice_GetIndicesEx=Module["_PySlice_GetIndicesEx"]=(a0,a1,a2,a3,a4,a5)=>(_PySlice_GetIndicesEx=Module["_PySlice_GetIndicesEx"]=wasmExports["PySlice_GetIndicesEx"])(a0,a1,a2,a3,a4,a5);var _PyStructSequence_SetItem=Module["_PyStructSequence_SetItem"]=(a0,a1,a2)=>(_PyStructSequence_SetItem=Module["_PyStructSequence_SetItem"]=wasmExports["PyStructSequence_SetItem"])(a0,a1,a2);var _PyStructSequence_GetItem=Module["_PyStructSequence_GetItem"]=(a0,a1)=>(_PyStructSequence_GetItem=Module["_PyStructSequence_GetItem"]=wasmExports["PyStructSequence_GetItem"])(a0,a1);var _PyStructSequence_InitType2=Module["_PyStructSequence_InitType2"]=(a0,a1)=>(_PyStructSequence_InitType2=Module["_PyStructSequence_InitType2"]=wasmExports["PyStructSequence_InitType2"])(a0,a1);var _PyStructSequence_InitType=Module["_PyStructSequence_InitType"]=(a0,a1)=>(_PyStructSequence_InitType=Module["_PyStructSequence_InitType"]=wasmExports["PyStructSequence_InitType"])(a0,a1);var __PyStructSequence_NewType=Module["__PyStructSequence_NewType"]=(a0,a1)=>(__PyStructSequence_NewType=Module["__PyStructSequence_NewType"]=wasmExports["_PyStructSequence_NewType"])(a0,a1);var _PyStructSequence_NewType=Module["_PyStructSequence_NewType"]=a0=>(_PyStructSequence_NewType=Module["_PyStructSequence_NewType"]=wasmExports["PyStructSequence_NewType"])(a0);var _PyTuple_SetItem=Module["_PyTuple_SetItem"]=(a0,a1,a2)=>(_PyTuple_SetItem=Module["_PyTuple_SetItem"]=wasmExports["PyTuple_SetItem"])(a0,a1,a2);var __PyTuple_MaybeUntrack=Module["__PyTuple_MaybeUntrack"]=a0=>(__PyTuple_MaybeUntrack=Module["__PyTuple_MaybeUntrack"]=wasmExports["_PyTuple_MaybeUntrack"])(a0);var __PyObject_GC_Resize=Module["__PyObject_GC_Resize"]=(a0,a1)=>(__PyObject_GC_Resize=Module["__PyObject_GC_Resize"]=wasmExports["_PyObject_GC_Resize"])(a0,a1);var _PyType_GetDict=Module["_PyType_GetDict"]=a0=>(_PyType_GetDict=Module["_PyType_GetDict"]=wasmExports["PyType_GetDict"])(a0);var _strrchr=Module["_strrchr"]=(a0,a1)=>(_strrchr=Module["_strrchr"]=wasmExports["strrchr"])(a0,a1);var _PyType_ClearCache=Module["_PyType_ClearCache"]=()=>(_PyType_ClearCache=Module["_PyType_ClearCache"]=wasmExports["PyType_ClearCache"])();var _PyType_AddWatcher=Module["_PyType_AddWatcher"]=a0=>(_PyType_AddWatcher=Module["_PyType_AddWatcher"]=wasmExports["PyType_AddWatcher"])(a0);var _PyType_ClearWatcher=Module["_PyType_ClearWatcher"]=a0=>(_PyType_ClearWatcher=Module["_PyType_ClearWatcher"]=wasmExports["PyType_ClearWatcher"])(a0);var _PyType_Watch=Module["_PyType_Watch"]=(a0,a1)=>(_PyType_Watch=Module["_PyType_Watch"]=wasmExports["PyType_Watch"])(a0,a1);var _PyType_Unwatch=Module["_PyType_Unwatch"]=(a0,a1)=>(_PyType_Unwatch=Module["_PyType_Unwatch"]=wasmExports["PyType_Unwatch"])(a0,a1);var _PyType_Modified=Module["_PyType_Modified"]=a0=>(_PyType_Modified=Module["_PyType_Modified"]=wasmExports["PyType_Modified"])(a0);var _PyUnstable_Type_AssignVersionTag=Module["_PyUnstable_Type_AssignVersionTag"]=a0=>(_PyUnstable_Type_AssignVersionTag=Module["_PyUnstable_Type_AssignVersionTag"]=wasmExports["PyUnstable_Type_AssignVersionTag"])(a0);var __PyObject_LookupSpecialId=Module["__PyObject_LookupSpecialId"]=(a0,a1)=>(__PyObject_LookupSpecialId=Module["__PyObject_LookupSpecialId"]=wasmExports["_PyObject_LookupSpecialId"])(a0,a1);var _PyType_GetFlags=Module["_PyType_GetFlags"]=a0=>(_PyType_GetFlags=Module["_PyType_GetFlags"]=wasmExports["PyType_GetFlags"])(a0);var _PyType_SUPPORTS_WEAKREFS=Module["_PyType_SUPPORTS_WEAKREFS"]=a0=>(_PyType_SUPPORTS_WEAKREFS=Module["_PyType_SUPPORTS_WEAKREFS"]=wasmExports["PyType_SUPPORTS_WEAKREFS"])(a0);var __PyType_CalculateMetaclass=Module["__PyType_CalculateMetaclass"]=(a0,a1)=>(__PyType_CalculateMetaclass=Module["__PyType_CalculateMetaclass"]=wasmExports["_PyType_CalculateMetaclass"])(a0,a1);var _PyType_FromMetaclass=Module["_PyType_FromMetaclass"]=(a0,a1,a2,a3)=>(_PyType_FromMetaclass=Module["_PyType_FromMetaclass"]=wasmExports["PyType_FromMetaclass"])(a0,a1,a2,a3);var _PyType_FromModuleAndSpec=Module["_PyType_FromModuleAndSpec"]=(a0,a1,a2)=>(_PyType_FromModuleAndSpec=Module["_PyType_FromModuleAndSpec"]=wasmExports["PyType_FromModuleAndSpec"])(a0,a1,a2);var _PyType_FromSpec=Module["_PyType_FromSpec"]=a0=>(_PyType_FromSpec=Module["_PyType_FromSpec"]=wasmExports["PyType_FromSpec"])(a0);var _PyType_GetName=Module["_PyType_GetName"]=a0=>(_PyType_GetName=Module["_PyType_GetName"]=wasmExports["PyType_GetName"])(a0);var _PyType_GetSlot=Module["_PyType_GetSlot"]=(a0,a1)=>(_PyType_GetSlot=Module["_PyType_GetSlot"]=wasmExports["PyType_GetSlot"])(a0,a1);var _PyType_GetModule=Module["_PyType_GetModule"]=a0=>(_PyType_GetModule=Module["_PyType_GetModule"]=wasmExports["PyType_GetModule"])(a0);var _PyType_GetModuleState=Module["_PyType_GetModuleState"]=a0=>(_PyType_GetModuleState=Module["_PyType_GetModuleState"]=wasmExports["PyType_GetModuleState"])(a0);var _PyType_GetModuleByDef=Module["_PyType_GetModuleByDef"]=(a0,a1)=>(_PyType_GetModuleByDef=Module["_PyType_GetModuleByDef"]=wasmExports["PyType_GetModuleByDef"])(a0,a1);var _PyObject_GetTypeData=Module["_PyObject_GetTypeData"]=(a0,a1)=>(_PyObject_GetTypeData=Module["_PyObject_GetTypeData"]=wasmExports["PyObject_GetTypeData"])(a0,a1);var _PyType_GetTypeDataSize=Module["_PyType_GetTypeDataSize"]=a0=>(_PyType_GetTypeDataSize=Module["_PyType_GetTypeDataSize"]=wasmExports["PyType_GetTypeDataSize"])(a0);var _PyObject_GetItemData=Module["_PyObject_GetItemData"]=a0=>(_PyObject_GetItemData=Module["_PyObject_GetItemData"]=wasmExports["PyObject_GetItemData"])(a0);var __PyType_LookupId=Module["__PyType_LookupId"]=(a0,a1)=>(__PyType_LookupId=Module["__PyType_LookupId"]=wasmExports["_PyType_LookupId"])(a0,a1);var _PyArg_ParseTuple=Module["_PyArg_ParseTuple"]=(a0,a1,a2)=>(_PyArg_ParseTuple=Module["_PyArg_ParseTuple"]=wasmExports["PyArg_ParseTuple"])(a0,a1,a2);var _PyUnicode_IsIdentifier=Module["_PyUnicode_IsIdentifier"]=a0=>(_PyUnicode_IsIdentifier=Module["_PyUnicode_IsIdentifier"]=wasmExports["PyUnicode_IsIdentifier"])(a0);var _PyEval_GetGlobals=Module["_PyEval_GetGlobals"]=()=>(_PyEval_GetGlobals=Module["_PyEval_GetGlobals"]=wasmExports["PyEval_GetGlobals"])();var __PyWeakref_ClearRef=Module["__PyWeakref_ClearRef"]=a0=>(__PyWeakref_ClearRef=Module["__PyWeakref_ClearRef"]=wasmExports["_PyWeakref_ClearRef"])(a0);var _PyWeakref_NewRef=Module["_PyWeakref_NewRef"]=(a0,a1)=>(_PyWeakref_NewRef=Module["_PyWeakref_NewRef"]=wasmExports["PyWeakref_NewRef"])(a0,a1);var _PyImport_GetModule=Module["_PyImport_GetModule"]=a0=>(_PyImport_GetModule=Module["_PyImport_GetModule"]=wasmExports["PyImport_GetModule"])(a0);var _PyImport_Import=Module["_PyImport_Import"]=a0=>(_PyImport_Import=Module["_PyImport_Import"]=wasmExports["PyImport_Import"])(a0);var __PyArg_UnpackKeywordsWithVararg=Module["__PyArg_UnpackKeywordsWithVararg"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)=>(__PyArg_UnpackKeywordsWithVararg=Module["__PyArg_UnpackKeywordsWithVararg"]=wasmExports["_PyArg_UnpackKeywordsWithVararg"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);var __Py_hashtable_len=Module["__Py_hashtable_len"]=a0=>(__Py_hashtable_len=Module["__Py_hashtable_len"]=wasmExports["_Py_hashtable_len"])(a0);var __Py_GetErrorHandler=Module["__Py_GetErrorHandler"]=a0=>(__Py_GetErrorHandler=Module["__Py_GetErrorHandler"]=wasmExports["_Py_GetErrorHandler"])(a0);var __PyUnicode_FastCopyCharacters=Module["__PyUnicode_FastCopyCharacters"]=(a0,a1,a2,a3,a4)=>(__PyUnicode_FastCopyCharacters=Module["__PyUnicode_FastCopyCharacters"]=wasmExports["_PyUnicode_FastCopyCharacters"])(a0,a1,a2,a3,a4);var _PyUnicode_CopyCharacters=Module["_PyUnicode_CopyCharacters"]=(a0,a1,a2,a3,a4)=>(_PyUnicode_CopyCharacters=Module["_PyUnicode_CopyCharacters"]=wasmExports["PyUnicode_CopyCharacters"])(a0,a1,a2,a3,a4);var _PyUnicode_Resize=Module["_PyUnicode_Resize"]=(a0,a1)=>(_PyUnicode_Resize=Module["_PyUnicode_Resize"]=wasmExports["PyUnicode_Resize"])(a0,a1);var _PyUnicode_FromWideChar=Module["_PyUnicode_FromWideChar"]=(a0,a1)=>(_PyUnicode_FromWideChar=Module["_PyUnicode_FromWideChar"]=wasmExports["PyUnicode_FromWideChar"])(a0,a1);var _PyUnicode_FromKindAndData=Module["_PyUnicode_FromKindAndData"]=(a0,a1,a2)=>(_PyUnicode_FromKindAndData=Module["_PyUnicode_FromKindAndData"]=wasmExports["PyUnicode_FromKindAndData"])(a0,a1,a2);var __PyUnicode_FindMaxChar=Module["__PyUnicode_FindMaxChar"]=(a0,a1,a2)=>(__PyUnicode_FindMaxChar=Module["__PyUnicode_FindMaxChar"]=wasmExports["_PyUnicode_FindMaxChar"])(a0,a1,a2);var _PyUnicode_AsUCS4=Module["_PyUnicode_AsUCS4"]=(a0,a1,a2,a3)=>(_PyUnicode_AsUCS4=Module["_PyUnicode_AsUCS4"]=wasmExports["PyUnicode_AsUCS4"])(a0,a1,a2,a3);var _PyUnicode_AsUCS4Copy=Module["_PyUnicode_AsUCS4Copy"]=a0=>(_PyUnicode_AsUCS4Copy=Module["_PyUnicode_AsUCS4Copy"]=wasmExports["PyUnicode_AsUCS4Copy"])(a0);var _PyUnicode_Fill=Module["_PyUnicode_Fill"]=(a0,a1,a2,a3)=>(_PyUnicode_Fill=Module["_PyUnicode_Fill"]=wasmExports["PyUnicode_Fill"])(a0,a1,a2,a3);var _PyUnicode_AsWideChar=Module["_PyUnicode_AsWideChar"]=(a0,a1,a2)=>(_PyUnicode_AsWideChar=Module["_PyUnicode_AsWideChar"]=wasmExports["PyUnicode_AsWideChar"])(a0,a1,a2);var _PyUnicode_AsWideCharString=Module["_PyUnicode_AsWideCharString"]=(a0,a1)=>(_PyUnicode_AsWideCharString=Module["_PyUnicode_AsWideCharString"]=wasmExports["PyUnicode_AsWideCharString"])(a0,a1);var __PyUnicode_WideCharString_Converter=Module["__PyUnicode_WideCharString_Converter"]=(a0,a1)=>(__PyUnicode_WideCharString_Converter=Module["__PyUnicode_WideCharString_Converter"]=wasmExports["_PyUnicode_WideCharString_Converter"])(a0,a1);var __PyUnicode_WideCharString_Opt_Converter=Module["__PyUnicode_WideCharString_Opt_Converter"]=(a0,a1)=>(__PyUnicode_WideCharString_Opt_Converter=Module["__PyUnicode_WideCharString_Opt_Converter"]=wasmExports["_PyUnicode_WideCharString_Opt_Converter"])(a0,a1);var _PyUnicode_FromOrdinal=Module["_PyUnicode_FromOrdinal"]=a0=>(_PyUnicode_FromOrdinal=Module["_PyUnicode_FromOrdinal"]=wasmExports["PyUnicode_FromOrdinal"])(a0);var _PyUnicode_FromObject=Module["_PyUnicode_FromObject"]=a0=>(_PyUnicode_FromObject=Module["_PyUnicode_FromObject"]=wasmExports["PyUnicode_FromObject"])(a0);var __PyInterpreterState_GetConfig=Module["__PyInterpreterState_GetConfig"]=a0=>(__PyInterpreterState_GetConfig=Module["__PyInterpreterState_GetConfig"]=wasmExports["_PyInterpreterState_GetConfig"])(a0);var __PyCodec_Lookup=Module["__PyCodec_Lookup"]=a0=>(__PyCodec_Lookup=Module["__PyCodec_Lookup"]=wasmExports["_PyCodec_Lookup"])(a0);var _PyCodec_LookupError=Module["_PyCodec_LookupError"]=a0=>(_PyCodec_LookupError=Module["_PyCodec_LookupError"]=wasmExports["PyCodec_LookupError"])(a0);var _PyUnicode_DecodeUTF16Stateful=Module["_PyUnicode_DecodeUTF16Stateful"]=(a0,a1,a2,a3,a4)=>(_PyUnicode_DecodeUTF16Stateful=Module["_PyUnicode_DecodeUTF16Stateful"]=wasmExports["PyUnicode_DecodeUTF16Stateful"])(a0,a1,a2,a3,a4);var _PyUnicode_DecodeUTF32Stateful=Module["_PyUnicode_DecodeUTF32Stateful"]=(a0,a1,a2,a3,a4)=>(_PyUnicode_DecodeUTF32Stateful=Module["_PyUnicode_DecodeUTF32Stateful"]=wasmExports["PyUnicode_DecodeUTF32Stateful"])(a0,a1,a2,a3,a4);var __PyCodec_DecodeText=Module["__PyCodec_DecodeText"]=(a0,a1,a2)=>(__PyCodec_DecodeText=Module["__PyCodec_DecodeText"]=wasmExports["_PyCodec_DecodeText"])(a0,a1,a2);var _PyUnicode_DecodeUTF16=Module["_PyUnicode_DecodeUTF16"]=(a0,a1,a2,a3)=>(_PyUnicode_DecodeUTF16=Module["_PyUnicode_DecodeUTF16"]=wasmExports["PyUnicode_DecodeUTF16"])(a0,a1,a2,a3);var _PyUnicode_DecodeUTF32=Module["_PyUnicode_DecodeUTF32"]=(a0,a1,a2,a3)=>(_PyUnicode_DecodeUTF32=Module["_PyUnicode_DecodeUTF32"]=wasmExports["PyUnicode_DecodeUTF32"])(a0,a1,a2,a3);var _PyUnicode_AsDecodedObject=Module["_PyUnicode_AsDecodedObject"]=(a0,a1,a2)=>(_PyUnicode_AsDecodedObject=Module["_PyUnicode_AsDecodedObject"]=wasmExports["PyUnicode_AsDecodedObject"])(a0,a1,a2);var _PyCodec_Decode=Module["_PyCodec_Decode"]=(a0,a1,a2)=>(_PyCodec_Decode=Module["_PyCodec_Decode"]=wasmExports["PyCodec_Decode"])(a0,a1,a2);var _PyUnicode_AsDecodedUnicode=Module["_PyUnicode_AsDecodedUnicode"]=(a0,a1,a2)=>(_PyUnicode_AsDecodedUnicode=Module["_PyUnicode_AsDecodedUnicode"]=wasmExports["PyUnicode_AsDecodedUnicode"])(a0,a1,a2);var _PyUnicode_AsEncodedObject=Module["_PyUnicode_AsEncodedObject"]=(a0,a1,a2)=>(_PyUnicode_AsEncodedObject=Module["_PyUnicode_AsEncodedObject"]=wasmExports["PyUnicode_AsEncodedObject"])(a0,a1,a2);var _PyCodec_Encode=Module["_PyCodec_Encode"]=(a0,a1,a2)=>(_PyCodec_Encode=Module["_PyCodec_Encode"]=wasmExports["PyCodec_Encode"])(a0,a1,a2);var _PyUnicode_EncodeLocale=Module["_PyUnicode_EncodeLocale"]=(a0,a1)=>(_PyUnicode_EncodeLocale=Module["_PyUnicode_EncodeLocale"]=wasmExports["PyUnicode_EncodeLocale"])(a0,a1);var __Py_EncodeLocaleEx=Module["__Py_EncodeLocaleEx"]=(a0,a1,a2,a3,a4,a5)=>(__Py_EncodeLocaleEx=Module["__Py_EncodeLocaleEx"]=wasmExports["_Py_EncodeLocaleEx"])(a0,a1,a2,a3,a4,a5);var _PyCodec_StrictErrors=Module["_PyCodec_StrictErrors"]=a0=>(_PyCodec_StrictErrors=Module["_PyCodec_StrictErrors"]=wasmExports["PyCodec_StrictErrors"])(a0);var _PyUnicode_EncodeFSDefault=Module["_PyUnicode_EncodeFSDefault"]=a0=>(_PyUnicode_EncodeFSDefault=Module["_PyUnicode_EncodeFSDefault"]=wasmExports["PyUnicode_EncodeFSDefault"])(a0);var __PyUnicode_EncodeUTF16=Module["__PyUnicode_EncodeUTF16"]=(a0,a1,a2)=>(__PyUnicode_EncodeUTF16=Module["__PyUnicode_EncodeUTF16"]=wasmExports["_PyUnicode_EncodeUTF16"])(a0,a1,a2);var __PyUnicode_EncodeUTF32=Module["__PyUnicode_EncodeUTF32"]=(a0,a1,a2)=>(__PyUnicode_EncodeUTF32=Module["__PyUnicode_EncodeUTF32"]=wasmExports["_PyUnicode_EncodeUTF32"])(a0,a1,a2);var __PyCodec_EncodeText=Module["__PyCodec_EncodeText"]=(a0,a1,a2)=>(__PyCodec_EncodeText=Module["__PyCodec_EncodeText"]=wasmExports["_PyCodec_EncodeText"])(a0,a1,a2);var _wcscmp=Module["_wcscmp"]=(a0,a1)=>(_wcscmp=Module["_wcscmp"]=wasmExports["wcscmp"])(a0,a1);var __PyUnicode_AsLatin1String=Module["__PyUnicode_AsLatin1String"]=(a0,a1)=>(__PyUnicode_AsLatin1String=Module["__PyUnicode_AsLatin1String"]=wasmExports["_PyUnicode_AsLatin1String"])(a0,a1);var _PyUnicode_AsEncodedUnicode=Module["_PyUnicode_AsEncodedUnicode"]=(a0,a1,a2)=>(_PyUnicode_AsEncodedUnicode=Module["_PyUnicode_AsEncodedUnicode"]=wasmExports["PyUnicode_AsEncodedUnicode"])(a0,a1,a2);var _PyUnicode_DecodeLocaleAndSize=Module["_PyUnicode_DecodeLocaleAndSize"]=(a0,a1,a2)=>(_PyUnicode_DecodeLocaleAndSize=Module["_PyUnicode_DecodeLocaleAndSize"]=wasmExports["PyUnicode_DecodeLocaleAndSize"])(a0,a1,a2);var __Py_DecodeLocaleEx=Module["__Py_DecodeLocaleEx"]=(a0,a1,a2,a3,a4,a5)=>(__Py_DecodeLocaleEx=Module["__Py_DecodeLocaleEx"]=wasmExports["_Py_DecodeLocaleEx"])(a0,a1,a2,a3,a4,a5);var _PyUnicode_DecodeLocale=Module["_PyUnicode_DecodeLocale"]=(a0,a1)=>(_PyUnicode_DecodeLocale=Module["_PyUnicode_DecodeLocale"]=wasmExports["PyUnicode_DecodeLocale"])(a0,a1);var _PyUnicode_DecodeFSDefaultAndSize=Module["_PyUnicode_DecodeFSDefaultAndSize"]=(a0,a1)=>(_PyUnicode_DecodeFSDefaultAndSize=Module["_PyUnicode_DecodeFSDefaultAndSize"]=wasmExports["PyUnicode_DecodeFSDefaultAndSize"])(a0,a1);var _PyUnicode_FSConverter=Module["_PyUnicode_FSConverter"]=(a0,a1)=>(_PyUnicode_FSConverter=Module["_PyUnicode_FSConverter"]=wasmExports["PyUnicode_FSConverter"])(a0,a1);var _PyOS_FSPath=Module["_PyOS_FSPath"]=a0=>(_PyOS_FSPath=Module["_PyOS_FSPath"]=wasmExports["PyOS_FSPath"])(a0);var _PyUnicode_FSDecoder=Module["_PyUnicode_FSDecoder"]=(a0,a1)=>(_PyUnicode_FSDecoder=Module["_PyUnicode_FSDecoder"]=wasmExports["PyUnicode_FSDecoder"])(a0,a1);var _wmemchr=Module["_wmemchr"]=(a0,a1,a2)=>(_wmemchr=Module["_wmemchr"]=wasmExports["wmemchr"])(a0,a1,a2);var _PyUnicode_GetSize=Module["_PyUnicode_GetSize"]=a0=>(_PyUnicode_GetSize=Module["_PyUnicode_GetSize"]=wasmExports["PyUnicode_GetSize"])(a0);var _PyUnicode_WriteChar=Module["_PyUnicode_WriteChar"]=(a0,a1,a2)=>(_PyUnicode_WriteChar=Module["_PyUnicode_WriteChar"]=wasmExports["PyUnicode_WriteChar"])(a0,a1,a2);var _PyUnicode_DecodeUTF7=Module["_PyUnicode_DecodeUTF7"]=(a0,a1,a2)=>(_PyUnicode_DecodeUTF7=Module["_PyUnicode_DecodeUTF7"]=wasmExports["PyUnicode_DecodeUTF7"])(a0,a1,a2);var _PyUnicode_DecodeUTF7Stateful=Module["_PyUnicode_DecodeUTF7Stateful"]=(a0,a1,a2,a3)=>(_PyUnicode_DecodeUTF7Stateful=Module["_PyUnicode_DecodeUTF7Stateful"]=wasmExports["PyUnicode_DecodeUTF7Stateful"])(a0,a1,a2,a3);var __PyUnicode_EncodeUTF7=Module["__PyUnicode_EncodeUTF7"]=(a0,a1,a2,a3)=>(__PyUnicode_EncodeUTF7=Module["__PyUnicode_EncodeUTF7"]=wasmExports["_PyUnicode_EncodeUTF7"])(a0,a1,a2,a3);var __Py_DecodeUTF8Ex=Module["__Py_DecodeUTF8Ex"]=(a0,a1,a2,a3,a4,a5)=>(__Py_DecodeUTF8Ex=Module["__Py_DecodeUTF8Ex"]=wasmExports["_Py_DecodeUTF8Ex"])(a0,a1,a2,a3,a4,a5);var __Py_DecodeUTF8_surrogateescape=Module["__Py_DecodeUTF8_surrogateescape"]=(a0,a1,a2)=>(__Py_DecodeUTF8_surrogateescape=Module["__Py_DecodeUTF8_surrogateescape"]=wasmExports["_Py_DecodeUTF8_surrogateescape"])(a0,a1,a2);var __Py_EncodeUTF8Ex=Module["__Py_EncodeUTF8Ex"]=(a0,a1,a2,a3,a4,a5)=>(__Py_EncodeUTF8Ex=Module["__Py_EncodeUTF8Ex"]=wasmExports["_Py_EncodeUTF8Ex"])(a0,a1,a2,a3,a4,a5);var _PyUnicode_AsUTF32String=Module["_PyUnicode_AsUTF32String"]=a0=>(_PyUnicode_AsUTF32String=Module["_PyUnicode_AsUTF32String"]=wasmExports["PyUnicode_AsUTF32String"])(a0);var _PyUnicode_AsUTF16String=Module["_PyUnicode_AsUTF16String"]=a0=>(_PyUnicode_AsUTF16String=Module["_PyUnicode_AsUTF16String"]=wasmExports["PyUnicode_AsUTF16String"])(a0);var __PyUnicode_DecodeUnicodeEscapeStateful=Module["__PyUnicode_DecodeUnicodeEscapeStateful"]=(a0,a1,a2,a3)=>(__PyUnicode_DecodeUnicodeEscapeStateful=Module["__PyUnicode_DecodeUnicodeEscapeStateful"]=wasmExports["_PyUnicode_DecodeUnicodeEscapeStateful"])(a0,a1,a2,a3);var _PyUnicode_DecodeUnicodeEscape=Module["_PyUnicode_DecodeUnicodeEscape"]=(a0,a1,a2)=>(_PyUnicode_DecodeUnicodeEscape=Module["_PyUnicode_DecodeUnicodeEscape"]=wasmExports["PyUnicode_DecodeUnicodeEscape"])(a0,a1,a2);var _PyUnicode_AsUnicodeEscapeString=Module["_PyUnicode_AsUnicodeEscapeString"]=a0=>(_PyUnicode_AsUnicodeEscapeString=Module["_PyUnicode_AsUnicodeEscapeString"]=wasmExports["PyUnicode_AsUnicodeEscapeString"])(a0);var __PyUnicode_DecodeRawUnicodeEscapeStateful=Module["__PyUnicode_DecodeRawUnicodeEscapeStateful"]=(a0,a1,a2,a3)=>(__PyUnicode_DecodeRawUnicodeEscapeStateful=Module["__PyUnicode_DecodeRawUnicodeEscapeStateful"]=wasmExports["_PyUnicode_DecodeRawUnicodeEscapeStateful"])(a0,a1,a2,a3);var _PyUnicode_DecodeRawUnicodeEscape=Module["_PyUnicode_DecodeRawUnicodeEscape"]=(a0,a1,a2)=>(_PyUnicode_DecodeRawUnicodeEscape=Module["_PyUnicode_DecodeRawUnicodeEscape"]=wasmExports["PyUnicode_DecodeRawUnicodeEscape"])(a0,a1,a2);var _PyUnicode_AsRawUnicodeEscapeString=Module["_PyUnicode_AsRawUnicodeEscapeString"]=a0=>(_PyUnicode_AsRawUnicodeEscapeString=Module["_PyUnicode_AsRawUnicodeEscapeString"]=wasmExports["PyUnicode_AsRawUnicodeEscapeString"])(a0);var _PyUnicode_AsLatin1String=Module["_PyUnicode_AsLatin1String"]=a0=>(_PyUnicode_AsLatin1String=Module["_PyUnicode_AsLatin1String"]=wasmExports["PyUnicode_AsLatin1String"])(a0);var __PyUnicodeWriter_PrepareKindInternal=Module["__PyUnicodeWriter_PrepareKindInternal"]=(a0,a1)=>(__PyUnicodeWriter_PrepareKindInternal=Module["__PyUnicodeWriter_PrepareKindInternal"]=wasmExports["_PyUnicodeWriter_PrepareKindInternal"])(a0,a1);var _PyUnicode_DecodeCharmap=Module["_PyUnicode_DecodeCharmap"]=(a0,a1,a2,a3)=>(_PyUnicode_DecodeCharmap=Module["_PyUnicode_DecodeCharmap"]=wasmExports["PyUnicode_DecodeCharmap"])(a0,a1,a2,a3);var _PyUnicode_BuildEncodingMap=Module["_PyUnicode_BuildEncodingMap"]=a0=>(_PyUnicode_BuildEncodingMap=Module["_PyUnicode_BuildEncodingMap"]=wasmExports["PyUnicode_BuildEncodingMap"])(a0);var __PyUnicode_EncodeCharmap=Module["__PyUnicode_EncodeCharmap"]=(a0,a1,a2)=>(__PyUnicode_EncodeCharmap=Module["__PyUnicode_EncodeCharmap"]=wasmExports["_PyUnicode_EncodeCharmap"])(a0,a1,a2);var _PyUnicode_AsCharmapString=Module["_PyUnicode_AsCharmapString"]=(a0,a1)=>(_PyUnicode_AsCharmapString=Module["_PyUnicode_AsCharmapString"]=wasmExports["PyUnicode_AsCharmapString"])(a0,a1);var _PyUnicode_Translate=Module["_PyUnicode_Translate"]=(a0,a1,a2)=>(_PyUnicode_Translate=Module["_PyUnicode_Translate"]=wasmExports["PyUnicode_Translate"])(a0,a1,a2);var __PyUnicode_IsWhitespace=Module["__PyUnicode_IsWhitespace"]=a0=>(__PyUnicode_IsWhitespace=Module["__PyUnicode_IsWhitespace"]=wasmExports["_PyUnicode_IsWhitespace"])(a0);var __PyUnicode_ToDecimalDigit=Module["__PyUnicode_ToDecimalDigit"]=a0=>(__PyUnicode_ToDecimalDigit=Module["__PyUnicode_ToDecimalDigit"]=wasmExports["_PyUnicode_ToDecimalDigit"])(a0);var __PyUnicode_InsertThousandsGrouping=Module["__PyUnicode_InsertThousandsGrouping"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(__PyUnicode_InsertThousandsGrouping=Module["__PyUnicode_InsertThousandsGrouping"]=wasmExports["_PyUnicode_InsertThousandsGrouping"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var _PyUnicode_Count=Module["_PyUnicode_Count"]=(a0,a1,a2,a3)=>(_PyUnicode_Count=Module["_PyUnicode_Count"]=wasmExports["PyUnicode_Count"])(a0,a1,a2,a3);var _PyUnicode_Find=Module["_PyUnicode_Find"]=(a0,a1,a2,a3,a4)=>(_PyUnicode_Find=Module["_PyUnicode_Find"]=wasmExports["PyUnicode_Find"])(a0,a1,a2,a3,a4);var _PyUnicode_FindChar=Module["_PyUnicode_FindChar"]=(a0,a1,a2,a3,a4)=>(_PyUnicode_FindChar=Module["_PyUnicode_FindChar"]=wasmExports["PyUnicode_FindChar"])(a0,a1,a2,a3,a4);var _PyUnicode_Tailmatch=Module["_PyUnicode_Tailmatch"]=(a0,a1,a2,a3,a4)=>(_PyUnicode_Tailmatch=Module["_PyUnicode_Tailmatch"]=wasmExports["PyUnicode_Tailmatch"])(a0,a1,a2,a3,a4);var __PyUnicode_JoinArray=Module["__PyUnicode_JoinArray"]=(a0,a1,a2)=>(__PyUnicode_JoinArray=Module["__PyUnicode_JoinArray"]=wasmExports["_PyUnicode_JoinArray"])(a0,a1,a2);var __PyUnicode_FastFill=Module["__PyUnicode_FastFill"]=(a0,a1,a2,a3)=>(__PyUnicode_FastFill=Module["__PyUnicode_FastFill"]=wasmExports["_PyUnicode_FastFill"])(a0,a1,a2,a3);var _PyUnicode_Splitlines=Module["_PyUnicode_Splitlines"]=(a0,a1)=>(_PyUnicode_Splitlines=Module["_PyUnicode_Splitlines"]=wasmExports["PyUnicode_Splitlines"])(a0,a1);var __PyUnicode_IsLinebreak=Module["__PyUnicode_IsLinebreak"]=a0=>(__PyUnicode_IsLinebreak=Module["__PyUnicode_IsLinebreak"]=wasmExports["_PyUnicode_IsLinebreak"])(a0);var _wmemcmp=Module["_wmemcmp"]=(a0,a1,a2)=>(_wmemcmp=Module["_wmemcmp"]=wasmExports["wmemcmp"])(a0,a1,a2);var __PyUnicode_EqualToASCIIId=Module["__PyUnicode_EqualToASCIIId"]=(a0,a1)=>(__PyUnicode_EqualToASCIIId=Module["__PyUnicode_EqualToASCIIId"]=wasmExports["_PyUnicode_EqualToASCIIId"])(a0,a1);var _PyUnicode_RichCompare=Module["_PyUnicode_RichCompare"]=(a0,a1,a2)=>(_PyUnicode_RichCompare=Module["_PyUnicode_RichCompare"]=wasmExports["PyUnicode_RichCompare"])(a0,a1,a2);var _PyUnicode_Contains=Module["_PyUnicode_Contains"]=(a0,a1)=>(_PyUnicode_Contains=Module["_PyUnicode_Contains"]=wasmExports["PyUnicode_Contains"])(a0,a1);var _PyUnicode_Concat=Module["_PyUnicode_Concat"]=(a0,a1)=>(_PyUnicode_Concat=Module["_PyUnicode_Concat"]=wasmExports["PyUnicode_Concat"])(a0,a1);var _PyUnicode_Append=Module["_PyUnicode_Append"]=(a0,a1)=>(_PyUnicode_Append=Module["_PyUnicode_Append"]=wasmExports["PyUnicode_Append"])(a0,a1);var _PyUnicode_AppendAndDel=Module["_PyUnicode_AppendAndDel"]=(a0,a1)=>(_PyUnicode_AppendAndDel=Module["_PyUnicode_AppendAndDel"]=wasmExports["PyUnicode_AppendAndDel"])(a0,a1);var __PyUnicode_IsXidStart=Module["__PyUnicode_IsXidStart"]=a0=>(__PyUnicode_IsXidStart=Module["__PyUnicode_IsXidStart"]=wasmExports["_PyUnicode_IsXidStart"])(a0);var __PyUnicode_IsXidContinue=Module["__PyUnicode_IsXidContinue"]=a0=>(__PyUnicode_IsXidContinue=Module["__PyUnicode_IsXidContinue"]=wasmExports["_PyUnicode_IsXidContinue"])(a0);var __PyUnicode_XStrip=Module["__PyUnicode_XStrip"]=(a0,a1,a2)=>(__PyUnicode_XStrip=Module["__PyUnicode_XStrip"]=wasmExports["_PyUnicode_XStrip"])(a0,a1,a2);var _PyUnicode_Replace=Module["_PyUnicode_Replace"]=(a0,a1,a2,a3)=>(_PyUnicode_Replace=Module["_PyUnicode_Replace"]=wasmExports["PyUnicode_Replace"])(a0,a1,a2,a3);var _PyUnicode_Split=Module["_PyUnicode_Split"]=(a0,a1,a2)=>(_PyUnicode_Split=Module["_PyUnicode_Split"]=wasmExports["PyUnicode_Split"])(a0,a1,a2);var _PyUnicode_Partition=Module["_PyUnicode_Partition"]=(a0,a1)=>(_PyUnicode_Partition=Module["_PyUnicode_Partition"]=wasmExports["PyUnicode_Partition"])(a0,a1);var _PyUnicode_RPartition=Module["_PyUnicode_RPartition"]=(a0,a1)=>(_PyUnicode_RPartition=Module["_PyUnicode_RPartition"]=wasmExports["PyUnicode_RPartition"])(a0,a1);var _PyUnicode_RSplit=Module["_PyUnicode_RSplit"]=(a0,a1,a2)=>(_PyUnicode_RSplit=Module["_PyUnicode_RSplit"]=wasmExports["PyUnicode_RSplit"])(a0,a1,a2);var __PyUnicodeWriter_WriteSubstring=Module["__PyUnicodeWriter_WriteSubstring"]=(a0,a1,a2,a3)=>(__PyUnicodeWriter_WriteSubstring=Module["__PyUnicodeWriter_WriteSubstring"]=wasmExports["_PyUnicodeWriter_WriteSubstring"])(a0,a1,a2,a3);var __PyUnicodeWriter_WriteLatin1String=Module["__PyUnicodeWriter_WriteLatin1String"]=(a0,a1,a2)=>(__PyUnicodeWriter_WriteLatin1String=Module["__PyUnicodeWriter_WriteLatin1String"]=wasmExports["_PyUnicodeWriter_WriteLatin1String"])(a0,a1,a2);var _PyUnicode_Format=Module["_PyUnicode_Format"]=(a0,a1)=>(_PyUnicode_Format=Module["_PyUnicode_Format"]=wasmExports["PyUnicode_Format"])(a0,a1);var __Py_hashtable_new_full=Module["__Py_hashtable_new_full"]=(a0,a1,a2,a3,a4)=>(__Py_hashtable_new_full=Module["__Py_hashtable_new_full"]=wasmExports["_Py_hashtable_new_full"])(a0,a1,a2,a3,a4);var __Py_hashtable_get=Module["__Py_hashtable_get"]=(a0,a1)=>(__Py_hashtable_get=Module["__Py_hashtable_get"]=wasmExports["_Py_hashtable_get"])(a0,a1);var __Py_hashtable_set=Module["__Py_hashtable_set"]=(a0,a1,a2)=>(__Py_hashtable_set=Module["__Py_hashtable_set"]=wasmExports["_Py_hashtable_set"])(a0,a1,a2);var __PyUnicode_InternInPlace=Module["__PyUnicode_InternInPlace"]=(a0,a1)=>(__PyUnicode_InternInPlace=Module["__PyUnicode_InternInPlace"]=wasmExports["_PyUnicode_InternInPlace"])(a0,a1);var _PyUnicode_InternInPlace=Module["_PyUnicode_InternInPlace"]=a0=>(_PyUnicode_InternInPlace=Module["_PyUnicode_InternInPlace"]=wasmExports["PyUnicode_InternInPlace"])(a0);var _PyUnicode_InternImmortal=Module["_PyUnicode_InternImmortal"]=a0=>(_PyUnicode_InternImmortal=Module["_PyUnicode_InternImmortal"]=wasmExports["PyUnicode_InternImmortal"])(a0);var __Py_hashtable_destroy=Module["__Py_hashtable_destroy"]=a0=>(__Py_hashtable_destroy=Module["__Py_hashtable_destroy"]=wasmExports["_Py_hashtable_destroy"])(a0);var _PyInit__string=Module["_PyInit__string"]=()=>(_PyInit__string=Module["_PyInit__string"]=wasmExports["PyInit__string"])();var __PyUnicode_IsLowercase=Module["__PyUnicode_IsLowercase"]=a0=>(__PyUnicode_IsLowercase=Module["__PyUnicode_IsLowercase"]=wasmExports["_PyUnicode_IsLowercase"])(a0);var __PyUnicode_IsUppercase=Module["__PyUnicode_IsUppercase"]=a0=>(__PyUnicode_IsUppercase=Module["__PyUnicode_IsUppercase"]=wasmExports["_PyUnicode_IsUppercase"])(a0);var __PyUnicode_IsTitlecase=Module["__PyUnicode_IsTitlecase"]=a0=>(__PyUnicode_IsTitlecase=Module["__PyUnicode_IsTitlecase"]=wasmExports["_PyUnicode_IsTitlecase"])(a0);var __PyUnicode_IsDecimalDigit=Module["__PyUnicode_IsDecimalDigit"]=a0=>(__PyUnicode_IsDecimalDigit=Module["__PyUnicode_IsDecimalDigit"]=wasmExports["_PyUnicode_IsDecimalDigit"])(a0);var __PyUnicode_IsDigit=Module["__PyUnicode_IsDigit"]=a0=>(__PyUnicode_IsDigit=Module["__PyUnicode_IsDigit"]=wasmExports["_PyUnicode_IsDigit"])(a0);var __PyUnicode_IsNumeric=Module["__PyUnicode_IsNumeric"]=a0=>(__PyUnicode_IsNumeric=Module["__PyUnicode_IsNumeric"]=wasmExports["_PyUnicode_IsNumeric"])(a0);var __PyUnicode_IsAlpha=Module["__PyUnicode_IsAlpha"]=a0=>(__PyUnicode_IsAlpha=Module["__PyUnicode_IsAlpha"]=wasmExports["_PyUnicode_IsAlpha"])(a0);var __PyUnicode_FormatAdvancedWriter=Module["__PyUnicode_FormatAdvancedWriter"]=(a0,a1,a2,a3,a4)=>(__PyUnicode_FormatAdvancedWriter=Module["__PyUnicode_FormatAdvancedWriter"]=wasmExports["_PyUnicode_FormatAdvancedWriter"])(a0,a1,a2,a3,a4);var __PyUnicode_ToTitleFull=Module["__PyUnicode_ToTitleFull"]=(a0,a1)=>(__PyUnicode_ToTitleFull=Module["__PyUnicode_ToTitleFull"]=wasmExports["_PyUnicode_ToTitleFull"])(a0,a1);var __PyUnicode_IsCaseIgnorable=Module["__PyUnicode_IsCaseIgnorable"]=a0=>(__PyUnicode_IsCaseIgnorable=Module["__PyUnicode_IsCaseIgnorable"]=wasmExports["_PyUnicode_IsCaseIgnorable"])(a0);var __PyUnicode_IsCased=Module["__PyUnicode_IsCased"]=a0=>(__PyUnicode_IsCased=Module["__PyUnicode_IsCased"]=wasmExports["_PyUnicode_IsCased"])(a0);var __PyUnicode_ToLowerFull=Module["__PyUnicode_ToLowerFull"]=(a0,a1)=>(__PyUnicode_ToLowerFull=Module["__PyUnicode_ToLowerFull"]=wasmExports["_PyUnicode_ToLowerFull"])(a0,a1);var __PyUnicode_ToFoldedFull=Module["__PyUnicode_ToFoldedFull"]=(a0,a1)=>(__PyUnicode_ToFoldedFull=Module["__PyUnicode_ToFoldedFull"]=wasmExports["_PyUnicode_ToFoldedFull"])(a0,a1);var __PyUnicode_ToUpperFull=Module["__PyUnicode_ToUpperFull"]=(a0,a1)=>(__PyUnicode_ToUpperFull=Module["__PyUnicode_ToUpperFull"]=wasmExports["_PyUnicode_ToUpperFull"])(a0,a1);var __PyUnicode_ToNumeric=Module["__PyUnicode_ToNumeric"]=a0=>(__PyUnicode_ToNumeric=Module["__PyUnicode_ToNumeric"]=wasmExports["_PyUnicode_ToNumeric"])(a0);var __PyUnicode_ToTitlecase=Module["__PyUnicode_ToTitlecase"]=a0=>(__PyUnicode_ToTitlecase=Module["__PyUnicode_ToTitlecase"]=wasmExports["_PyUnicode_ToTitlecase"])(a0);var __PyUnicode_ToDigit=Module["__PyUnicode_ToDigit"]=a0=>(__PyUnicode_ToDigit=Module["__PyUnicode_ToDigit"]=wasmExports["_PyUnicode_ToDigit"])(a0);var __PyUnicode_ToUppercase=Module["__PyUnicode_ToUppercase"]=a0=>(__PyUnicode_ToUppercase=Module["__PyUnicode_ToUppercase"]=wasmExports["_PyUnicode_ToUppercase"])(a0);var __PyUnicode_ToLowercase=Module["__PyUnicode_ToLowercase"]=a0=>(__PyUnicode_ToLowercase=Module["__PyUnicode_ToLowercase"]=wasmExports["_PyUnicode_ToLowercase"])(a0);var __PyWeakref_GetWeakrefCount=Module["__PyWeakref_GetWeakrefCount"]=a0=>(__PyWeakref_GetWeakrefCount=Module["__PyWeakref_GetWeakrefCount"]=wasmExports["_PyWeakref_GetWeakrefCount"])(a0);var _PyWeakref_NewProxy=Module["_PyWeakref_NewProxy"]=(a0,a1)=>(_PyWeakref_NewProxy=Module["_PyWeakref_NewProxy"]=wasmExports["PyWeakref_NewProxy"])(a0,a1);var _PyWeakref_GetObject=Module["_PyWeakref_GetObject"]=a0=>(_PyWeakref_GetObject=Module["_PyWeakref_GetObject"]=wasmExports["PyWeakref_GetObject"])(a0);var _PyErr_ResourceWarning=Module["_PyErr_ResourceWarning"]=(a0,a1,a2,a3)=>(_PyErr_ResourceWarning=Module["_PyErr_ResourceWarning"]=wasmExports["PyErr_ResourceWarning"])(a0,a1,a2,a3);var _PyErr_WarnExplicit=Module["_PyErr_WarnExplicit"]=(a0,a1,a2,a3,a4,a5)=>(_PyErr_WarnExplicit=Module["_PyErr_WarnExplicit"]=wasmExports["PyErr_WarnExplicit"])(a0,a1,a2,a3,a4,a5);var _PyErr_WarnExplicitFormat=Module["_PyErr_WarnExplicitFormat"]=(a0,a1,a2,a3,a4,a5,a6)=>(_PyErr_WarnExplicitFormat=Module["_PyErr_WarnExplicitFormat"]=wasmExports["PyErr_WarnExplicitFormat"])(a0,a1,a2,a3,a4,a5,a6);var __Py_IsInterpreterFinalizing=Module["__Py_IsInterpreterFinalizing"]=a0=>(__Py_IsInterpreterFinalizing=Module["__Py_IsInterpreterFinalizing"]=wasmExports["_Py_IsInterpreterFinalizing"])(a0);var __PyWarnings_Init=Module["__PyWarnings_Init"]=()=>(__PyWarnings_Init=Module["__PyWarnings_Init"]=wasmExports["_PyWarnings_Init"])();var _PyThreadState_GetFrame=Module["_PyThreadState_GetFrame"]=a0=>(_PyThreadState_GetFrame=Module["_PyThreadState_GetFrame"]=wasmExports["PyThreadState_GetFrame"])(a0);var __PySys_GetAttr=Module["__PySys_GetAttr"]=(a0,a1)=>(__PySys_GetAttr=Module["__PySys_GetAttr"]=wasmExports["_PySys_GetAttr"])(a0,a1);var __Py_DisplaySourceLine=Module["__Py_DisplaySourceLine"]=(a0,a1,a2,a3,a4,a5)=>(__Py_DisplaySourceLine=Module["__Py_DisplaySourceLine"]=wasmExports["_Py_DisplaySourceLine"])(a0,a1,a2,a3,a4,a5);var _PyModule_AddObjectRef=Module["_PyModule_AddObjectRef"]=(a0,a1,a2)=>(_PyModule_AddObjectRef=Module["_PyModule_AddObjectRef"]=wasmExports["PyModule_AddObjectRef"])(a0,a1,a2);var _PyInit__ast=Module["_PyInit__ast"]=()=>(_PyInit__ast=Module["_PyInit__ast"]=wasmExports["PyInit__ast"])();var _PyModule_AddIntConstant=Module["_PyModule_AddIntConstant"]=(a0,a1,a2)=>(_PyModule_AddIntConstant=Module["_PyModule_AddIntConstant"]=wasmExports["PyModule_AddIntConstant"])(a0,a1,a2);var _PyInit__tokenize=Module["_PyInit__tokenize"]=()=>(_PyInit__tokenize=Module["_PyInit__tokenize"]=wasmExports["PyInit__tokenize"])();var _PyModule_AddType=Module["_PyModule_AddType"]=(a0,a1)=>(_PyModule_AddType=Module["_PyModule_AddType"]=wasmExports["PyModule_AddType"])(a0,a1);var _PyErr_SyntaxLocationObject=Module["_PyErr_SyntaxLocationObject"]=(a0,a1,a2)=>(_PyErr_SyntaxLocationObject=Module["_PyErr_SyntaxLocationObject"]=wasmExports["PyErr_SyntaxLocationObject"])(a0,a1,a2);var _snprintf=Module["_snprintf"]=(a0,a1,a2,a3)=>(_snprintf=Module["_snprintf"]=wasmExports["snprintf"])(a0,a1,a2,a3);var _PyImport_ImportModuleLevelObject=Module["_PyImport_ImportModuleLevelObject"]=(a0,a1,a2,a3,a4)=>(_PyImport_ImportModuleLevelObject=Module["_PyImport_ImportModuleLevelObject"]=wasmExports["PyImport_ImportModuleLevelObject"])(a0,a1,a2,a3,a4);var _PyEval_MergeCompilerFlags=Module["_PyEval_MergeCompilerFlags"]=a0=>(_PyEval_MergeCompilerFlags=Module["_PyEval_MergeCompilerFlags"]=wasmExports["PyEval_MergeCompilerFlags"])(a0);var __PyArena_New=Module["__PyArena_New"]=()=>(__PyArena_New=Module["__PyArena_New"]=wasmExports["_PyArena_New"])();var __PyArena_Free=Module["__PyArena_Free"]=a0=>(__PyArena_Free=Module["__PyArena_Free"]=wasmExports["_PyArena_Free"])(a0);var __PyAST_Compile=Module["__PyAST_Compile"]=(a0,a1,a2,a3,a4)=>(__PyAST_Compile=Module["__PyAST_Compile"]=wasmExports["_PyAST_Compile"])(a0,a1,a2,a3,a4);var __Py_SourceAsString=Module["__Py_SourceAsString"]=(a0,a1,a2,a3,a4)=>(__Py_SourceAsString=Module["__Py_SourceAsString"]=wasmExports["_Py_SourceAsString"])(a0,a1,a2,a3,a4);var _Py_CompileStringObject=Module["_Py_CompileStringObject"]=(a0,a1,a2,a3,a4)=>(_Py_CompileStringObject=Module["_Py_CompileStringObject"]=wasmExports["Py_CompileStringObject"])(a0,a1,a2,a3,a4);var _PyEval_GetBuiltins=Module["_PyEval_GetBuiltins"]=()=>(_PyEval_GetBuiltins=Module["_PyEval_GetBuiltins"]=wasmExports["PyEval_GetBuiltins"])();var _PyEval_EvalCode=Module["_PyEval_EvalCode"]=(a0,a1,a2)=>(_PyEval_EvalCode=Module["_PyEval_EvalCode"]=wasmExports["PyEval_EvalCode"])(a0,a1,a2);var _PyRun_StringFlags=Module["_PyRun_StringFlags"]=(a0,a1,a2,a3,a4)=>(_PyRun_StringFlags=Module["_PyRun_StringFlags"]=wasmExports["PyRun_StringFlags"])(a0,a1,a2,a3,a4);var _PyEval_EvalCodeEx=Module["_PyEval_EvalCodeEx"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)=>(_PyEval_EvalCodeEx=Module["_PyEval_EvalCodeEx"]=wasmExports["PyEval_EvalCodeEx"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10);var _Py_GetRecursionLimit=Module["_Py_GetRecursionLimit"]=()=>(_Py_GetRecursionLimit=Module["_Py_GetRecursionLimit"]=wasmExports["Py_GetRecursionLimit"])();var _Py_SetRecursionLimit=Module["_Py_SetRecursionLimit"]=a0=>(_Py_SetRecursionLimit=Module["_Py_SetRecursionLimit"]=wasmExports["Py_SetRecursionLimit"])(a0);var _PyEval_EvalFrame=Module["_PyEval_EvalFrame"]=a0=>(_PyEval_EvalFrame=Module["_PyEval_EvalFrame"]=wasmExports["PyEval_EvalFrame"])(a0);var _PyEval_EvalFrameEx=Module["_PyEval_EvalFrameEx"]=(a0,a1)=>(_PyEval_EvalFrameEx=Module["_PyEval_EvalFrameEx"]=wasmExports["PyEval_EvalFrameEx"])(a0,a1);var _PyTraceBack_Here=Module["_PyTraceBack_Here"]=a0=>(_PyTraceBack_Here=Module["_PyTraceBack_Here"]=wasmExports["PyTraceBack_Here"])(a0);var _PyErr_SetHandledException=Module["_PyErr_SetHandledException"]=a0=>(_PyErr_SetHandledException=Module["_PyErr_SetHandledException"]=wasmExports["PyErr_SetHandledException"])(a0);var __PyErr_GetTopmostException=Module["__PyErr_GetTopmostException"]=a0=>(__PyErr_GetTopmostException=Module["__PyErr_GetTopmostException"]=wasmExports["_PyErr_GetTopmostException"])(a0);var __PyErr_SetObject=Module["__PyErr_SetObject"]=(a0,a1,a2)=>(__PyErr_SetObject=Module["__PyErr_SetObject"]=wasmExports["_PyErr_SetObject"])(a0,a1,a2);var _PyThreadState_EnterTracing=Module["_PyThreadState_EnterTracing"]=a0=>(_PyThreadState_EnterTracing=Module["_PyThreadState_EnterTracing"]=wasmExports["PyThreadState_EnterTracing"])(a0);var _PyThreadState_LeaveTracing=Module["_PyThreadState_LeaveTracing"]=a0=>(_PyThreadState_LeaveTracing=Module["_PyThreadState_LeaveTracing"]=wasmExports["PyThreadState_LeaveTracing"])(a0);var _PyEval_SetProfile=Module["_PyEval_SetProfile"]=(a0,a1)=>(_PyEval_SetProfile=Module["_PyEval_SetProfile"]=wasmExports["PyEval_SetProfile"])(a0,a1);var __PyEval_SetProfile=Module["__PyEval_SetProfile"]=(a0,a1,a2)=>(__PyEval_SetProfile=Module["__PyEval_SetProfile"]=wasmExports["_PyEval_SetProfile"])(a0,a1,a2);var __PyErr_WriteUnraisableMsg=Module["__PyErr_WriteUnraisableMsg"]=(a0,a1)=>(__PyErr_WriteUnraisableMsg=Module["__PyErr_WriteUnraisableMsg"]=wasmExports["_PyErr_WriteUnraisableMsg"])(a0,a1);var _PyEval_SetProfileAllThreads=Module["_PyEval_SetProfileAllThreads"]=(a0,a1)=>(_PyEval_SetProfileAllThreads=Module["_PyEval_SetProfileAllThreads"]=wasmExports["PyEval_SetProfileAllThreads"])(a0,a1);var _PyInterpreterState_ThreadHead=Module["_PyInterpreterState_ThreadHead"]=a0=>(_PyInterpreterState_ThreadHead=Module["_PyInterpreterState_ThreadHead"]=wasmExports["PyInterpreterState_ThreadHead"])(a0);var _PyThreadState_Next=Module["_PyThreadState_Next"]=a0=>(_PyThreadState_Next=Module["_PyThreadState_Next"]=wasmExports["PyThreadState_Next"])(a0);var _PyEval_SetTrace=Module["_PyEval_SetTrace"]=(a0,a1)=>(_PyEval_SetTrace=Module["_PyEval_SetTrace"]=wasmExports["PyEval_SetTrace"])(a0,a1);var __PyEval_SetTrace=Module["__PyEval_SetTrace"]=(a0,a1,a2)=>(__PyEval_SetTrace=Module["__PyEval_SetTrace"]=wasmExports["_PyEval_SetTrace"])(a0,a1,a2);var _PyEval_SetTraceAllThreads=Module["_PyEval_SetTraceAllThreads"]=(a0,a1)=>(_PyEval_SetTraceAllThreads=Module["_PyEval_SetTraceAllThreads"]=wasmExports["PyEval_SetTraceAllThreads"])(a0,a1);var _PyEval_GetFrame=Module["_PyEval_GetFrame"]=()=>(_PyEval_GetFrame=Module["_PyEval_GetFrame"]=wasmExports["PyEval_GetFrame"])();var __PyEval_GetBuiltinId=Module["__PyEval_GetBuiltinId"]=a0=>(__PyEval_GetBuiltinId=Module["__PyEval_GetBuiltinId"]=wasmExports["_PyEval_GetBuiltinId"])(a0);var _PyEval_GetLocals=Module["_PyEval_GetLocals"]=()=>(_PyEval_GetLocals=Module["_PyEval_GetLocals"]=wasmExports["PyEval_GetLocals"])();var _PyEval_GetFuncName=Module["_PyEval_GetFuncName"]=a0=>(_PyEval_GetFuncName=Module["_PyEval_GetFuncName"]=wasmExports["PyEval_GetFuncName"])(a0);var _PyEval_GetFuncDesc=Module["_PyEval_GetFuncDesc"]=a0=>(_PyEval_GetFuncDesc=Module["_PyEval_GetFuncDesc"]=wasmExports["PyEval_GetFuncDesc"])(a0);var _PyUnstable_Eval_RequestCodeExtraIndex=Module["_PyUnstable_Eval_RequestCodeExtraIndex"]=a0=>(_PyUnstable_Eval_RequestCodeExtraIndex=Module["_PyUnstable_Eval_RequestCodeExtraIndex"]=wasmExports["PyUnstable_Eval_RequestCodeExtraIndex"])(a0);var _PyCodec_Register=Module["_PyCodec_Register"]=a0=>(_PyCodec_Register=Module["_PyCodec_Register"]=wasmExports["PyCodec_Register"])(a0);var _PyCodec_Unregister=Module["_PyCodec_Unregister"]=a0=>(_PyCodec_Unregister=Module["_PyCodec_Unregister"]=wasmExports["PyCodec_Unregister"])(a0);var _PyCodec_KnownEncoding=Module["_PyCodec_KnownEncoding"]=a0=>(_PyCodec_KnownEncoding=Module["_PyCodec_KnownEncoding"]=wasmExports["PyCodec_KnownEncoding"])(a0);var __PyCodecInfo_GetIncrementalDecoder=Module["__PyCodecInfo_GetIncrementalDecoder"]=(a0,a1)=>(__PyCodecInfo_GetIncrementalDecoder=Module["__PyCodecInfo_GetIncrementalDecoder"]=wasmExports["_PyCodecInfo_GetIncrementalDecoder"])(a0,a1);var __PyCodecInfo_GetIncrementalEncoder=Module["__PyCodecInfo_GetIncrementalEncoder"]=(a0,a1)=>(__PyCodecInfo_GetIncrementalEncoder=Module["__PyCodecInfo_GetIncrementalEncoder"]=wasmExports["_PyCodecInfo_GetIncrementalEncoder"])(a0,a1);var _PyCodec_Encoder=Module["_PyCodec_Encoder"]=a0=>(_PyCodec_Encoder=Module["_PyCodec_Encoder"]=wasmExports["PyCodec_Encoder"])(a0);var _PyCodec_Decoder=Module["_PyCodec_Decoder"]=a0=>(_PyCodec_Decoder=Module["_PyCodec_Decoder"]=wasmExports["PyCodec_Decoder"])(a0);var _PyCodec_IncrementalEncoder=Module["_PyCodec_IncrementalEncoder"]=(a0,a1)=>(_PyCodec_IncrementalEncoder=Module["_PyCodec_IncrementalEncoder"]=wasmExports["PyCodec_IncrementalEncoder"])(a0,a1);var _PyCodec_IncrementalDecoder=Module["_PyCodec_IncrementalDecoder"]=(a0,a1)=>(_PyCodec_IncrementalDecoder=Module["_PyCodec_IncrementalDecoder"]=wasmExports["PyCodec_IncrementalDecoder"])(a0,a1);var _PyCodec_StreamReader=Module["_PyCodec_StreamReader"]=(a0,a1,a2)=>(_PyCodec_StreamReader=Module["_PyCodec_StreamReader"]=wasmExports["PyCodec_StreamReader"])(a0,a1,a2);var _PyCodec_StreamWriter=Module["_PyCodec_StreamWriter"]=(a0,a1,a2)=>(_PyCodec_StreamWriter=Module["_PyCodec_StreamWriter"]=wasmExports["PyCodec_StreamWriter"])(a0,a1,a2);var __PyCodec_LookupTextEncoding=Module["__PyCodec_LookupTextEncoding"]=(a0,a1)=>(__PyCodec_LookupTextEncoding=Module["__PyCodec_LookupTextEncoding"]=wasmExports["_PyCodec_LookupTextEncoding"])(a0,a1);var _PyCodec_RegisterError=Module["_PyCodec_RegisterError"]=(a0,a1)=>(_PyCodec_RegisterError=Module["_PyCodec_RegisterError"]=wasmExports["PyCodec_RegisterError"])(a0,a1);var _PyCodec_IgnoreErrors=Module["_PyCodec_IgnoreErrors"]=a0=>(_PyCodec_IgnoreErrors=Module["_PyCodec_IgnoreErrors"]=wasmExports["PyCodec_IgnoreErrors"])(a0);var _PyCodec_ReplaceErrors=Module["_PyCodec_ReplaceErrors"]=a0=>(_PyCodec_ReplaceErrors=Module["_PyCodec_ReplaceErrors"]=wasmExports["PyCodec_ReplaceErrors"])(a0);var _PyCodec_XMLCharRefReplaceErrors=Module["_PyCodec_XMLCharRefReplaceErrors"]=a0=>(_PyCodec_XMLCharRefReplaceErrors=Module["_PyCodec_XMLCharRefReplaceErrors"]=wasmExports["PyCodec_XMLCharRefReplaceErrors"])(a0);var _PyCodec_BackslashReplaceErrors=Module["_PyCodec_BackslashReplaceErrors"]=a0=>(_PyCodec_BackslashReplaceErrors=Module["_PyCodec_BackslashReplaceErrors"]=wasmExports["PyCodec_BackslashReplaceErrors"])(a0);var _PyCodec_NameReplaceErrors=Module["_PyCodec_NameReplaceErrors"]=a0=>(_PyCodec_NameReplaceErrors=Module["_PyCodec_NameReplaceErrors"]=wasmExports["PyCodec_NameReplaceErrors"])(a0);var _PyCompile_OpcodeStackEffectWithJump=Module["_PyCompile_OpcodeStackEffectWithJump"]=(a0,a1,a2)=>(_PyCompile_OpcodeStackEffectWithJump=Module["_PyCompile_OpcodeStackEffectWithJump"]=wasmExports["PyCompile_OpcodeStackEffectWithJump"])(a0,a1,a2);var __PyCompile_CodeGen=Module["__PyCompile_CodeGen"]=(a0,a1,a2,a3,a4)=>(__PyCompile_CodeGen=Module["__PyCompile_CodeGen"]=wasmExports["_PyCompile_CodeGen"])(a0,a1,a2,a3,a4);var __PyCompile_OptimizeCfg=Module["__PyCompile_OptimizeCfg"]=(a0,a1,a2)=>(__PyCompile_OptimizeCfg=Module["__PyCompile_OptimizeCfg"]=wasmExports["_PyCompile_OptimizeCfg"])(a0,a1,a2);var __PyCompile_Assemble=Module["__PyCompile_Assemble"]=(a0,a1,a2)=>(__PyCompile_Assemble=Module["__PyCompile_Assemble"]=wasmExports["_PyCompile_Assemble"])(a0,a1,a2);var _PyCode_Optimize=Module["_PyCode_Optimize"]=(a0,a1,a2,a3)=>(_PyCode_Optimize=Module["_PyCode_Optimize"]=wasmExports["PyCode_Optimize"])(a0,a1,a2,a3);var _PySymtable_Lookup=Module["_PySymtable_Lookup"]=(a0,a1)=>(_PySymtable_Lookup=Module["_PySymtable_Lookup"]=wasmExports["PySymtable_Lookup"])(a0,a1);var _PyErr_ProgramTextObject=Module["_PyErr_ProgramTextObject"]=(a0,a1)=>(_PyErr_ProgramTextObject=Module["_PyErr_ProgramTextObject"]=wasmExports["PyErr_ProgramTextObject"])(a0,a1);var __PyContext_NewHamtForTests=Module["__PyContext_NewHamtForTests"]=()=>(__PyContext_NewHamtForTests=Module["__PyContext_NewHamtForTests"]=wasmExports["_PyContext_NewHamtForTests"])();var _PyContext_New=Module["_PyContext_New"]=()=>(_PyContext_New=Module["_PyContext_New"]=wasmExports["PyContext_New"])();var _PyContext_Copy=Module["_PyContext_Copy"]=a0=>(_PyContext_Copy=Module["_PyContext_Copy"]=wasmExports["PyContext_Copy"])(a0);var _PyContext_CopyCurrent=Module["_PyContext_CopyCurrent"]=()=>(_PyContext_CopyCurrent=Module["_PyContext_CopyCurrent"]=wasmExports["PyContext_CopyCurrent"])();var _PyContext_Enter=Module["_PyContext_Enter"]=a0=>(_PyContext_Enter=Module["_PyContext_Enter"]=wasmExports["PyContext_Enter"])(a0);var _PyContext_Exit=Module["_PyContext_Exit"]=a0=>(_PyContext_Exit=Module["_PyContext_Exit"]=wasmExports["PyContext_Exit"])(a0);var _PyContextVar_New=Module["_PyContextVar_New"]=(a0,a1)=>(_PyContextVar_New=Module["_PyContextVar_New"]=wasmExports["PyContextVar_New"])(a0,a1);var _PyContextVar_Get=Module["_PyContextVar_Get"]=(a0,a1,a2)=>(_PyContextVar_Get=Module["_PyContextVar_Get"]=wasmExports["PyContextVar_Get"])(a0,a1,a2);var _PyContextVar_Set=Module["_PyContextVar_Set"]=(a0,a1)=>(_PyContextVar_Set=Module["_PyContextVar_Set"]=wasmExports["PyContextVar_Set"])(a0,a1);var _PyContextVar_Reset=Module["_PyContextVar_Reset"]=(a0,a1)=>(_PyContextVar_Reset=Module["_PyContextVar_Reset"]=wasmExports["PyContextVar_Reset"])(a0,a1);var __PyErr_Restore=Module["__PyErr_Restore"]=(a0,a1,a2,a3)=>(__PyErr_Restore=Module["__PyErr_Restore"]=wasmExports["_PyErr_Restore"])(a0,a1,a2,a3);var __PyErr_SetNone=Module["__PyErr_SetNone"]=(a0,a1)=>(__PyErr_SetNone=Module["__PyErr_SetNone"]=wasmExports["_PyErr_SetNone"])(a0,a1);var __PyErr_NormalizeException=Module["__PyErr_NormalizeException"]=(a0,a1,a2,a3)=>(__PyErr_NormalizeException=Module["__PyErr_NormalizeException"]=wasmExports["_PyErr_NormalizeException"])(a0,a1,a2,a3);var __PyErr_Fetch=Module["__PyErr_Fetch"]=(a0,a1,a2,a3)=>(__PyErr_Fetch=Module["__PyErr_Fetch"]=wasmExports["_PyErr_Fetch"])(a0,a1,a2,a3);var __PyErr_GetExcInfo=Module["__PyErr_GetExcInfo"]=(a0,a1,a2,a3)=>(__PyErr_GetExcInfo=Module["__PyErr_GetExcInfo"]=wasmExports["_PyErr_GetExcInfo"])(a0,a1,a2,a3);var __PyErr_GetHandledException=Module["__PyErr_GetHandledException"]=a0=>(__PyErr_GetHandledException=Module["__PyErr_GetHandledException"]=wasmExports["_PyErr_GetHandledException"])(a0);var _PyErr_GetHandledException=Module["_PyErr_GetHandledException"]=()=>(_PyErr_GetHandledException=Module["_PyErr_GetHandledException"]=wasmExports["PyErr_GetHandledException"])();var __PyErr_SetHandledException=Module["__PyErr_SetHandledException"]=(a0,a1)=>(__PyErr_SetHandledException=Module["__PyErr_SetHandledException"]=wasmExports["_PyErr_SetHandledException"])(a0,a1);var _PyErr_GetExcInfo=Module["_PyErr_GetExcInfo"]=(a0,a1,a2)=>(_PyErr_GetExcInfo=Module["_PyErr_GetExcInfo"]=wasmExports["PyErr_GetExcInfo"])(a0,a1,a2);var _PyErr_SetExcInfo=Module["_PyErr_SetExcInfo"]=(a0,a1,a2)=>(_PyErr_SetExcInfo=Module["_PyErr_SetExcInfo"]=wasmExports["PyErr_SetExcInfo"])(a0,a1,a2);var __PyErr_StackItemToExcInfoTuple=Module["__PyErr_StackItemToExcInfoTuple"]=a0=>(__PyErr_StackItemToExcInfoTuple=Module["__PyErr_StackItemToExcInfoTuple"]=wasmExports["_PyErr_StackItemToExcInfoTuple"])(a0);var __PyErr_ChainExceptions=Module["__PyErr_ChainExceptions"]=(a0,a1,a2)=>(__PyErr_ChainExceptions=Module["__PyErr_ChainExceptions"]=wasmExports["_PyErr_ChainExceptions"])(a0,a1,a2);var _PyErr_SetFromErrnoWithFilenameObject=Module["_PyErr_SetFromErrnoWithFilenameObject"]=(a0,a1)=>(_PyErr_SetFromErrnoWithFilenameObject=Module["_PyErr_SetFromErrnoWithFilenameObject"]=wasmExports["PyErr_SetFromErrnoWithFilenameObject"])(a0,a1);var _PyErr_SetFromErrnoWithFilenameObjects=Module["_PyErr_SetFromErrnoWithFilenameObjects"]=(a0,a1,a2)=>(_PyErr_SetFromErrnoWithFilenameObjects=Module["_PyErr_SetFromErrnoWithFilenameObjects"]=wasmExports["PyErr_SetFromErrnoWithFilenameObjects"])(a0,a1,a2);var _strerror=Module["_strerror"]=a0=>(_strerror=Module["_strerror"]=wasmExports["strerror"])(a0);var _PyErr_SetImportErrorSubclass=Module["_PyErr_SetImportErrorSubclass"]=(a0,a1,a2,a3)=>(_PyErr_SetImportErrorSubclass=Module["_PyErr_SetImportErrorSubclass"]=wasmExports["PyErr_SetImportErrorSubclass"])(a0,a1,a2,a3);var _PyErr_SetImportError=Module["_PyErr_SetImportError"]=(a0,a1,a2)=>(_PyErr_SetImportError=Module["_PyErr_SetImportError"]=wasmExports["PyErr_SetImportError"])(a0,a1,a2);var _PyErr_BadInternalCall=Module["_PyErr_BadInternalCall"]=()=>(_PyErr_BadInternalCall=Module["_PyErr_BadInternalCall"]=wasmExports["PyErr_BadInternalCall"])();var _PyErr_FormatV=Module["_PyErr_FormatV"]=(a0,a1,a2)=>(_PyErr_FormatV=Module["_PyErr_FormatV"]=wasmExports["PyErr_FormatV"])(a0,a1,a2);var _PyErr_NewExceptionWithDoc=Module["_PyErr_NewExceptionWithDoc"]=(a0,a1,a2,a3)=>(_PyErr_NewExceptionWithDoc=Module["_PyErr_NewExceptionWithDoc"]=wasmExports["PyErr_NewExceptionWithDoc"])(a0,a1,a2,a3);var _PyTraceBack_Print=Module["_PyTraceBack_Print"]=(a0,a1)=>(_PyTraceBack_Print=Module["_PyTraceBack_Print"]=wasmExports["PyTraceBack_Print"])(a0,a1);var __PyTraceBack_FromFrame=Module["__PyTraceBack_FromFrame"]=(a0,a1)=>(__PyTraceBack_FromFrame=Module["__PyTraceBack_FromFrame"]=wasmExports["_PyTraceBack_FromFrame"])(a0,a1);var _PyErr_SyntaxLocation=Module["_PyErr_SyntaxLocation"]=(a0,a1)=>(_PyErr_SyntaxLocation=Module["_PyErr_SyntaxLocation"]=wasmExports["PyErr_SyntaxLocation"])(a0,a1);var _PyErr_SyntaxLocationEx=Module["_PyErr_SyntaxLocationEx"]=(a0,a1,a2)=>(_PyErr_SyntaxLocationEx=Module["_PyErr_SyntaxLocationEx"]=wasmExports["PyErr_SyntaxLocationEx"])(a0,a1,a2);var _PyErr_RangedSyntaxLocationObject=Module["_PyErr_RangedSyntaxLocationObject"]=(a0,a1,a2,a3,a4)=>(_PyErr_RangedSyntaxLocationObject=Module["_PyErr_RangedSyntaxLocationObject"]=wasmExports["PyErr_RangedSyntaxLocationObject"])(a0,a1,a2,a3,a4);var _PyErr_ProgramText=Module["_PyErr_ProgramText"]=(a0,a1)=>(_PyErr_ProgramText=Module["_PyErr_ProgramText"]=wasmExports["PyErr_ProgramText"])(a0,a1);var __Py_fopen_obj=Module["__Py_fopen_obj"]=(a0,a1)=>(__Py_fopen_obj=Module["__Py_fopen_obj"]=wasmExports["_Py_fopen_obj"])(a0,a1);var _PyUnstable_InterpreterFrame_GetCode=Module["_PyUnstable_InterpreterFrame_GetCode"]=a0=>(_PyUnstable_InterpreterFrame_GetCode=Module["_PyUnstable_InterpreterFrame_GetCode"]=wasmExports["PyUnstable_InterpreterFrame_GetCode"])(a0);var _PyUnstable_InterpreterFrame_GetLasti=Module["_PyUnstable_InterpreterFrame_GetLasti"]=a0=>(_PyUnstable_InterpreterFrame_GetLasti=Module["_PyUnstable_InterpreterFrame_GetLasti"]=wasmExports["PyUnstable_InterpreterFrame_GetLasti"])(a0);var _Py_FrozenMain=Module["_Py_FrozenMain"]=(a0,a1)=>(_Py_FrozenMain=Module["_Py_FrozenMain"]=wasmExports["Py_FrozenMain"])(a0,a1);var __PyRuntime_Initialize=Module["__PyRuntime_Initialize"]=a0=>(__PyRuntime_Initialize=Module["__PyRuntime_Initialize"]=wasmExports["_PyRuntime_Initialize"])(a0);var _Py_GETENV=Module["_Py_GETENV"]=a0=>(_Py_GETENV=Module["_Py_GETENV"]=wasmExports["Py_GETENV"])(a0);var _Py_GetVersion=Module["_Py_GetVersion"]=()=>(_Py_GetVersion=Module["_Py_GetVersion"]=wasmExports["Py_GetVersion"])();var _Py_GetCopyright=Module["_Py_GetCopyright"]=()=>(_Py_GetCopyright=Module["_Py_GetCopyright"]=wasmExports["Py_GetCopyright"])();var _PyImport_ImportFrozenModule=Module["_PyImport_ImportFrozenModule"]=a0=>(_PyImport_ImportFrozenModule=Module["_PyImport_ImportFrozenModule"]=wasmExports["PyImport_ImportFrozenModule"])(a0);var _PyRun_AnyFileExFlags=Module["_PyRun_AnyFileExFlags"]=(a0,a1,a2,a3)=>(_PyRun_AnyFileExFlags=Module["_PyRun_AnyFileExFlags"]=wasmExports["PyRun_AnyFileExFlags"])(a0,a1,a2,a3);var _Py_FinalizeEx=Module["_Py_FinalizeEx"]=()=>(_Py_FinalizeEx=Module["_Py_FinalizeEx"]=wasmExports["Py_FinalizeEx"])();var _PyArg_Parse=Module["_PyArg_Parse"]=(a0,a1,a2)=>(_PyArg_Parse=Module["_PyArg_Parse"]=wasmExports["PyArg_Parse"])(a0,a1,a2);var __PyArg_Parse_SizeT=Module["__PyArg_Parse_SizeT"]=(a0,a1,a2)=>(__PyArg_Parse_SizeT=Module["__PyArg_Parse_SizeT"]=wasmExports["_PyArg_Parse_SizeT"])(a0,a1,a2);var __PyArg_ParseStack=Module["__PyArg_ParseStack"]=(a0,a1,a2,a3)=>(__PyArg_ParseStack=Module["__PyArg_ParseStack"]=wasmExports["_PyArg_ParseStack"])(a0,a1,a2,a3);var _PyArg_VaParse=Module["_PyArg_VaParse"]=(a0,a1,a2)=>(_PyArg_VaParse=Module["_PyArg_VaParse"]=wasmExports["PyArg_VaParse"])(a0,a1,a2);var __PyArg_VaParse_SizeT=Module["__PyArg_VaParse_SizeT"]=(a0,a1,a2)=>(__PyArg_VaParse_SizeT=Module["__PyArg_VaParse_SizeT"]=wasmExports["_PyArg_VaParse_SizeT"])(a0,a1,a2);var _PyArg_VaParseTupleAndKeywords=Module["_PyArg_VaParseTupleAndKeywords"]=(a0,a1,a2,a3,a4)=>(_PyArg_VaParseTupleAndKeywords=Module["_PyArg_VaParseTupleAndKeywords"]=wasmExports["PyArg_VaParseTupleAndKeywords"])(a0,a1,a2,a3,a4);var __PyArg_VaParseTupleAndKeywords_SizeT=Module["__PyArg_VaParseTupleAndKeywords_SizeT"]=(a0,a1,a2,a3,a4)=>(__PyArg_VaParseTupleAndKeywords_SizeT=Module["__PyArg_VaParseTupleAndKeywords_SizeT"]=wasmExports["_PyArg_VaParseTupleAndKeywords_SizeT"])(a0,a1,a2,a3,a4);var __PyArg_ParseTupleAndKeywordsFast=Module["__PyArg_ParseTupleAndKeywordsFast"]=(a0,a1,a2,a3)=>(__PyArg_ParseTupleAndKeywordsFast=Module["__PyArg_ParseTupleAndKeywordsFast"]=wasmExports["_PyArg_ParseTupleAndKeywordsFast"])(a0,a1,a2,a3);var __PyArg_ParseTupleAndKeywordsFast_SizeT=Module["__PyArg_ParseTupleAndKeywordsFast_SizeT"]=(a0,a1,a2,a3)=>(__PyArg_ParseTupleAndKeywordsFast_SizeT=Module["__PyArg_ParseTupleAndKeywordsFast_SizeT"]=wasmExports["_PyArg_ParseTupleAndKeywordsFast_SizeT"])(a0,a1,a2,a3);var __PyArg_ParseStackAndKeywords=Module["__PyArg_ParseStackAndKeywords"]=(a0,a1,a2,a3,a4)=>(__PyArg_ParseStackAndKeywords=Module["__PyArg_ParseStackAndKeywords"]=wasmExports["_PyArg_ParseStackAndKeywords"])(a0,a1,a2,a3,a4);var __PyArg_VaParseTupleAndKeywordsFast=Module["__PyArg_VaParseTupleAndKeywordsFast"]=(a0,a1,a2,a3)=>(__PyArg_VaParseTupleAndKeywordsFast=Module["__PyArg_VaParseTupleAndKeywordsFast"]=wasmExports["_PyArg_VaParseTupleAndKeywordsFast"])(a0,a1,a2,a3);var __PyArg_VaParseTupleAndKeywordsFast_SizeT=Module["__PyArg_VaParseTupleAndKeywordsFast_SizeT"]=(a0,a1,a2,a3)=>(__PyArg_VaParseTupleAndKeywordsFast_SizeT=Module["__PyArg_VaParseTupleAndKeywordsFast_SizeT"]=wasmExports["_PyArg_VaParseTupleAndKeywordsFast_SizeT"])(a0,a1,a2,a3);var _PyThreadState_Swap=Module["_PyThreadState_Swap"]=a0=>(_PyThreadState_Swap=Module["_PyThreadState_Swap"]=wasmExports["PyThreadState_Swap"])(a0);var _PyThreadState_Clear=Module["_PyThreadState_Clear"]=a0=>(_PyThreadState_Clear=Module["_PyThreadState_Clear"]=wasmExports["PyThreadState_Clear"])(a0);var __PyArg_NoPositional=Module["__PyArg_NoPositional"]=(a0,a1)=>(__PyArg_NoPositional=Module["__PyArg_NoPositional"]=wasmExports["_PyArg_NoPositional"])(a0,a1);var _Py_GetCompiler=Module["_Py_GetCompiler"]=()=>(_Py_GetCompiler=Module["_Py_GetCompiler"]=wasmExports["Py_GetCompiler"])();var _Py_GetPlatform=Module["_Py_GetPlatform"]=()=>(_Py_GetPlatform=Module["_Py_GetPlatform"]=wasmExports["Py_GetPlatform"])();var __PyEval_SetSwitchInterval=Module["__PyEval_SetSwitchInterval"]=a0=>(__PyEval_SetSwitchInterval=Module["__PyEval_SetSwitchInterval"]=wasmExports["_PyEval_SetSwitchInterval"])(a0);var __PyEval_GetSwitchInterval=Module["__PyEval_GetSwitchInterval"]=()=>(__PyEval_GetSwitchInterval=Module["__PyEval_GetSwitchInterval"]=wasmExports["_PyEval_GetSwitchInterval"])();var _PyEval_ThreadsInitialized=Module["_PyEval_ThreadsInitialized"]=()=>(_PyEval_ThreadsInitialized=Module["_PyEval_ThreadsInitialized"]=wasmExports["PyEval_ThreadsInitialized"])();var _PyThread_init_thread=Module["_PyThread_init_thread"]=()=>(_PyThread_init_thread=Module["_PyThread_init_thread"]=wasmExports["PyThread_init_thread"])();var _pthread_mutex_lock=Module["_pthread_mutex_lock"]=a0=>(_pthread_mutex_lock=Module["_pthread_mutex_lock"]=wasmExports["pthread_mutex_lock"])(a0);var _pthread_cond_timedwait=Module["_pthread_cond_timedwait"]=(a0,a1,a2)=>(_pthread_cond_timedwait=Module["_pthread_cond_timedwait"]=wasmExports["pthread_cond_timedwait"])(a0,a1,a2);var _pthread_mutex_unlock=Module["_pthread_mutex_unlock"]=a0=>(_pthread_mutex_unlock=Module["_pthread_mutex_unlock"]=wasmExports["pthread_mutex_unlock"])(a0);var _pthread_cond_signal=Module["_pthread_cond_signal"]=a0=>(_pthread_cond_signal=Module["_pthread_cond_signal"]=wasmExports["pthread_cond_signal"])(a0);var _PyThread_exit_thread=Module["_PyThread_exit_thread"]=()=>(_PyThread_exit_thread=Module["_PyThread_exit_thread"]=wasmExports["PyThread_exit_thread"])();var _PyThread_get_thread_ident=Module["_PyThread_get_thread_ident"]=()=>(_PyThread_get_thread_ident=Module["_PyThread_get_thread_ident"]=wasmExports["PyThread_get_thread_ident"])();var _pthread_cond_destroy=Module["_pthread_cond_destroy"]=a0=>(_pthread_cond_destroy=Module["_pthread_cond_destroy"]=wasmExports["pthread_cond_destroy"])(a0);var _pthread_mutex_destroy=Module["_pthread_mutex_destroy"]=a0=>(_pthread_mutex_destroy=Module["_pthread_mutex_destroy"]=wasmExports["pthread_mutex_destroy"])(a0);var _PyEval_InitThreads=Module["_PyEval_InitThreads"]=()=>(_PyEval_InitThreads=Module["_PyEval_InitThreads"]=wasmExports["PyEval_InitThreads"])();var _PyEval_AcquireLock=Module["_PyEval_AcquireLock"]=()=>(_PyEval_AcquireLock=Module["_PyEval_AcquireLock"]=wasmExports["PyEval_AcquireLock"])();var _PyEval_ReleaseLock=Module["_PyEval_ReleaseLock"]=()=>(_PyEval_ReleaseLock=Module["_PyEval_ReleaseLock"]=wasmExports["PyEval_ReleaseLock"])();var _pthread_cond_wait=Module["_pthread_cond_wait"]=(a0,a1)=>(_pthread_cond_wait=Module["_pthread_cond_wait"]=wasmExports["pthread_cond_wait"])(a0,a1);var _PyEval_AcquireThread=Module["_PyEval_AcquireThread"]=a0=>(_PyEval_AcquireThread=Module["_PyEval_AcquireThread"]=wasmExports["PyEval_AcquireThread"])(a0);var _PyEval_ReleaseThread=Module["_PyEval_ReleaseThread"]=a0=>(_PyEval_ReleaseThread=Module["_PyEval_ReleaseThread"]=wasmExports["PyEval_ReleaseThread"])(a0);var __PyThread_at_fork_reinit=Module["__PyThread_at_fork_reinit"]=a0=>(__PyThread_at_fork_reinit=Module["__PyThread_at_fork_reinit"]=wasmExports["_PyThread_at_fork_reinit"])(a0);var __PyThreadState_DeleteExcept=Module["__PyThreadState_DeleteExcept"]=a0=>(__PyThreadState_DeleteExcept=Module["__PyThreadState_DeleteExcept"]=wasmExports["_PyThreadState_DeleteExcept"])(a0);var __PyEval_SignalAsyncExc=Module["__PyEval_SignalAsyncExc"]=a0=>(__PyEval_SignalAsyncExc=Module["__PyEval_SignalAsyncExc"]=wasmExports["_PyEval_SignalAsyncExc"])(a0);var __PyEval_SignalReceived=Module["__PyEval_SignalReceived"]=a0=>(__PyEval_SignalReceived=Module["__PyEval_SignalReceived"]=wasmExports["_PyEval_SignalReceived"])(a0);var __PyEval_AddPendingCall=Module["__PyEval_AddPendingCall"]=(a0,a1,a2,a3)=>(__PyEval_AddPendingCall=Module["__PyEval_AddPendingCall"]=wasmExports["_PyEval_AddPendingCall"])(a0,a1,a2,a3);var _Py_AddPendingCall=Module["_Py_AddPendingCall"]=(a0,a1)=>(_Py_AddPendingCall=Module["_Py_AddPendingCall"]=wasmExports["Py_AddPendingCall"])(a0,a1);var __PyErr_Print=Module["__PyErr_Print"]=a0=>(__PyErr_Print=Module["__PyErr_Print"]=wasmExports["_PyErr_Print"])(a0);var __PyEval_MakePendingCalls=Module["__PyEval_MakePendingCalls"]=a0=>(__PyEval_MakePendingCalls=Module["__PyEval_MakePendingCalls"]=wasmExports["_PyEval_MakePendingCalls"])(a0);var __PyErr_CheckSignalsTstate=Module["__PyErr_CheckSignalsTstate"]=a0=>(__PyErr_CheckSignalsTstate=Module["__PyErr_CheckSignalsTstate"]=wasmExports["_PyErr_CheckSignalsTstate"])(a0);var _Py_MakePendingCalls=Module["_Py_MakePendingCalls"]=()=>(_Py_MakePendingCalls=Module["_Py_MakePendingCalls"]=wasmExports["Py_MakePendingCalls"])();var _PyThread_free_lock=Module["_PyThread_free_lock"]=a0=>(_PyThread_free_lock=Module["_PyThread_free_lock"]=wasmExports["PyThread_free_lock"])(a0);var _pthread_mutex_init=Module["_pthread_mutex_init"]=(a0,a1)=>(_pthread_mutex_init=Module["_pthread_mutex_init"]=wasmExports["pthread_mutex_init"])(a0,a1);var __Py_hashtable_hash_ptr=Module["__Py_hashtable_hash_ptr"]=a0=>(__Py_hashtable_hash_ptr=Module["__Py_hashtable_hash_ptr"]=wasmExports["_Py_hashtable_hash_ptr"])(a0);var __Py_HashPointerRaw=Module["__Py_HashPointerRaw"]=a0=>(__Py_HashPointerRaw=Module["__Py_HashPointerRaw"]=wasmExports["_Py_HashPointerRaw"])(a0);var __Py_hashtable_compare_direct=Module["__Py_hashtable_compare_direct"]=(a0,a1)=>(__Py_hashtable_compare_direct=Module["__Py_hashtable_compare_direct"]=wasmExports["_Py_hashtable_compare_direct"])(a0,a1);var __Py_hashtable_size=Module["__Py_hashtable_size"]=a0=>(__Py_hashtable_size=Module["__Py_hashtable_size"]=wasmExports["_Py_hashtable_size"])(a0);var __Py_hashtable_steal=Module["__Py_hashtable_steal"]=(a0,a1)=>(__Py_hashtable_steal=Module["__Py_hashtable_steal"]=wasmExports["_Py_hashtable_steal"])(a0,a1);var __Py_hashtable_foreach=Module["__Py_hashtable_foreach"]=(a0,a1,a2)=>(__Py_hashtable_foreach=Module["__Py_hashtable_foreach"]=wasmExports["_Py_hashtable_foreach"])(a0,a1,a2);var __Py_hashtable_new=Module["__Py_hashtable_new"]=(a0,a1)=>(__Py_hashtable_new=Module["__Py_hashtable_new"]=wasmExports["_Py_hashtable_new"])(a0,a1);var __Py_hashtable_clear=Module["__Py_hashtable_clear"]=a0=>(__Py_hashtable_clear=Module["__Py_hashtable_clear"]=wasmExports["_Py_hashtable_clear"])(a0);var __PyImport_AcquireLock=Module["__PyImport_AcquireLock"]=a0=>(__PyImport_AcquireLock=Module["__PyImport_AcquireLock"]=wasmExports["_PyImport_AcquireLock"])(a0);var __PyImport_ReleaseLock=Module["__PyImport_ReleaseLock"]=a0=>(__PyImport_ReleaseLock=Module["__PyImport_ReleaseLock"]=wasmExports["_PyImport_ReleaseLock"])(a0);var __PyImport_GetModuleId=Module["__PyImport_GetModuleId"]=a0=>(__PyImport_GetModuleId=Module["__PyImport_GetModuleId"]=wasmExports["_PyImport_GetModuleId"])(a0);var __PyImport_SetModule=Module["__PyImport_SetModule"]=(a0,a1)=>(__PyImport_SetModule=Module["__PyImport_SetModule"]=wasmExports["_PyImport_SetModule"])(a0,a1);var __PyImport_SetModuleString=Module["__PyImport_SetModuleString"]=(a0,a1)=>(__PyImport_SetModuleString=Module["__PyImport_SetModuleString"]=wasmExports["_PyImport_SetModuleString"])(a0,a1);var _PyImport_AddModuleObject=Module["_PyImport_AddModuleObject"]=a0=>(_PyImport_AddModuleObject=Module["_PyImport_AddModuleObject"]=wasmExports["PyImport_AddModuleObject"])(a0);var _PyImport_AddModule=Module["_PyImport_AddModule"]=a0=>(_PyImport_AddModule=Module["_PyImport_AddModule"]=wasmExports["PyImport_AddModule"])(a0);var _PyState_FindModule=Module["_PyState_FindModule"]=a0=>(_PyState_FindModule=Module["_PyState_FindModule"]=wasmExports["PyState_FindModule"])(a0);var __PyState_AddModule=Module["__PyState_AddModule"]=(a0,a1,a2)=>(__PyState_AddModule=Module["__PyState_AddModule"]=wasmExports["_PyState_AddModule"])(a0,a1,a2);var _PyState_AddModule=Module["_PyState_AddModule"]=(a0,a1)=>(_PyState_AddModule=Module["_PyState_AddModule"]=wasmExports["PyState_AddModule"])(a0,a1);var _PyState_RemoveModule=Module["_PyState_RemoveModule"]=a0=>(_PyState_RemoveModule=Module["_PyState_RemoveModule"]=wasmExports["PyState_RemoveModule"])(a0);var __PyImport_ClearExtension=Module["__PyImport_ClearExtension"]=(a0,a1)=>(__PyImport_ClearExtension=Module["__PyImport_ClearExtension"]=wasmExports["_PyImport_ClearExtension"])(a0,a1);var __PyInterpreterState_HasFeature=Module["__PyInterpreterState_HasFeature"]=(a0,a1)=>(__PyInterpreterState_HasFeature=Module["__PyInterpreterState_HasFeature"]=wasmExports["_PyInterpreterState_HasFeature"])(a0,a1);var __PyImport_FixupExtensionObject=Module["__PyImport_FixupExtensionObject"]=(a0,a1,a2,a3)=>(__PyImport_FixupExtensionObject=Module["__PyImport_FixupExtensionObject"]=wasmExports["_PyImport_FixupExtensionObject"])(a0,a1,a2,a3);var __PyImport_FixupBuiltin=Module["__PyImport_FixupBuiltin"]=(a0,a1,a2)=>(__PyImport_FixupBuiltin=Module["__PyImport_FixupBuiltin"]=wasmExports["_PyImport_FixupBuiltin"])(a0,a1,a2);var _PyImport_ExtendInittab=Module["_PyImport_ExtendInittab"]=a0=>(_PyImport_ExtendInittab=Module["_PyImport_ExtendInittab"]=wasmExports["PyImport_ExtendInittab"])(a0);var _PyImport_GetMagicNumber=Module["_PyImport_GetMagicNumber"]=()=>(_PyImport_GetMagicNumber=Module["_PyImport_GetMagicNumber"]=wasmExports["PyImport_GetMagicNumber"])();var _PyImport_GetMagicTag=Module["_PyImport_GetMagicTag"]=()=>(_PyImport_GetMagicTag=Module["_PyImport_GetMagicTag"]=wasmExports["PyImport_GetMagicTag"])();var _PyImport_ExecCodeModule=Module["_PyImport_ExecCodeModule"]=(a0,a1)=>(_PyImport_ExecCodeModule=Module["_PyImport_ExecCodeModule"]=wasmExports["PyImport_ExecCodeModule"])(a0,a1);var _PyImport_ExecCodeModuleObject=Module["_PyImport_ExecCodeModuleObject"]=(a0,a1,a2,a3)=>(_PyImport_ExecCodeModuleObject=Module["_PyImport_ExecCodeModuleObject"]=wasmExports["PyImport_ExecCodeModuleObject"])(a0,a1,a2,a3);var _PyImport_ExecCodeModuleWithPathnames=Module["_PyImport_ExecCodeModuleWithPathnames"]=(a0,a1,a2,a3)=>(_PyImport_ExecCodeModuleWithPathnames=Module["_PyImport_ExecCodeModuleWithPathnames"]=wasmExports["PyImport_ExecCodeModuleWithPathnames"])(a0,a1,a2,a3);var _PyImport_ExecCodeModuleEx=Module["_PyImport_ExecCodeModuleEx"]=(a0,a1,a2)=>(_PyImport_ExecCodeModuleEx=Module["_PyImport_ExecCodeModuleEx"]=wasmExports["PyImport_ExecCodeModuleEx"])(a0,a1,a2);var _PyImport_ImportFrozenModuleObject=Module["_PyImport_ImportFrozenModuleObject"]=a0=>(_PyImport_ImportFrozenModuleObject=Module["_PyImport_ImportFrozenModuleObject"]=wasmExports["PyImport_ImportFrozenModuleObject"])(a0);var _PyMarshal_ReadObjectFromString=Module["_PyMarshal_ReadObjectFromString"]=(a0,a1)=>(_PyMarshal_ReadObjectFromString=Module["_PyMarshal_ReadObjectFromString"]=wasmExports["PyMarshal_ReadObjectFromString"])(a0,a1);var _PyImport_GetImporter=Module["_PyImport_GetImporter"]=a0=>(_PyImport_GetImporter=Module["_PyImport_GetImporter"]=wasmExports["PyImport_GetImporter"])(a0);var _PyImport_ImportModuleNoBlock=Module["_PyImport_ImportModuleNoBlock"]=a0=>(_PyImport_ImportModuleNoBlock=Module["_PyImport_ImportModuleNoBlock"]=wasmExports["PyImport_ImportModuleNoBlock"])(a0);var __PyTime_GetPerfCounter=Module["__PyTime_GetPerfCounter"]=()=>(__PyTime_GetPerfCounter=Module["__PyTime_GetPerfCounter"]=wasmExports["_PyTime_GetPerfCounter"])();var __PyTime_AsMicroseconds=Module["__PyTime_AsMicroseconds"]=(a0,a1)=>(__PyTime_AsMicroseconds=Module["__PyTime_AsMicroseconds"]=wasmExports["_PyTime_AsMicroseconds"])(a0,a1);var _PyImport_ImportModuleLevel=Module["_PyImport_ImportModuleLevel"]=(a0,a1,a2,a3,a4)=>(_PyImport_ImportModuleLevel=Module["_PyImport_ImportModuleLevel"]=wasmExports["PyImport_ImportModuleLevel"])(a0,a1,a2,a3,a4);var _PyImport_ReloadModule=Module["_PyImport_ReloadModule"]=a0=>(_PyImport_ReloadModule=Module["_PyImport_ReloadModule"]=wasmExports["PyImport_ReloadModule"])(a0);var _PyStatus_NoMemory=Module["_PyStatus_NoMemory"]=a0=>(_PyStatus_NoMemory=Module["_PyStatus_NoMemory"]=wasmExports["PyStatus_NoMemory"])(a0);var __PyImport_GetModuleAttr=Module["__PyImport_GetModuleAttr"]=(a0,a1)=>(__PyImport_GetModuleAttr=Module["__PyImport_GetModuleAttr"]=wasmExports["_PyImport_GetModuleAttr"])(a0,a1);var _PyInit__imp=Module["_PyInit__imp"]=()=>(_PyInit__imp=Module["_PyInit__imp"]=wasmExports["PyInit__imp"])();var _getenv=Module["_getenv"]=a0=>(_getenv=Module["_getenv"]=wasmExports["getenv"])(a0);var _PyStatus_Ok=Module["_PyStatus_Ok"]=a0=>(_PyStatus_Ok=Module["_PyStatus_Ok"]=wasmExports["PyStatus_Ok"])(a0);var _PyStatus_Error=Module["_PyStatus_Error"]=(a0,a1)=>(_PyStatus_Error=Module["_PyStatus_Error"]=wasmExports["PyStatus_Error"])(a0,a1);var _PyStatus_Exit=Module["_PyStatus_Exit"]=(a0,a1)=>(_PyStatus_Exit=Module["_PyStatus_Exit"]=wasmExports["PyStatus_Exit"])(a0,a1);var _PyStatus_IsError=Module["_PyStatus_IsError"]=a0=>(_PyStatus_IsError=Module["_PyStatus_IsError"]=wasmExports["PyStatus_IsError"])(a0);var _PyStatus_IsExit=Module["_PyStatus_IsExit"]=a0=>(_PyStatus_IsExit=Module["_PyStatus_IsExit"]=wasmExports["PyStatus_IsExit"])(a0);var __PyErr_SetFromPyStatus=Module["__PyErr_SetFromPyStatus"]=a0=>(__PyErr_SetFromPyStatus=Module["__PyErr_SetFromPyStatus"]=wasmExports["_PyErr_SetFromPyStatus"])(a0);var __PyWideStringList_Clear=Module["__PyWideStringList_Clear"]=a0=>(__PyWideStringList_Clear=Module["__PyWideStringList_Clear"]=wasmExports["_PyWideStringList_Clear"])(a0);var __PyWideStringList_Copy=Module["__PyWideStringList_Copy"]=(a0,a1)=>(__PyWideStringList_Copy=Module["__PyWideStringList_Copy"]=wasmExports["_PyWideStringList_Copy"])(a0,a1);var _PyWideStringList_Insert=Module["_PyWideStringList_Insert"]=(a0,a1,a2,a3)=>(_PyWideStringList_Insert=Module["_PyWideStringList_Insert"]=wasmExports["PyWideStringList_Insert"])(a0,a1,a2,a3);var _PyWideStringList_Append=Module["_PyWideStringList_Append"]=(a0,a1,a2)=>(_PyWideStringList_Append=Module["_PyWideStringList_Append"]=wasmExports["PyWideStringList_Append"])(a0,a1,a2);var __PyWideStringList_Extend=Module["__PyWideStringList_Extend"]=(a0,a1,a2)=>(__PyWideStringList_Extend=Module["__PyWideStringList_Extend"]=wasmExports["_PyWideStringList_Extend"])(a0,a1,a2);var __PyWideStringList_AsList=Module["__PyWideStringList_AsList"]=a0=>(__PyWideStringList_AsList=Module["__PyWideStringList_AsList"]=wasmExports["_PyWideStringList_AsList"])(a0);var _Py_SetStandardStreamEncoding=Module["_Py_SetStandardStreamEncoding"]=(a0,a1)=>(_Py_SetStandardStreamEncoding=Module["_Py_SetStandardStreamEncoding"]=wasmExports["Py_SetStandardStreamEncoding"])(a0,a1);var __Py_ClearStandardStreamEncoding=Module["__Py_ClearStandardStreamEncoding"]=()=>(__Py_ClearStandardStreamEncoding=Module["__Py_ClearStandardStreamEncoding"]=wasmExports["_Py_ClearStandardStreamEncoding"])();var __Py_ClearArgcArgv=Module["__Py_ClearArgcArgv"]=()=>(__Py_ClearArgcArgv=Module["__Py_ClearArgcArgv"]=wasmExports["_Py_ClearArgcArgv"])();var _Py_GetArgcArgv=Module["_Py_GetArgcArgv"]=(a0,a1)=>(_Py_GetArgcArgv=Module["_Py_GetArgcArgv"]=wasmExports["Py_GetArgcArgv"])(a0,a1);var __PyConfig_InitCompatConfig=Module["__PyConfig_InitCompatConfig"]=a0=>(__PyConfig_InitCompatConfig=Module["__PyConfig_InitCompatConfig"]=wasmExports["_PyConfig_InitCompatConfig"])(a0);var _PyConfig_InitIsolatedConfig=Module["_PyConfig_InitIsolatedConfig"]=a0=>(_PyConfig_InitIsolatedConfig=Module["_PyConfig_InitIsolatedConfig"]=wasmExports["PyConfig_InitIsolatedConfig"])(a0);var _PyConfig_SetString=Module["_PyConfig_SetString"]=(a0,a1,a2,a3)=>(_PyConfig_SetString=Module["_PyConfig_SetString"]=wasmExports["PyConfig_SetString"])(a0,a1,a2,a3);var __Py_PreInitializeFromConfig=Module["__Py_PreInitializeFromConfig"]=(a0,a1,a2)=>(__Py_PreInitializeFromConfig=Module["__Py_PreInitializeFromConfig"]=wasmExports["_Py_PreInitializeFromConfig"])(a0,a1,a2);var _Py_DecodeLocale=Module["_Py_DecodeLocale"]=(a0,a1)=>(_Py_DecodeLocale=Module["_Py_DecodeLocale"]=wasmExports["Py_DecodeLocale"])(a0,a1);var __PyConfig_AsDict=Module["__PyConfig_AsDict"]=a0=>(__PyConfig_AsDict=Module["__PyConfig_AsDict"]=wasmExports["_PyConfig_AsDict"])(a0);var __PyConfig_FromDict=Module["__PyConfig_FromDict"]=(a0,a1)=>(__PyConfig_FromDict=Module["__PyConfig_FromDict"]=wasmExports["_PyConfig_FromDict"])(a0,a1);var __Py_get_xoption=Module["__Py_get_xoption"]=(a0,a1)=>(__Py_get_xoption=Module["__Py_get_xoption"]=wasmExports["_Py_get_xoption"])(a0,a1);var _wcschr=Module["_wcschr"]=(a0,a1)=>(_wcschr=Module["_wcschr"]=wasmExports["wcschr"])(a0,a1);var _setvbuf=Module["_setvbuf"]=(a0,a1,a2,a3)=>(_setvbuf=Module["_setvbuf"]=wasmExports["setvbuf"])(a0,a1,a2,a3);var __PyArgv_AsWstrList=Module["__PyArgv_AsWstrList"]=(a0,a1,a2)=>(__PyArgv_AsWstrList=Module["__PyArgv_AsWstrList"]=wasmExports["_PyArgv_AsWstrList"])(a0,a1,a2);var _PyConfig_SetArgv=Module["_PyConfig_SetArgv"]=(a0,a1,a2,a3)=>(_PyConfig_SetArgv=Module["_PyConfig_SetArgv"]=wasmExports["PyConfig_SetArgv"])(a0,a1,a2,a3);var _PyConfig_SetWideStringList=Module["_PyConfig_SetWideStringList"]=(a0,a1,a2,a3,a4)=>(_PyConfig_SetWideStringList=Module["_PyConfig_SetWideStringList"]=wasmExports["PyConfig_SetWideStringList"])(a0,a1,a2,a3,a4);var _putchar=Module["_putchar"]=a0=>(_putchar=Module["_putchar"]=wasmExports["putchar"])(a0);var _iprintf=Module["_iprintf"]=(a0,a1)=>(_iprintf=Module["_iprintf"]=wasmExports["iprintf"])(a0,a1);var _wcstok=Module["_wcstok"]=(a0,a1,a2)=>(_wcstok=Module["_wcstok"]=wasmExports["wcstok"])(a0,a1,a2);var __Py_get_env_flag=Module["__Py_get_env_flag"]=(a0,a1,a2)=>(__Py_get_env_flag=Module["__Py_get_env_flag"]=wasmExports["_Py_get_env_flag"])(a0,a1,a2);var __Py_GetEnv=Module["__Py_GetEnv"]=(a0,a1)=>(__Py_GetEnv=Module["__Py_GetEnv"]=wasmExports["_Py_GetEnv"])(a0,a1);var _strtoul=Module["_strtoul"]=(a0,a1,a2)=>(_strtoul=Module["_strtoul"]=wasmExports["strtoul"])(a0,a1,a2);var __Py_str_to_int=Module["__Py_str_to_int"]=(a0,a1)=>(__Py_str_to_int=Module["__Py_str_to_int"]=wasmExports["_Py_str_to_int"])(a0,a1);var _wcstol=Module["_wcstol"]=(a0,a1,a2)=>(_wcstol=Module["_wcstol"]=wasmExports["wcstol"])(a0,a1,a2);var __Py_GetForceASCII=Module["__Py_GetForceASCII"]=()=>(__Py_GetForceASCII=Module["__Py_GetForceASCII"]=wasmExports["_Py_GetForceASCII"])();var _setlocale=Module["_setlocale"]=(a0,a1)=>(_setlocale=Module["_setlocale"]=wasmExports["setlocale"])(a0,a1);var __Py_IsLocaleCoercionTarget=Module["__Py_IsLocaleCoercionTarget"]=a0=>(__Py_IsLocaleCoercionTarget=Module["__Py_IsLocaleCoercionTarget"]=wasmExports["_Py_IsLocaleCoercionTarget"])(a0);var _PyConfig_Read=Module["_PyConfig_Read"]=(a0,a1)=>(_PyConfig_Read=Module["_PyConfig_Read"]=wasmExports["PyConfig_Read"])(a0,a1);var __Py_GetConfigsAsDict=Module["__Py_GetConfigsAsDict"]=()=>(__Py_GetConfigsAsDict=Module["__Py_GetConfigsAsDict"]=wasmExports["_Py_GetConfigsAsDict"])();var __Py_GetLocaleEncoding=Module["__Py_GetLocaleEncoding"]=()=>(__Py_GetLocaleEncoding=Module["__Py_GetLocaleEncoding"]=wasmExports["_Py_GetLocaleEncoding"])();var _PyMarshal_WriteLongToFile=Module["_PyMarshal_WriteLongToFile"]=(a0,a1,a2)=>(_PyMarshal_WriteLongToFile=Module["_PyMarshal_WriteLongToFile"]=wasmExports["PyMarshal_WriteLongToFile"])(a0,a1,a2);var _PyMarshal_WriteObjectToFile=Module["_PyMarshal_WriteObjectToFile"]=(a0,a1,a2)=>(_PyMarshal_WriteObjectToFile=Module["_PyMarshal_WriteObjectToFile"]=wasmExports["PyMarshal_WriteObjectToFile"])(a0,a1,a2);var _PyMarshal_ReadShortFromFile=Module["_PyMarshal_ReadShortFromFile"]=a0=>(_PyMarshal_ReadShortFromFile=Module["_PyMarshal_ReadShortFromFile"]=wasmExports["PyMarshal_ReadShortFromFile"])(a0);var _PyMarshal_ReadLongFromFile=Module["_PyMarshal_ReadLongFromFile"]=a0=>(_PyMarshal_ReadLongFromFile=Module["_PyMarshal_ReadLongFromFile"]=wasmExports["PyMarshal_ReadLongFromFile"])(a0);var _PyMarshal_ReadLastObjectFromFile=Module["_PyMarshal_ReadLastObjectFromFile"]=a0=>(_PyMarshal_ReadLastObjectFromFile=Module["_PyMarshal_ReadLastObjectFromFile"]=wasmExports["PyMarshal_ReadLastObjectFromFile"])(a0);var __Py_fstat_noraise=Module["__Py_fstat_noraise"]=(a0,a1)=>(__Py_fstat_noraise=Module["__Py_fstat_noraise"]=wasmExports["_Py_fstat_noraise"])(a0,a1);var _fread=Module["_fread"]=(a0,a1,a2,a3)=>(_fread=Module["_fread"]=wasmExports["fread"])(a0,a1,a2,a3);var _PyMarshal_ReadObjectFromFile=Module["_PyMarshal_ReadObjectFromFile"]=a0=>(_PyMarshal_ReadObjectFromFile=Module["_PyMarshal_ReadObjectFromFile"]=wasmExports["PyMarshal_ReadObjectFromFile"])(a0);var _PyMarshal_WriteObjectToString=Module["_PyMarshal_WriteObjectToString"]=(a0,a1)=>(_PyMarshal_WriteObjectToString=Module["_PyMarshal_WriteObjectToString"]=wasmExports["PyMarshal_WriteObjectToString"])(a0,a1);var _PyMarshal_Init=Module["_PyMarshal_Init"]=()=>(_PyMarshal_Init=Module["_PyMarshal_Init"]=wasmExports["PyMarshal_Init"])();var __Py_convert_optional_to_ssize_t=Module["__Py_convert_optional_to_ssize_t"]=(a0,a1)=>(__Py_convert_optional_to_ssize_t=Module["__Py_convert_optional_to_ssize_t"]=wasmExports["_Py_convert_optional_to_ssize_t"])(a0,a1);var _Py_VaBuildValue=Module["_Py_VaBuildValue"]=(a0,a1)=>(_Py_VaBuildValue=Module["_Py_VaBuildValue"]=wasmExports["Py_VaBuildValue"])(a0,a1);var __Py_VaBuildValue_SizeT=Module["__Py_VaBuildValue_SizeT"]=(a0,a1)=>(__Py_VaBuildValue_SizeT=Module["__Py_VaBuildValue_SizeT"]=wasmExports["_Py_VaBuildValue_SizeT"])(a0,a1);var __PyModule_Add=Module["__PyModule_Add"]=(a0,a1,a2)=>(__PyModule_Add=Module["__PyModule_Add"]=wasmExports["_PyModule_Add"])(a0,a1,a2);var _PyModule_AddStringConstant=Module["_PyModule_AddStringConstant"]=(a0,a1,a2)=>(_PyModule_AddStringConstant=Module["_PyModule_AddStringConstant"]=wasmExports["PyModule_AddStringConstant"])(a0,a1,a2);var _vsnprintf=Module["_vsnprintf"]=(a0,a1,a2,a3)=>(_vsnprintf=Module["_vsnprintf"]=wasmExports["vsnprintf"])(a0,a1,a2,a3);var _PyOS_vsnprintf=Module["_PyOS_vsnprintf"]=(a0,a1,a2,a3)=>(_PyOS_vsnprintf=Module["_PyOS_vsnprintf"]=wasmExports["PyOS_vsnprintf"])(a0,a1,a2,a3);var __PyPathConfig_ClearGlobal=Module["__PyPathConfig_ClearGlobal"]=()=>(__PyPathConfig_ClearGlobal=Module["__PyPathConfig_ClearGlobal"]=wasmExports["_PyPathConfig_ClearGlobal"])();var _wcscpy=Module["_wcscpy"]=(a0,a1)=>(_wcscpy=Module["_wcscpy"]=wasmExports["wcscpy"])(a0,a1);var _Py_SetPath=Module["_Py_SetPath"]=a0=>(_Py_SetPath=Module["_Py_SetPath"]=wasmExports["Py_SetPath"])(a0);var _Py_SetPythonHome=Module["_Py_SetPythonHome"]=a0=>(_Py_SetPythonHome=Module["_Py_SetPythonHome"]=wasmExports["Py_SetPythonHome"])(a0);var _Py_SetProgramName=Module["_Py_SetProgramName"]=a0=>(_Py_SetProgramName=Module["_Py_SetProgramName"]=wasmExports["Py_SetProgramName"])(a0);var __Py_SetProgramFullPath=Module["__Py_SetProgramFullPath"]=a0=>(__Py_SetProgramFullPath=Module["__Py_SetProgramFullPath"]=wasmExports["_Py_SetProgramFullPath"])(a0);var _Py_GetPath=Module["_Py_GetPath"]=()=>(_Py_GetPath=Module["_Py_GetPath"]=wasmExports["Py_GetPath"])();var _Py_GetPrefix=Module["_Py_GetPrefix"]=()=>(_Py_GetPrefix=Module["_Py_GetPrefix"]=wasmExports["Py_GetPrefix"])();var _Py_GetExecPrefix=Module["_Py_GetExecPrefix"]=()=>(_Py_GetExecPrefix=Module["_Py_GetExecPrefix"]=wasmExports["Py_GetExecPrefix"])();var _Py_GetProgramFullPath=Module["_Py_GetProgramFullPath"]=()=>(_Py_GetProgramFullPath=Module["_Py_GetProgramFullPath"]=wasmExports["Py_GetProgramFullPath"])();var _Py_GetPythonHome=Module["_Py_GetPythonHome"]=()=>(_Py_GetPythonHome=Module["_Py_GetPythonHome"]=wasmExports["Py_GetPythonHome"])();var _Py_GetProgramName=Module["_Py_GetProgramName"]=()=>(_Py_GetProgramName=Module["_Py_GetProgramName"]=wasmExports["Py_GetProgramName"])();var __Py_wgetcwd=Module["__Py_wgetcwd"]=(a0,a1)=>(__Py_wgetcwd=Module["__Py_wgetcwd"]=wasmExports["_Py_wgetcwd"])(a0,a1);var __Py_wreadlink=Module["__Py_wreadlink"]=(a0,a1,a2)=>(__Py_wreadlink=Module["__Py_wreadlink"]=wasmExports["_Py_wreadlink"])(a0,a1,a2);var _wcsrchr=Module["_wcsrchr"]=(a0,a1)=>(_wcsrchr=Module["_wcsrchr"]=wasmExports["wcsrchr"])(a0,a1);var _wcsncpy=Module["_wcsncpy"]=(a0,a1,a2)=>(_wcsncpy=Module["_wcsncpy"]=wasmExports["wcsncpy"])(a0,a1,a2);var __Py_wrealpath=Module["__Py_wrealpath"]=(a0,a1,a2)=>(__Py_wrealpath=Module["__Py_wrealpath"]=wasmExports["_Py_wrealpath"])(a0,a1,a2);var _wcsncmp=Module["_wcsncmp"]=(a0,a1,a2)=>(_wcsncmp=Module["_wcsncmp"]=wasmExports["wcsncmp"])(a0,a1,a2);var __PyPreConfig_InitCompatConfig=Module["__PyPreConfig_InitCompatConfig"]=a0=>(__PyPreConfig_InitCompatConfig=Module["__PyPreConfig_InitCompatConfig"]=wasmExports["_PyPreConfig_InitCompatConfig"])(a0);var _PyPreConfig_InitIsolatedConfig=Module["_PyPreConfig_InitIsolatedConfig"]=a0=>(_PyPreConfig_InitIsolatedConfig=Module["_PyPreConfig_InitIsolatedConfig"]=wasmExports["PyPreConfig_InitIsolatedConfig"])(a0);var __Py_SetLocaleFromEnv=Module["__Py_SetLocaleFromEnv"]=a0=>(__Py_SetLocaleFromEnv=Module["__Py_SetLocaleFromEnv"]=wasmExports["_Py_SetLocaleFromEnv"])(a0);var __Py_LegacyLocaleDetected=Module["__Py_LegacyLocaleDetected"]=a0=>(__Py_LegacyLocaleDetected=Module["__Py_LegacyLocaleDetected"]=wasmExports["_Py_LegacyLocaleDetected"])(a0);var __Py_CoerceLegacyLocale=Module["__Py_CoerceLegacyLocale"]=a0=>(__Py_CoerceLegacyLocale=Module["__Py_CoerceLegacyLocale"]=wasmExports["_Py_CoerceLegacyLocale"])(a0);var _PyHash_GetFuncDef=Module["_PyHash_GetFuncDef"]=()=>(_PyHash_GetFuncDef=Module["_PyHash_GetFuncDef"]=wasmExports["PyHash_GetFuncDef"])();var __PyRuntimeState_Init=Module["__PyRuntimeState_Init"]=(a0,a1)=>(__PyRuntimeState_Init=Module["__PyRuntimeState_Init"]=wasmExports["_PyRuntimeState_Init"])(a0,a1);var __PyRuntime_Finalize=Module["__PyRuntime_Finalize"]=()=>(__PyRuntime_Finalize=Module["__PyRuntime_Finalize"]=wasmExports["_PyRuntime_Finalize"])();var __PyRuntimeState_Fini=Module["__PyRuntimeState_Fini"]=a0=>(__PyRuntimeState_Fini=Module["__PyRuntimeState_Fini"]=wasmExports["_PyRuntimeState_Fini"])(a0);var __Py_IsFinalizing=Module["__Py_IsFinalizing"]=()=>(__Py_IsFinalizing=Module["__Py_IsFinalizing"]=wasmExports["_Py_IsFinalizing"])();var __Py_IsCoreInitialized=Module["__Py_IsCoreInitialized"]=()=>(__Py_IsCoreInitialized=Module["__Py_IsCoreInitialized"]=wasmExports["_Py_IsCoreInitialized"])();var _nl_langinfo=Module["_nl_langinfo"]=a0=>(_nl_langinfo=Module["_nl_langinfo"]=wasmExports["nl_langinfo"])(a0);var __Py_ResetForceASCII=Module["__Py_ResetForceASCII"]=()=>(__Py_ResetForceASCII=Module["__Py_ResetForceASCII"]=wasmExports["_Py_ResetForceASCII"])();var _setenv=Module["_setenv"]=(a0,a1,a2)=>(_setenv=Module["_setenv"]=wasmExports["setenv"])(a0,a1,a2);var __PyInterpreterState_SetConfig=Module["__PyInterpreterState_SetConfig"]=a0=>(__PyInterpreterState_SetConfig=Module["__PyInterpreterState_SetConfig"]=wasmExports["_PyInterpreterState_SetConfig"])(a0);var __Py_PreInitializeFromPyArgv=Module["__Py_PreInitializeFromPyArgv"]=(a0,a1,a2)=>(__Py_PreInitializeFromPyArgv=Module["__Py_PreInitializeFromPyArgv"]=wasmExports["_Py_PreInitializeFromPyArgv"])(a0,a1,a2);var _Py_PreInitializeFromArgs=Module["_Py_PreInitializeFromArgs"]=(a0,a1,a2,a3)=>(_Py_PreInitializeFromArgs=Module["_Py_PreInitializeFromArgs"]=wasmExports["Py_PreInitializeFromArgs"])(a0,a1,a2,a3);var _Py_PreInitialize=Module["_Py_PreInitialize"]=(a0,a1)=>(_Py_PreInitialize=Module["_Py_PreInitialize"]=wasmExports["Py_PreInitialize"])(a0,a1);var _Py_InitializeEx=Module["_Py_InitializeEx"]=a0=>(_Py_InitializeEx=Module["_Py_InitializeEx"]=wasmExports["Py_InitializeEx"])(a0);var _Py_FatalError=Module["_Py_FatalError"]=a0=>(_Py_FatalError=Module["_Py_FatalError"]=wasmExports["Py_FatalError"])(a0);var _Py_Initialize=Module["_Py_Initialize"]=()=>(_Py_Initialize=Module["_Py_Initialize"]=wasmExports["Py_Initialize"])();var __Py_InitializeMain=Module["__Py_InitializeMain"]=a0=>(__Py_InitializeMain=Module["__Py_InitializeMain"]=wasmExports["_Py_InitializeMain"])(a0);var _PyGC_Collect=Module["_PyGC_Collect"]=()=>(_PyGC_Collect=Module["_PyGC_Collect"]=wasmExports["PyGC_Collect"])();var _PyInterpreterState_Delete=Module["_PyInterpreterState_Delete"]=a0=>(_PyInterpreterState_Delete=Module["_PyInterpreterState_Delete"]=wasmExports["PyInterpreterState_Delete"])(a0);var _Py_Finalize=Module["_Py_Finalize"]=()=>(_Py_Finalize=Module["_Py_Finalize"]=wasmExports["Py_Finalize"])();var _Py_NewInterpreterFromConfig=Module["_Py_NewInterpreterFromConfig"]=(a0,a1,a2)=>(_Py_NewInterpreterFromConfig=Module["_Py_NewInterpreterFromConfig"]=wasmExports["Py_NewInterpreterFromConfig"])(a0,a1,a2);var _PyInterpreterState_New=Module["_PyInterpreterState_New"]=()=>(_PyInterpreterState_New=Module["_PyInterpreterState_New"]=wasmExports["PyInterpreterState_New"])();var __PyThreadState_New=Module["__PyThreadState_New"]=a0=>(__PyThreadState_New=Module["__PyThreadState_New"]=wasmExports["_PyThreadState_New"])(a0);var __PyThreadState_Bind=Module["__PyThreadState_Bind"]=a0=>(__PyThreadState_Bind=Module["__PyThreadState_Bind"]=wasmExports["_PyThreadState_Bind"])(a0);var _PyErr_PrintEx=Module["_PyErr_PrintEx"]=a0=>(_PyErr_PrintEx=Module["_PyErr_PrintEx"]=wasmExports["PyErr_PrintEx"])(a0);var _Py_NewInterpreter=Module["_Py_NewInterpreter"]=()=>(_Py_NewInterpreter=Module["_Py_NewInterpreter"]=wasmExports["Py_NewInterpreter"])();var _Py_EndInterpreter=Module["_Py_EndInterpreter"]=a0=>(_Py_EndInterpreter=Module["_Py_EndInterpreter"]=wasmExports["Py_EndInterpreter"])(a0);var __Py_DumpExtensionModules=Module["__Py_DumpExtensionModules"]=(a0,a1)=>(__Py_DumpExtensionModules=Module["__Py_DumpExtensionModules"]=wasmExports["_Py_DumpExtensionModules"])(a0,a1);var __Py_write_noraise=Module["__Py_write_noraise"]=(a0,a1,a2)=>(__Py_write_noraise=Module["__Py_write_noraise"]=wasmExports["_Py_write_noraise"])(a0,a1,a2);var __Py_DumpASCII=Module["__Py_DumpASCII"]=(a0,a1)=>(__Py_DumpASCII=Module["__Py_DumpASCII"]=wasmExports["_Py_DumpASCII"])(a0,a1);var __Py_DumpDecimal=Module["__Py_DumpDecimal"]=(a0,a1)=>(__Py_DumpDecimal=Module["__Py_DumpDecimal"]=wasmExports["_Py_DumpDecimal"])(a0,a1);var __Py_DumpHexadecimal=Module["__Py_DumpHexadecimal"]=(a0,a1,a2)=>(__Py_DumpHexadecimal=Module["__Py_DumpHexadecimal"]=wasmExports["_Py_DumpHexadecimal"])(a0,a1,a2);var __Py_DumpTracebackThreads=Module["__Py_DumpTracebackThreads"]=(a0,a1,a2)=>(__Py_DumpTracebackThreads=Module["__Py_DumpTracebackThreads"]=wasmExports["_Py_DumpTracebackThreads"])(a0,a1,a2);var _vfprintf=Module["_vfprintf"]=(a0,a1,a2)=>(_vfprintf=Module["_vfprintf"]=wasmExports["vfprintf"])(a0,a1,a2);var __Py_FatalRefcountErrorFunc=Module["__Py_FatalRefcountErrorFunc"]=(a0,a1)=>(__Py_FatalRefcountErrorFunc=Module["__Py_FatalRefcountErrorFunc"]=wasmExports["_Py_FatalRefcountErrorFunc"])(a0,a1);var _Py_AtExit=Module["_Py_AtExit"]=a0=>(_Py_AtExit=Module["_Py_AtExit"]=wasmExports["Py_AtExit"])(a0);var _Py_Exit=Module["_Py_Exit"]=a0=>(_Py_Exit=Module["_Py_Exit"]=wasmExports["Py_Exit"])(a0);var _Py_FdIsInteractive=Module["_Py_FdIsInteractive"]=(a0,a1)=>(_Py_FdIsInteractive=Module["_Py_FdIsInteractive"]=wasmExports["Py_FdIsInteractive"])(a0,a1);var __Py_FdIsInteractive=Module["__Py_FdIsInteractive"]=(a0,a1)=>(__Py_FdIsInteractive=Module["__Py_FdIsInteractive"]=wasmExports["_Py_FdIsInteractive"])(a0,a1);var _PyOS_getsig=Module["_PyOS_getsig"]=a0=>(_PyOS_getsig=Module["_PyOS_getsig"]=wasmExports["PyOS_getsig"])(a0);var _signal=Module["_signal"]=(a0,a1)=>(_signal=Module["_signal"]=wasmExports["signal"])(a0,a1);var _PyOS_setsig=Module["_PyOS_setsig"]=(a0,a1)=>(_PyOS_setsig=Module["_PyOS_setsig"]=wasmExports["PyOS_setsig"])(a0,a1);var _siginterrupt=Module["_siginterrupt"]=(a0,a1)=>(_siginterrupt=Module["_siginterrupt"]=wasmExports["siginterrupt"])(a0,a1);var __PyInterpreterState_Enable=Module["__PyInterpreterState_Enable"]=(a0,a1)=>(__PyInterpreterState_Enable=Module["__PyInterpreterState_Enable"]=wasmExports["_PyInterpreterState_Enable"])(a0,a1);var __PyTraceMalloc_Start=Module["__PyTraceMalloc_Start"]=a0=>(__PyTraceMalloc_Start=Module["__PyTraceMalloc_Start"]=wasmExports["_PyTraceMalloc_Start"])(a0);var _PySys_SetObject=Module["_PySys_SetObject"]=(a0,a1)=>(_PySys_SetObject=Module["_PySys_SetObject"]=wasmExports["PySys_SetObject"])(a0,a1);var _fcntl=Module["_fcntl"]=(a0,a1,a2)=>(_fcntl=Module["_fcntl"]=wasmExports["fcntl"])(a0,a1,a2);var _PyOS_mystrnicmp=Module["_PyOS_mystrnicmp"]=(a0,a1,a2)=>(_PyOS_mystrnicmp=Module["_PyOS_mystrnicmp"]=wasmExports["PyOS_mystrnicmp"])(a0,a1,a2);var __PyThreadState_GetCurrent=Module["__PyThreadState_GetCurrent"]=()=>(__PyThreadState_GetCurrent=Module["__PyThreadState_GetCurrent"]=wasmExports["_PyThreadState_GetCurrent"])();var _PyThread_tss_create=Module["_PyThread_tss_create"]=a0=>(_PyThread_tss_create=Module["_PyThread_tss_create"]=wasmExports["PyThread_tss_create"])(a0);var _PyThread_tss_delete=Module["_PyThread_tss_delete"]=a0=>(_PyThread_tss_delete=Module["_PyThread_tss_delete"]=wasmExports["PyThread_tss_delete"])(a0);var _PyInterpreterState_Clear=Module["_PyInterpreterState_Clear"]=a0=>(_PyInterpreterState_Clear=Module["_PyInterpreterState_Clear"]=wasmExports["PyInterpreterState_Clear"])(a0);var __PyThreadState_Swap=Module["__PyThreadState_Swap"]=(a0,a1)=>(__PyThreadState_Swap=Module["__PyThreadState_Swap"]=wasmExports["_PyThreadState_Swap"])(a0,a1);var __PyInterpreterState_SetRunningMain=Module["__PyInterpreterState_SetRunningMain"]=a0=>(__PyInterpreterState_SetRunningMain=Module["__PyInterpreterState_SetRunningMain"]=wasmExports["_PyInterpreterState_SetRunningMain"])(a0);var __PyInterpreterState_SetNotRunningMain=Module["__PyInterpreterState_SetNotRunningMain"]=a0=>(__PyInterpreterState_SetNotRunningMain=Module["__PyInterpreterState_SetNotRunningMain"]=wasmExports["_PyInterpreterState_SetNotRunningMain"])(a0);var __PyInterpreterState_IsRunningMain=Module["__PyInterpreterState_IsRunningMain"]=a0=>(__PyInterpreterState_IsRunningMain=Module["__PyInterpreterState_IsRunningMain"]=wasmExports["_PyInterpreterState_IsRunningMain"])(a0);var __PyInterpreterState_RequiresIDRef=Module["__PyInterpreterState_RequiresIDRef"]=a0=>(__PyInterpreterState_RequiresIDRef=Module["__PyInterpreterState_RequiresIDRef"]=wasmExports["_PyInterpreterState_RequiresIDRef"])(a0);var __PyInterpreterState_RequireIDRef=Module["__PyInterpreterState_RequireIDRef"]=(a0,a1)=>(__PyInterpreterState_RequireIDRef=Module["__PyInterpreterState_RequireIDRef"]=wasmExports["_PyInterpreterState_RequireIDRef"])(a0,a1);var __PyInterpreterState_GetMainModule=Module["__PyInterpreterState_GetMainModule"]=a0=>(__PyInterpreterState_GetMainModule=Module["__PyInterpreterState_GetMainModule"]=wasmExports["_PyInterpreterState_GetMainModule"])(a0);var _PyInterpreterState_GetDict=Module["_PyInterpreterState_GetDict"]=a0=>(_PyInterpreterState_GetDict=Module["_PyInterpreterState_GetDict"]=wasmExports["PyInterpreterState_GetDict"])(a0);var __PyThreadState_Prealloc=Module["__PyThreadState_Prealloc"]=a0=>(__PyThreadState_Prealloc=Module["__PyThreadState_Prealloc"]=wasmExports["_PyThreadState_Prealloc"])(a0);var __PyThreadState_Init=Module["__PyThreadState_Init"]=a0=>(__PyThreadState_Init=Module["__PyThreadState_Init"]=wasmExports["_PyThreadState_Init"])(a0);var __PyThreadState_DeleteCurrent=Module["__PyThreadState_DeleteCurrent"]=a0=>(__PyThreadState_DeleteCurrent=Module["__PyThreadState_DeleteCurrent"]=wasmExports["_PyThreadState_DeleteCurrent"])(a0);var _PyThreadState_DeleteCurrent=Module["_PyThreadState_DeleteCurrent"]=()=>(_PyThreadState_DeleteCurrent=Module["_PyThreadState_DeleteCurrent"]=wasmExports["PyThreadState_DeleteCurrent"])();var __PyThreadState_GetDict=Module["__PyThreadState_GetDict"]=a0=>(__PyThreadState_GetDict=Module["__PyThreadState_GetDict"]=wasmExports["_PyThreadState_GetDict"])(a0);var _PyThreadState_GetInterpreter=Module["_PyThreadState_GetInterpreter"]=a0=>(_PyThreadState_GetInterpreter=Module["_PyThreadState_GetInterpreter"]=wasmExports["PyThreadState_GetInterpreter"])(a0);var _PyThreadState_GetID=Module["_PyThreadState_GetID"]=a0=>(_PyThreadState_GetID=Module["_PyThreadState_GetID"]=wasmExports["PyThreadState_GetID"])(a0);var _PyThreadState_SetAsyncExc=Module["_PyThreadState_SetAsyncExc"]=(a0,a1)=>(_PyThreadState_SetAsyncExc=Module["_PyThreadState_SetAsyncExc"]=wasmExports["PyThreadState_SetAsyncExc"])(a0,a1);var _PyInterpreterState_Head=Module["_PyInterpreterState_Head"]=()=>(_PyInterpreterState_Head=Module["_PyInterpreterState_Head"]=wasmExports["PyInterpreterState_Head"])();var _PyInterpreterState_Main=Module["_PyInterpreterState_Main"]=()=>(_PyInterpreterState_Main=Module["_PyInterpreterState_Main"]=wasmExports["PyInterpreterState_Main"])();var _PyInterpreterState_Next=Module["_PyInterpreterState_Next"]=a0=>(_PyInterpreterState_Next=Module["_PyInterpreterState_Next"]=wasmExports["PyInterpreterState_Next"])(a0);var __PyThread_CurrentFrames=Module["__PyThread_CurrentFrames"]=()=>(__PyThread_CurrentFrames=Module["__PyThread_CurrentFrames"]=wasmExports["_PyThread_CurrentFrames"])();var __PyThread_CurrentExceptions=Module["__PyThread_CurrentExceptions"]=()=>(__PyThread_CurrentExceptions=Module["__PyThread_CurrentExceptions"]=wasmExports["_PyThread_CurrentExceptions"])();var __PyGILState_GetInterpreterStateUnsafe=Module["__PyGILState_GetInterpreterStateUnsafe"]=()=>(__PyGILState_GetInterpreterStateUnsafe=Module["__PyGILState_GetInterpreterStateUnsafe"]=wasmExports["_PyGILState_GetInterpreterStateUnsafe"])();var __PyCrossInterpreterData_Init=Module["__PyCrossInterpreterData_Init"]=(a0,a1,a2,a3,a4)=>(__PyCrossInterpreterData_Init=Module["__PyCrossInterpreterData_Init"]=wasmExports["_PyCrossInterpreterData_Init"])(a0,a1,a2,a3,a4);var __PyCrossInterpreterData_InitWithSize=Module["__PyCrossInterpreterData_InitWithSize"]=(a0,a1,a2,a3,a4)=>(__PyCrossInterpreterData_InitWithSize=Module["__PyCrossInterpreterData_InitWithSize"]=wasmExports["_PyCrossInterpreterData_InitWithSize"])(a0,a1,a2,a3,a4);var __PyCrossInterpreterData_Clear=Module["__PyCrossInterpreterData_Clear"]=(a0,a1)=>(__PyCrossInterpreterData_Clear=Module["__PyCrossInterpreterData_Clear"]=wasmExports["_PyCrossInterpreterData_Clear"])(a0,a1);var __PyObject_CheckCrossInterpreterData=Module["__PyObject_CheckCrossInterpreterData"]=a0=>(__PyObject_CheckCrossInterpreterData=Module["__PyObject_CheckCrossInterpreterData"]=wasmExports["_PyObject_CheckCrossInterpreterData"])(a0);var __PyObject_GetCrossInterpreterData=Module["__PyObject_GetCrossInterpreterData"]=(a0,a1)=>(__PyObject_GetCrossInterpreterData=Module["__PyObject_GetCrossInterpreterData"]=wasmExports["_PyObject_GetCrossInterpreterData"])(a0,a1);var __PyCrossInterpreterData_Release=Module["__PyCrossInterpreterData_Release"]=a0=>(__PyCrossInterpreterData_Release=Module["__PyCrossInterpreterData_Release"]=wasmExports["_PyCrossInterpreterData_Release"])(a0);var __PyCrossInterpreterData_NewObject=Module["__PyCrossInterpreterData_NewObject"]=a0=>(__PyCrossInterpreterData_NewObject=Module["__PyCrossInterpreterData_NewObject"]=wasmExports["_PyCrossInterpreterData_NewObject"])(a0);var __PyCrossInterpreterData_ReleaseAndRawFree=Module["__PyCrossInterpreterData_ReleaseAndRawFree"]=a0=>(__PyCrossInterpreterData_ReleaseAndRawFree=Module["__PyCrossInterpreterData_ReleaseAndRawFree"]=wasmExports["_PyCrossInterpreterData_ReleaseAndRawFree"])(a0);var __PyCrossInterpreterData_RegisterClass=Module["__PyCrossInterpreterData_RegisterClass"]=(a0,a1)=>(__PyCrossInterpreterData_RegisterClass=Module["__PyCrossInterpreterData_RegisterClass"]=wasmExports["_PyCrossInterpreterData_RegisterClass"])(a0,a1);var __PyCrossInterpreterData_UnregisterClass=Module["__PyCrossInterpreterData_UnregisterClass"]=a0=>(__PyCrossInterpreterData_UnregisterClass=Module["__PyCrossInterpreterData_UnregisterClass"]=wasmExports["_PyCrossInterpreterData_UnregisterClass"])(a0);var __PyCrossInterpreterData_Lookup=Module["__PyCrossInterpreterData_Lookup"]=a0=>(__PyCrossInterpreterData_Lookup=Module["__PyCrossInterpreterData_Lookup"]=wasmExports["_PyCrossInterpreterData_Lookup"])(a0);var __PyInterpreterState_GetEvalFrameFunc=Module["__PyInterpreterState_GetEvalFrameFunc"]=a0=>(__PyInterpreterState_GetEvalFrameFunc=Module["__PyInterpreterState_GetEvalFrameFunc"]=wasmExports["_PyInterpreterState_GetEvalFrameFunc"])(a0);var __PyInterpreterState_SetEvalFrameFunc=Module["__PyInterpreterState_SetEvalFrameFunc"]=(a0,a1)=>(__PyInterpreterState_SetEvalFrameFunc=Module["__PyInterpreterState_SetEvalFrameFunc"]=wasmExports["_PyInterpreterState_SetEvalFrameFunc"])(a0,a1);var __PyInterpreterState_GetConfigCopy=Module["__PyInterpreterState_GetConfigCopy"]=a0=>(__PyInterpreterState_GetConfigCopy=Module["__PyInterpreterState_GetConfigCopy"]=wasmExports["_PyInterpreterState_GetConfigCopy"])(a0);var __PyRun_AnyFileObject=Module["__PyRun_AnyFileObject"]=(a0,a1,a2,a3)=>(__PyRun_AnyFileObject=Module["__PyRun_AnyFileObject"]=wasmExports["_PyRun_AnyFileObject"])(a0,a1,a2,a3);var __PyRun_InteractiveLoopObject=Module["__PyRun_InteractiveLoopObject"]=(a0,a1,a2)=>(__PyRun_InteractiveLoopObject=Module["__PyRun_InteractiveLoopObject"]=wasmExports["_PyRun_InteractiveLoopObject"])(a0,a1,a2);var __PyRun_SimpleFileObject=Module["__PyRun_SimpleFileObject"]=(a0,a1,a2,a3)=>(__PyRun_SimpleFileObject=Module["__PyRun_SimpleFileObject"]=wasmExports["_PyRun_SimpleFileObject"])(a0,a1,a2,a3);var _rewind=Module["_rewind"]=a0=>(_rewind=Module["_rewind"]=wasmExports["rewind"])(a0);var _PyRun_InteractiveLoopFlags=Module["_PyRun_InteractiveLoopFlags"]=(a0,a1,a2)=>(_PyRun_InteractiveLoopFlags=Module["_PyRun_InteractiveLoopFlags"]=wasmExports["PyRun_InteractiveLoopFlags"])(a0,a1,a2);var _PyRun_InteractiveOneObject=Module["_PyRun_InteractiveOneObject"]=(a0,a1,a2)=>(_PyRun_InteractiveOneObject=Module["_PyRun_InteractiveOneObject"]=wasmExports["PyRun_InteractiveOneObject"])(a0,a1,a2);var _PyRun_InteractiveOneFlags=Module["_PyRun_InteractiveOneFlags"]=(a0,a1,a2)=>(_PyRun_InteractiveOneFlags=Module["_PyRun_InteractiveOneFlags"]=wasmExports["PyRun_InteractiveOneFlags"])(a0,a1,a2);var _PyRun_SimpleFileExFlags=Module["_PyRun_SimpleFileExFlags"]=(a0,a1,a2,a3)=>(_PyRun_SimpleFileExFlags=Module["_PyRun_SimpleFileExFlags"]=wasmExports["PyRun_SimpleFileExFlags"])(a0,a1,a2,a3);var _PyRun_SimpleStringFlags=Module["_PyRun_SimpleStringFlags"]=(a0,a1)=>(_PyRun_SimpleStringFlags=Module["_PyRun_SimpleStringFlags"]=wasmExports["PyRun_SimpleStringFlags"])(a0,a1);var __Py_HandleSystemExit=Module["__Py_HandleSystemExit"]=a0=>(__Py_HandleSystemExit=Module["__Py_HandleSystemExit"]=wasmExports["_Py_HandleSystemExit"])(a0);var _PyErr_Display=Module["_PyErr_Display"]=(a0,a1,a2)=>(_PyErr_Display=Module["_PyErr_Display"]=wasmExports["PyErr_Display"])(a0,a1,a2);var __PyErr_Display=Module["__PyErr_Display"]=(a0,a1,a2,a3)=>(__PyErr_Display=Module["__PyErr_Display"]=wasmExports["_PyErr_Display"])(a0,a1,a2,a3);var __Py_WriteIndentedMargin=Module["__Py_WriteIndentedMargin"]=(a0,a1,a2)=>(__Py_WriteIndentedMargin=Module["__Py_WriteIndentedMargin"]=wasmExports["_Py_WriteIndentedMargin"])(a0,a1,a2);var __Py_WriteIndent=Module["__Py_WriteIndent"]=(a0,a1)=>(__Py_WriteIndent=Module["__Py_WriteIndent"]=wasmExports["_Py_WriteIndent"])(a0,a1);var __PyErr_DisplayException=Module["__PyErr_DisplayException"]=(a0,a1)=>(__PyErr_DisplayException=Module["__PyErr_DisplayException"]=wasmExports["_PyErr_DisplayException"])(a0,a1);var _PyRun_FileExFlags=Module["_PyRun_FileExFlags"]=(a0,a1,a2,a3,a4,a5,a6)=>(_PyRun_FileExFlags=Module["_PyRun_FileExFlags"]=wasmExports["PyRun_FileExFlags"])(a0,a1,a2,a3,a4,a5,a6);var _Py_CompileStringExFlags=Module["_Py_CompileStringExFlags"]=(a0,a1,a2,a3,a4)=>(_Py_CompileStringExFlags=Module["_Py_CompileStringExFlags"]=wasmExports["Py_CompileStringExFlags"])(a0,a1,a2,a3,a4);var _PyRun_AnyFile=Module["_PyRun_AnyFile"]=(a0,a1)=>(_PyRun_AnyFile=Module["_PyRun_AnyFile"]=wasmExports["PyRun_AnyFile"])(a0,a1);var _PyRun_AnyFileEx=Module["_PyRun_AnyFileEx"]=(a0,a1,a2)=>(_PyRun_AnyFileEx=Module["_PyRun_AnyFileEx"]=wasmExports["PyRun_AnyFileEx"])(a0,a1,a2);var _PyRun_AnyFileFlags=Module["_PyRun_AnyFileFlags"]=(a0,a1,a2)=>(_PyRun_AnyFileFlags=Module["_PyRun_AnyFileFlags"]=wasmExports["PyRun_AnyFileFlags"])(a0,a1,a2);var _PyRun_File=Module["_PyRun_File"]=(a0,a1,a2,a3,a4)=>(_PyRun_File=Module["_PyRun_File"]=wasmExports["PyRun_File"])(a0,a1,a2,a3,a4);var _PyRun_FileEx=Module["_PyRun_FileEx"]=(a0,a1,a2,a3,a4,a5)=>(_PyRun_FileEx=Module["_PyRun_FileEx"]=wasmExports["PyRun_FileEx"])(a0,a1,a2,a3,a4,a5);var _PyRun_FileFlags=Module["_PyRun_FileFlags"]=(a0,a1,a2,a3,a4,a5)=>(_PyRun_FileFlags=Module["_PyRun_FileFlags"]=wasmExports["PyRun_FileFlags"])(a0,a1,a2,a3,a4,a5);var _PyRun_SimpleFile=Module["_PyRun_SimpleFile"]=(a0,a1)=>(_PyRun_SimpleFile=Module["_PyRun_SimpleFile"]=wasmExports["PyRun_SimpleFile"])(a0,a1);var _PyRun_SimpleFileEx=Module["_PyRun_SimpleFileEx"]=(a0,a1,a2)=>(_PyRun_SimpleFileEx=Module["_PyRun_SimpleFileEx"]=wasmExports["PyRun_SimpleFileEx"])(a0,a1,a2);var _PyRun_String=Module["_PyRun_String"]=(a0,a1,a2,a3)=>(_PyRun_String=Module["_PyRun_String"]=wasmExports["PyRun_String"])(a0,a1,a2,a3);var _PyRun_SimpleString=Module["_PyRun_SimpleString"]=a0=>(_PyRun_SimpleString=Module["_PyRun_SimpleString"]=wasmExports["PyRun_SimpleString"])(a0);var _Py_CompileString=Module["_Py_CompileString"]=(a0,a1,a2)=>(_Py_CompileString=Module["_Py_CompileString"]=wasmExports["Py_CompileString"])(a0,a1,a2);var _Py_CompileStringFlags=Module["_Py_CompileStringFlags"]=(a0,a1,a2,a3)=>(_Py_CompileStringFlags=Module["_Py_CompileStringFlags"]=wasmExports["Py_CompileStringFlags"])(a0,a1,a2,a3);var _PyRun_InteractiveOne=Module["_PyRun_InteractiveOne"]=(a0,a1)=>(_PyRun_InteractiveOne=Module["_PyRun_InteractiveOne"]=wasmExports["PyRun_InteractiveOne"])(a0,a1);var _PyRun_InteractiveLoop=Module["_PyRun_InteractiveLoop"]=(a0,a1)=>(_PyRun_InteractiveLoop=Module["_PyRun_InteractiveLoop"]=wasmExports["PyRun_InteractiveLoop"])(a0,a1);var __PyTraceBack_Print_Indented=Module["__PyTraceBack_Print_Indented"]=(a0,a1,a2,a3,a4,a5)=>(__PyTraceBack_Print_Indented=Module["__PyTraceBack_Print_Indented"]=wasmExports["_PyTraceBack_Print_Indented"])(a0,a1,a2,a3,a4,a5);var __PyTime_Add=Module["__PyTime_Add"]=(a0,a1)=>(__PyTime_Add=Module["__PyTime_Add"]=wasmExports["_PyTime_Add"])(a0,a1);var __PyTime_MulDiv=Module["__PyTime_MulDiv"]=(a0,a1,a2)=>(__PyTime_MulDiv=Module["__PyTime_MulDiv"]=wasmExports["_PyTime_MulDiv"])(a0,a1,a2);var __PyLong_AsTime_t=Module["__PyLong_AsTime_t"]=a0=>(__PyLong_AsTime_t=Module["__PyLong_AsTime_t"]=wasmExports["_PyLong_AsTime_t"])(a0);var __PyLong_FromTime_t=Module["__PyLong_FromTime_t"]=a0=>(__PyLong_FromTime_t=Module["__PyLong_FromTime_t"]=wasmExports["_PyLong_FromTime_t"])(a0);var __PyTime_ObjectToTime_t=Module["__PyTime_ObjectToTime_t"]=(a0,a1,a2)=>(__PyTime_ObjectToTime_t=Module["__PyTime_ObjectToTime_t"]=wasmExports["_PyTime_ObjectToTime_t"])(a0,a1,a2);var __PyTime_ObjectToTimespec=Module["__PyTime_ObjectToTimespec"]=(a0,a1,a2,a3)=>(__PyTime_ObjectToTimespec=Module["__PyTime_ObjectToTimespec"]=wasmExports["_PyTime_ObjectToTimespec"])(a0,a1,a2,a3);var __PyTime_ObjectToTimeval=Module["__PyTime_ObjectToTimeval"]=(a0,a1,a2,a3)=>(__PyTime_ObjectToTimeval=Module["__PyTime_ObjectToTimeval"]=wasmExports["_PyTime_ObjectToTimeval"])(a0,a1,a2,a3);var __PyTime_FromSeconds=Module["__PyTime_FromSeconds"]=a0=>(__PyTime_FromSeconds=Module["__PyTime_FromSeconds"]=wasmExports["_PyTime_FromSeconds"])(a0);var __PyTime_FromNanoseconds=Module["__PyTime_FromNanoseconds"]=a0=>(__PyTime_FromNanoseconds=Module["__PyTime_FromNanoseconds"]=wasmExports["_PyTime_FromNanoseconds"])(a0);var __PyTime_FromMicrosecondsClamp=Module["__PyTime_FromMicrosecondsClamp"]=a0=>(__PyTime_FromMicrosecondsClamp=Module["__PyTime_FromMicrosecondsClamp"]=wasmExports["_PyTime_FromMicrosecondsClamp"])(a0);var __PyTime_FromNanosecondsObject=Module["__PyTime_FromNanosecondsObject"]=(a0,a1)=>(__PyTime_FromNanosecondsObject=Module["__PyTime_FromNanosecondsObject"]=wasmExports["_PyTime_FromNanosecondsObject"])(a0,a1);var __PyTime_FromTimespec=Module["__PyTime_FromTimespec"]=(a0,a1)=>(__PyTime_FromTimespec=Module["__PyTime_FromTimespec"]=wasmExports["_PyTime_FromTimespec"])(a0,a1);var __PyTime_FromTimeval=Module["__PyTime_FromTimeval"]=(a0,a1)=>(__PyTime_FromTimeval=Module["__PyTime_FromTimeval"]=wasmExports["_PyTime_FromTimeval"])(a0,a1);var __PyTime_FromSecondsObject=Module["__PyTime_FromSecondsObject"]=(a0,a1,a2)=>(__PyTime_FromSecondsObject=Module["__PyTime_FromSecondsObject"]=wasmExports["_PyTime_FromSecondsObject"])(a0,a1,a2);var __PyTime_FromMillisecondsObject=Module["__PyTime_FromMillisecondsObject"]=(a0,a1,a2)=>(__PyTime_FromMillisecondsObject=Module["__PyTime_FromMillisecondsObject"]=wasmExports["_PyTime_FromMillisecondsObject"])(a0,a1,a2);var __PyTime_AsSecondsDouble=Module["__PyTime_AsSecondsDouble"]=a0=>(__PyTime_AsSecondsDouble=Module["__PyTime_AsSecondsDouble"]=wasmExports["_PyTime_AsSecondsDouble"])(a0);var __PyTime_AsNanosecondsObject=Module["__PyTime_AsNanosecondsObject"]=a0=>(__PyTime_AsNanosecondsObject=Module["__PyTime_AsNanosecondsObject"]=wasmExports["_PyTime_AsNanosecondsObject"])(a0);var __PyTime_AsNanoseconds=Module["__PyTime_AsNanoseconds"]=a0=>(__PyTime_AsNanoseconds=Module["__PyTime_AsNanoseconds"]=wasmExports["_PyTime_AsNanoseconds"])(a0);var __PyTime_AsMilliseconds=Module["__PyTime_AsMilliseconds"]=(a0,a1)=>(__PyTime_AsMilliseconds=Module["__PyTime_AsMilliseconds"]=wasmExports["_PyTime_AsMilliseconds"])(a0,a1);var __PyTime_AsTimeval=Module["__PyTime_AsTimeval"]=(a0,a1,a2)=>(__PyTime_AsTimeval=Module["__PyTime_AsTimeval"]=wasmExports["_PyTime_AsTimeval"])(a0,a1,a2);var __PyTime_AsTimeval_clamp=Module["__PyTime_AsTimeval_clamp"]=(a0,a1,a2)=>(__PyTime_AsTimeval_clamp=Module["__PyTime_AsTimeval_clamp"]=wasmExports["_PyTime_AsTimeval_clamp"])(a0,a1,a2);var __PyTime_AsTimevalTime_t=Module["__PyTime_AsTimevalTime_t"]=(a0,a1,a2,a3)=>(__PyTime_AsTimevalTime_t=Module["__PyTime_AsTimevalTime_t"]=wasmExports["_PyTime_AsTimevalTime_t"])(a0,a1,a2,a3);var __PyTime_AsTimespec_clamp=Module["__PyTime_AsTimespec_clamp"]=(a0,a1)=>(__PyTime_AsTimespec_clamp=Module["__PyTime_AsTimespec_clamp"]=wasmExports["_PyTime_AsTimespec_clamp"])(a0,a1);var __PyTime_AsTimespec=Module["__PyTime_AsTimespec"]=(a0,a1)=>(__PyTime_AsTimespec=Module["__PyTime_AsTimespec"]=wasmExports["_PyTime_AsTimespec"])(a0,a1);var __PyTime_GetSystemClock=Module["__PyTime_GetSystemClock"]=()=>(__PyTime_GetSystemClock=Module["__PyTime_GetSystemClock"]=wasmExports["_PyTime_GetSystemClock"])();var _clock_gettime=Module["_clock_gettime"]=(a0,a1)=>(_clock_gettime=Module["_clock_gettime"]=wasmExports["clock_gettime"])(a0,a1);var __PyTime_GetSystemClockWithInfo=Module["__PyTime_GetSystemClockWithInfo"]=(a0,a1)=>(__PyTime_GetSystemClockWithInfo=Module["__PyTime_GetSystemClockWithInfo"]=wasmExports["_PyTime_GetSystemClockWithInfo"])(a0,a1);var _clock_getres=Module["_clock_getres"]=(a0,a1)=>(_clock_getres=Module["_clock_getres"]=wasmExports["clock_getres"])(a0,a1);var __PyTime_GetMonotonicClock=Module["__PyTime_GetMonotonicClock"]=()=>(__PyTime_GetMonotonicClock=Module["__PyTime_GetMonotonicClock"]=wasmExports["_PyTime_GetMonotonicClock"])();var __PyTime_GetMonotonicClockWithInfo=Module["__PyTime_GetMonotonicClockWithInfo"]=(a0,a1)=>(__PyTime_GetMonotonicClockWithInfo=Module["__PyTime_GetMonotonicClockWithInfo"]=wasmExports["_PyTime_GetMonotonicClockWithInfo"])(a0,a1);var __PyTime_GetPerfCounterWithInfo=Module["__PyTime_GetPerfCounterWithInfo"]=(a0,a1)=>(__PyTime_GetPerfCounterWithInfo=Module["__PyTime_GetPerfCounterWithInfo"]=wasmExports["_PyTime_GetPerfCounterWithInfo"])(a0,a1);var __PyTime_localtime=Module["__PyTime_localtime"]=(a0,a1)=>(__PyTime_localtime=Module["__PyTime_localtime"]=wasmExports["_PyTime_localtime"])(a0,a1);var _localtime_r=Module["_localtime_r"]=(a0,a1)=>(_localtime_r=Module["_localtime_r"]=wasmExports["localtime_r"])(a0,a1);var __PyTime_gmtime=Module["__PyTime_gmtime"]=(a0,a1)=>(__PyTime_gmtime=Module["__PyTime_gmtime"]=wasmExports["_PyTime_gmtime"])(a0,a1);var _gmtime_r=Module["_gmtime_r"]=(a0,a1)=>(_gmtime_r=Module["_gmtime_r"]=wasmExports["gmtime_r"])(a0,a1);var __PyDeadline_Init=Module["__PyDeadline_Init"]=a0=>(__PyDeadline_Init=Module["__PyDeadline_Init"]=wasmExports["_PyDeadline_Init"])(a0);var __PyDeadline_Get=Module["__PyDeadline_Get"]=a0=>(__PyDeadline_Get=Module["__PyDeadline_Get"]=wasmExports["_PyDeadline_Get"])(a0);var __PyOS_URandom=Module["__PyOS_URandom"]=(a0,a1)=>(__PyOS_URandom=Module["__PyOS_URandom"]=wasmExports["_PyOS_URandom"])(a0,a1);var __Py_open=Module["__Py_open"]=(a0,a1)=>(__Py_open=Module["__Py_open"]=wasmExports["_Py_open"])(a0,a1);var _close=Module["_close"]=a0=>(_close=Module["_close"]=wasmExports["close"])(a0);var __Py_fstat=Module["__Py_fstat"]=(a0,a1)=>(__Py_fstat=Module["__Py_fstat"]=wasmExports["_Py_fstat"])(a0,a1);var __Py_read=Module["__Py_read"]=(a0,a1,a2)=>(__Py_read=Module["__Py_read"]=wasmExports["_Py_read"])(a0,a1,a2);var __Py_open_noraise=Module["__Py_open_noraise"]=(a0,a1)=>(__Py_open_noraise=Module["__Py_open_noraise"]=wasmExports["_Py_open_noraise"])(a0,a1);var _read=Module["_read"]=(a0,a1,a2)=>(_read=Module["_read"]=wasmExports["read"])(a0,a1,a2);var __PyOS_URandomNonblock=Module["__PyOS_URandomNonblock"]=(a0,a1)=>(__PyOS_URandomNonblock=Module["__PyOS_URandomNonblock"]=wasmExports["_PyOS_URandomNonblock"])(a0,a1);var _PySys_AddAuditHook=Module["_PySys_AddAuditHook"]=(a0,a1)=>(_PySys_AddAuditHook=Module["_PySys_AddAuditHook"]=wasmExports["PySys_AddAuditHook"])(a0,a1);var __PySys_GetSizeOf=Module["__PySys_GetSizeOf"]=a0=>(__PySys_GetSizeOf=Module["__PySys_GetSizeOf"]=wasmExports["_PySys_GetSizeOf"])(a0);var _PyUnstable_PerfMapState_Init=Module["_PyUnstable_PerfMapState_Init"]=()=>(_PyUnstable_PerfMapState_Init=Module["_PyUnstable_PerfMapState_Init"]=wasmExports["PyUnstable_PerfMapState_Init"])();var _getpid=Module["_getpid"]=()=>(_getpid=Module["_getpid"]=wasmExports["getpid"])();var _open=Module["_open"]=(a0,a1,a2)=>(_open=Module["_open"]=wasmExports["open"])(a0,a1,a2);var _PyUnstable_WritePerfMapEntry=Module["_PyUnstable_WritePerfMapEntry"]=(a0,a1,a2)=>(_PyUnstable_WritePerfMapEntry=Module["_PyUnstable_WritePerfMapEntry"]=wasmExports["PyUnstable_WritePerfMapEntry"])(a0,a1,a2);var _PyUnstable_PerfMapState_Fini=Module["_PyUnstable_PerfMapState_Fini"]=()=>(_PyUnstable_PerfMapState_Fini=Module["_PyUnstable_PerfMapState_Fini"]=wasmExports["PyUnstable_PerfMapState_Fini"])();var _PySys_ResetWarnOptions=Module["_PySys_ResetWarnOptions"]=()=>(_PySys_ResetWarnOptions=Module["_PySys_ResetWarnOptions"]=wasmExports["PySys_ResetWarnOptions"])();var _PySys_AddWarnOptionUnicode=Module["_PySys_AddWarnOptionUnicode"]=a0=>(_PySys_AddWarnOptionUnicode=Module["_PySys_AddWarnOptionUnicode"]=wasmExports["PySys_AddWarnOptionUnicode"])(a0);var _PySys_AddWarnOption=Module["_PySys_AddWarnOption"]=a0=>(_PySys_AddWarnOption=Module["_PySys_AddWarnOption"]=wasmExports["PySys_AddWarnOption"])(a0);var _PySys_HasWarnOptions=Module["_PySys_HasWarnOptions"]=()=>(_PySys_HasWarnOptions=Module["_PySys_HasWarnOptions"]=wasmExports["PySys_HasWarnOptions"])();var _PySys_AddXOption=Module["_PySys_AddXOption"]=a0=>(_PySys_AddXOption=Module["_PySys_AddXOption"]=wasmExports["PySys_AddXOption"])(a0);var _PySys_GetXOptions=Module["_PySys_GetXOptions"]=()=>(_PySys_GetXOptions=Module["_PySys_GetXOptions"]=wasmExports["PySys_GetXOptions"])();var _PyThread_GetInfo=Module["_PyThread_GetInfo"]=()=>(_PyThread_GetInfo=Module["_PyThread_GetInfo"]=wasmExports["PyThread_GetInfo"])();var _PySys_SetPath=Module["_PySys_SetPath"]=a0=>(_PySys_SetPath=Module["_PySys_SetPath"]=wasmExports["PySys_SetPath"])(a0);var _PySys_SetArgvEx=Module["_PySys_SetArgvEx"]=(a0,a1,a2)=>(_PySys_SetArgvEx=Module["_PySys_SetArgvEx"]=wasmExports["PySys_SetArgvEx"])(a0,a1,a2);var _PySys_SetArgv=Module["_PySys_SetArgv"]=(a0,a1)=>(_PySys_SetArgv=Module["_PySys_SetArgv"]=wasmExports["PySys_SetArgv"])(a0,a1);var _PySys_WriteStdout=Module["_PySys_WriteStdout"]=(a0,a1)=>(_PySys_WriteStdout=Module["_PySys_WriteStdout"]=wasmExports["PySys_WriteStdout"])(a0,a1);var _PySys_FormatStdout=Module["_PySys_FormatStdout"]=(a0,a1)=>(_PySys_FormatStdout=Module["_PySys_FormatStdout"]=wasmExports["PySys_FormatStdout"])(a0,a1);var _pthread_condattr_init=Module["_pthread_condattr_init"]=a0=>(_pthread_condattr_init=Module["_pthread_condattr_init"]=wasmExports["pthread_condattr_init"])(a0);var _pthread_condattr_setclock=Module["_pthread_condattr_setclock"]=(a0,a1)=>(_pthread_condattr_setclock=Module["_pthread_condattr_setclock"]=wasmExports["pthread_condattr_setclock"])(a0,a1);var _pthread_cond_init=Module["_pthread_cond_init"]=(a0,a1)=>(_pthread_cond_init=Module["_pthread_cond_init"]=wasmExports["pthread_cond_init"])(a0,a1);var _PyThread_start_new_thread=Module["_PyThread_start_new_thread"]=(a0,a1)=>(_PyThread_start_new_thread=Module["_PyThread_start_new_thread"]=wasmExports["PyThread_start_new_thread"])(a0,a1);var _pthread_attr_init=Module["_pthread_attr_init"]=a0=>(_pthread_attr_init=Module["_pthread_attr_init"]=wasmExports["pthread_attr_init"])(a0);var _pthread_attr_setstacksize=Module["_pthread_attr_setstacksize"]=(a0,a1)=>(_pthread_attr_setstacksize=Module["_pthread_attr_setstacksize"]=wasmExports["pthread_attr_setstacksize"])(a0,a1);var _pthread_attr_destroy=Module["_pthread_attr_destroy"]=a0=>(_pthread_attr_destroy=Module["_pthread_attr_destroy"]=wasmExports["pthread_attr_destroy"])(a0);var _pthread_create=Module["_pthread_create"]=(a0,a1,a2,a3)=>(_pthread_create=Module["_pthread_create"]=wasmExports["pthread_create"])(a0,a1,a2,a3);var _pthread_detach=Module["_pthread_detach"]=a0=>(_pthread_detach=Module["_pthread_detach"]=wasmExports["pthread_detach"])(a0);var _pthread_self=Module["_pthread_self"]=()=>(_pthread_self=Module["_pthread_self"]=wasmExports["pthread_self"])();var _pthread_exit=Module["_pthread_exit"]=a0=>(_pthread_exit=Module["_pthread_exit"]=wasmExports["pthread_exit"])(a0);var _PyThread_acquire_lock_timed=Module["_PyThread_acquire_lock_timed"]=(a0,a1,a2)=>(_PyThread_acquire_lock_timed=Module["_PyThread_acquire_lock_timed"]=wasmExports["PyThread_acquire_lock_timed"])(a0,a1,a2);var _pthread_mutex_trylock=Module["_pthread_mutex_trylock"]=a0=>(_pthread_mutex_trylock=Module["_pthread_mutex_trylock"]=wasmExports["pthread_mutex_trylock"])(a0);var _PyThread_create_key=Module["_PyThread_create_key"]=()=>(_PyThread_create_key=Module["_PyThread_create_key"]=wasmExports["PyThread_create_key"])();var _pthread_key_create=Module["_pthread_key_create"]=(a0,a1)=>(_pthread_key_create=Module["_pthread_key_create"]=wasmExports["pthread_key_create"])(a0,a1);var _pthread_key_delete=Module["_pthread_key_delete"]=a0=>(_pthread_key_delete=Module["_pthread_key_delete"]=wasmExports["pthread_key_delete"])(a0);var _PyThread_delete_key=Module["_PyThread_delete_key"]=a0=>(_PyThread_delete_key=Module["_PyThread_delete_key"]=wasmExports["PyThread_delete_key"])(a0);var _PyThread_delete_key_value=Module["_PyThread_delete_key_value"]=a0=>(_PyThread_delete_key_value=Module["_PyThread_delete_key_value"]=wasmExports["PyThread_delete_key_value"])(a0);var _pthread_setspecific=Module["_pthread_setspecific"]=(a0,a1)=>(_pthread_setspecific=Module["_pthread_setspecific"]=wasmExports["pthread_setspecific"])(a0,a1);var _PyThread_set_key_value=Module["_PyThread_set_key_value"]=(a0,a1)=>(_PyThread_set_key_value=Module["_PyThread_set_key_value"]=wasmExports["PyThread_set_key_value"])(a0,a1);var _PyThread_get_key_value=Module["_PyThread_get_key_value"]=a0=>(_PyThread_get_key_value=Module["_PyThread_get_key_value"]=wasmExports["PyThread_get_key_value"])(a0);var _pthread_getspecific=Module["_pthread_getspecific"]=a0=>(_pthread_getspecific=Module["_pthread_getspecific"]=wasmExports["pthread_getspecific"])(a0);var _PyThread_ReInitTLS=Module["_PyThread_ReInitTLS"]=()=>(_PyThread_ReInitTLS=Module["_PyThread_ReInitTLS"]=wasmExports["PyThread_ReInitTLS"])();var _PyThread_get_stacksize=Module["_PyThread_get_stacksize"]=()=>(_PyThread_get_stacksize=Module["_PyThread_get_stacksize"]=wasmExports["PyThread_get_stacksize"])();var _PyThread_set_stacksize=Module["_PyThread_set_stacksize"]=a0=>(_PyThread_set_stacksize=Module["_PyThread_set_stacksize"]=wasmExports["PyThread_set_stacksize"])(a0);var _PyThread_tss_alloc=Module["_PyThread_tss_alloc"]=()=>(_PyThread_tss_alloc=Module["_PyThread_tss_alloc"]=wasmExports["PyThread_tss_alloc"])();var _PyThread_tss_free=Module["_PyThread_tss_free"]=a0=>(_PyThread_tss_free=Module["_PyThread_tss_free"]=wasmExports["PyThread_tss_free"])(a0);var _confstr=Module["_confstr"]=(a0,a1,a2)=>(_confstr=Module["_confstr"]=wasmExports["confstr"])(a0,a1,a2);var __PyTraceback_Add=Module["__PyTraceback_Add"]=(a0,a1,a2)=>(__PyTraceback_Add=Module["__PyTraceback_Add"]=wasmExports["_PyTraceback_Add"])(a0,a1,a2);var __PyTraceMalloc_Init=Module["__PyTraceMalloc_Init"]=()=>(__PyTraceMalloc_Init=Module["__PyTraceMalloc_Init"]=wasmExports["_PyTraceMalloc_Init"])();var __PyTraceMalloc_Stop=Module["__PyTraceMalloc_Stop"]=()=>(__PyTraceMalloc_Stop=Module["__PyTraceMalloc_Stop"]=wasmExports["_PyTraceMalloc_Stop"])();var _PyTraceMalloc_Track=Module["_PyTraceMalloc_Track"]=(a0,a1,a2)=>(_PyTraceMalloc_Track=Module["_PyTraceMalloc_Track"]=wasmExports["PyTraceMalloc_Track"])(a0,a1,a2);var _PyTraceMalloc_Untrack=Module["_PyTraceMalloc_Untrack"]=(a0,a1)=>(_PyTraceMalloc_Untrack=Module["_PyTraceMalloc_Untrack"]=wasmExports["PyTraceMalloc_Untrack"])(a0,a1);var __PyTraceMalloc_GetTraceback=Module["__PyTraceMalloc_GetTraceback"]=(a0,a1)=>(__PyTraceMalloc_GetTraceback=Module["__PyTraceMalloc_GetTraceback"]=wasmExports["_PyTraceMalloc_GetTraceback"])(a0,a1);var __PyTraceMalloc_IsTracing=Module["__PyTraceMalloc_IsTracing"]=()=>(__PyTraceMalloc_IsTracing=Module["__PyTraceMalloc_IsTracing"]=wasmExports["_PyTraceMalloc_IsTracing"])();var __PyTraceMalloc_ClearTraces=Module["__PyTraceMalloc_ClearTraces"]=()=>(__PyTraceMalloc_ClearTraces=Module["__PyTraceMalloc_ClearTraces"]=wasmExports["_PyTraceMalloc_ClearTraces"])();var __PyTraceMalloc_GetTraces=Module["__PyTraceMalloc_GetTraces"]=()=>(__PyTraceMalloc_GetTraces=Module["__PyTraceMalloc_GetTraces"]=wasmExports["_PyTraceMalloc_GetTraces"])();var __PyTraceMalloc_GetObjectTraceback=Module["__PyTraceMalloc_GetObjectTraceback"]=a0=>(__PyTraceMalloc_GetObjectTraceback=Module["__PyTraceMalloc_GetObjectTraceback"]=wasmExports["_PyTraceMalloc_GetObjectTraceback"])(a0);var __PyTraceMalloc_GetTracebackLimit=Module["__PyTraceMalloc_GetTracebackLimit"]=()=>(__PyTraceMalloc_GetTracebackLimit=Module["__PyTraceMalloc_GetTracebackLimit"]=wasmExports["_PyTraceMalloc_GetTracebackLimit"])();var __PyTraceMalloc_GetMemory=Module["__PyTraceMalloc_GetMemory"]=()=>(__PyTraceMalloc_GetMemory=Module["__PyTraceMalloc_GetMemory"]=wasmExports["_PyTraceMalloc_GetMemory"])();var __PyTraceMalloc_GetTracedMemory=Module["__PyTraceMalloc_GetTracedMemory"]=()=>(__PyTraceMalloc_GetTracedMemory=Module["__PyTraceMalloc_GetTracedMemory"]=wasmExports["_PyTraceMalloc_GetTracedMemory"])();var __PyTraceMalloc_ResetPeak=Module["__PyTraceMalloc_ResetPeak"]=()=>(__PyTraceMalloc_ResetPeak=Module["__PyTraceMalloc_ResetPeak"]=wasmExports["_PyTraceMalloc_ResetPeak"])();var _PyOS_mystricmp=Module["_PyOS_mystricmp"]=(a0,a1)=>(_PyOS_mystricmp=Module["_PyOS_mystricmp"]=wasmExports["PyOS_mystricmp"])(a0,a1);var __Py_strhex=Module["__Py_strhex"]=(a0,a1)=>(__Py_strhex=Module["__Py_strhex"]=wasmExports["_Py_strhex"])(a0,a1);var __Py_strhex_bytes=Module["__Py_strhex_bytes"]=(a0,a1)=>(__Py_strhex_bytes=Module["__Py_strhex_bytes"]=wasmExports["_Py_strhex_bytes"])(a0,a1);var __Py_strhex_bytes_with_sep=Module["__Py_strhex_bytes_with_sep"]=(a0,a1,a2,a3)=>(__Py_strhex_bytes_with_sep=Module["__Py_strhex_bytes_with_sep"]=wasmExports["_Py_strhex_bytes_with_sep"])(a0,a1,a2,a3);var _localeconv=Module["_localeconv"]=()=>(_localeconv=Module["_localeconv"]=wasmExports["localeconv"])();var __Py_GetLocaleconvNumeric=Module["__Py_GetLocaleconvNumeric"]=(a0,a1,a2)=>(__Py_GetLocaleconvNumeric=Module["__Py_GetLocaleconvNumeric"]=wasmExports["_Py_GetLocaleconvNumeric"])(a0,a1,a2);var __Py_device_encoding=Module["__Py_device_encoding"]=a0=>(__Py_device_encoding=Module["__Py_device_encoding"]=wasmExports["_Py_device_encoding"])(a0);var __Py_GetLocaleEncodingObject=Module["__Py_GetLocaleEncodingObject"]=()=>(__Py_GetLocaleEncodingObject=Module["__Py_GetLocaleEncodingObject"]=wasmExports["_Py_GetLocaleEncodingObject"])();var _mbstowcs=Module["_mbstowcs"]=(a0,a1,a2)=>(_mbstowcs=Module["_mbstowcs"]=wasmExports["mbstowcs"])(a0,a1,a2);var _mbrtowc=Module["_mbrtowc"]=(a0,a1,a2,a3)=>(_mbrtowc=Module["_mbrtowc"]=wasmExports["mbrtowc"])(a0,a1,a2,a3);var _Py_EncodeLocale=Module["_Py_EncodeLocale"]=(a0,a1)=>(_Py_EncodeLocale=Module["_Py_EncodeLocale"]=wasmExports["Py_EncodeLocale"])(a0,a1);var __Py_EncodeLocaleRaw=Module["__Py_EncodeLocaleRaw"]=(a0,a1)=>(__Py_EncodeLocaleRaw=Module["__Py_EncodeLocaleRaw"]=wasmExports["_Py_EncodeLocaleRaw"])(a0,a1);var _fstat=Module["_fstat"]=(a0,a1)=>(_fstat=Module["_fstat"]=wasmExports["fstat"])(a0,a1);var _stat=Module["_stat"]=(a0,a1)=>(_stat=Module["_stat"]=wasmExports["stat"])(a0,a1);var __Py_stat=Module["__Py_stat"]=(a0,a1)=>(__Py_stat=Module["__Py_stat"]=wasmExports["_Py_stat"])(a0,a1);var __Py_get_inheritable=Module["__Py_get_inheritable"]=a0=>(__Py_get_inheritable=Module["__Py_get_inheritable"]=wasmExports["_Py_get_inheritable"])(a0);var __Py_set_inheritable=Module["__Py_set_inheritable"]=(a0,a1,a2)=>(__Py_set_inheritable=Module["__Py_set_inheritable"]=wasmExports["_Py_set_inheritable"])(a0,a1,a2);var __Py_set_inheritable_async_safe=Module["__Py_set_inheritable_async_safe"]=(a0,a1,a2)=>(__Py_set_inheritable_async_safe=Module["__Py_set_inheritable_async_safe"]=wasmExports["_Py_set_inheritable_async_safe"])(a0,a1,a2);var __Py_wfopen=Module["__Py_wfopen"]=(a0,a1)=>(__Py_wfopen=Module["__Py_wfopen"]=wasmExports["_Py_wfopen"])(a0,a1);var _wcstombs=Module["_wcstombs"]=(a0,a1,a2)=>(_wcstombs=Module["_wcstombs"]=wasmExports["wcstombs"])(a0,a1,a2);var _fopen=Module["_fopen"]=(a0,a1)=>(_fopen=Module["_fopen"]=wasmExports["fopen"])(a0,a1);var _write=Module["_write"]=(a0,a1,a2)=>(_write=Module["_write"]=wasmExports["write"])(a0,a1,a2);var _readlink=Module["_readlink"]=(a0,a1,a2)=>(_readlink=Module["_readlink"]=wasmExports["readlink"])(a0,a1,a2);var _realpath=Module["_realpath"]=(a0,a1)=>(_realpath=Module["_realpath"]=wasmExports["realpath"])(a0,a1);var _getcwd=Module["_getcwd"]=(a0,a1)=>(_getcwd=Module["_getcwd"]=wasmExports["getcwd"])(a0,a1);var __Py_normpath=Module["__Py_normpath"]=(a0,a1)=>(__Py_normpath=Module["__Py_normpath"]=wasmExports["_Py_normpath"])(a0,a1);var __Py_get_blocking=Module["__Py_get_blocking"]=a0=>(__Py_get_blocking=Module["__Py_get_blocking"]=wasmExports["_Py_get_blocking"])(a0);var __Py_set_blocking=Module["__Py_set_blocking"]=(a0,a1)=>(__Py_set_blocking=Module["__Py_set_blocking"]=wasmExports["_Py_set_blocking"])(a0,a1);var __Py_closerange=Module["__Py_closerange"]=(a0,a1)=>(__Py_closerange=Module["__Py_closerange"]=wasmExports["_Py_closerange"])(a0,a1);var __Py_UTF8_Edit_Cost=Module["__Py_UTF8_Edit_Cost"]=(a0,a1,a2)=>(__Py_UTF8_Edit_Cost=Module["__Py_UTF8_Edit_Cost"]=wasmExports["_Py_UTF8_Edit_Cost"])(a0,a1,a2);var _dlopen=Module["_dlopen"]=(a0,a1)=>(_dlopen=Module["_dlopen"]=wasmExports["dlopen"])(a0,a1);var _dlerror=Module["_dlerror"]=()=>(_dlerror=Module["_dlerror"]=wasmExports["dlerror"])();var _dlsym=Module["_dlsym"]=(a0,a1)=>(_dlsym=Module["_dlsym"]=wasmExports["dlsym"])(a0,a1);var _PyErr_SetInterruptEx=Module["_PyErr_SetInterruptEx"]=a0=>(_PyErr_SetInterruptEx=Module["_PyErr_SetInterruptEx"]=wasmExports["PyErr_SetInterruptEx"])(a0);var _PyInit__ctypes=Module["_PyInit__ctypes"]=()=>(_PyInit__ctypes=Module["_PyInit__ctypes"]=wasmExports["PyInit__ctypes"])();var _PyInit__posixsubprocess=Module["_PyInit__posixsubprocess"]=()=>(_PyInit__posixsubprocess=Module["_PyInit__posixsubprocess"]=wasmExports["PyInit__posixsubprocess"])();var _PyInit__bz2=Module["_PyInit__bz2"]=()=>(_PyInit__bz2=Module["_PyInit__bz2"]=wasmExports["PyInit__bz2"])();var _PyInit_zlib=Module["_PyInit_zlib"]=()=>(_PyInit_zlib=Module["_PyInit_zlib"]=wasmExports["PyInit_zlib"])();var _PyInit__xxsubinterpreters=Module["_PyInit__xxsubinterpreters"]=()=>(_PyInit__xxsubinterpreters=Module["_PyInit__xxsubinterpreters"]=wasmExports["PyInit__xxsubinterpreters"])();var _PyInit_array=Module["_PyInit_array"]=()=>(_PyInit_array=Module["_PyInit_array"]=wasmExports["PyInit_array"])();var _PyInit__asyncio=Module["_PyInit__asyncio"]=()=>(_PyInit__asyncio=Module["_PyInit__asyncio"]=wasmExports["PyInit__asyncio"])();var _PyInit__bisect=Module["_PyInit__bisect"]=()=>(_PyInit__bisect=Module["_PyInit__bisect"]=wasmExports["PyInit__bisect"])();var _PyInit__contextvars=Module["_PyInit__contextvars"]=()=>(_PyInit__contextvars=Module["_PyInit__contextvars"]=wasmExports["PyInit__contextvars"])();var _PyInit__csv=Module["_PyInit__csv"]=()=>(_PyInit__csv=Module["_PyInit__csv"]=wasmExports["PyInit__csv"])();var _PyInit__heapq=Module["_PyInit__heapq"]=()=>(_PyInit__heapq=Module["_PyInit__heapq"]=wasmExports["PyInit__heapq"])();var _PyInit__json=Module["_PyInit__json"]=()=>(_PyInit__json=Module["_PyInit__json"]=wasmExports["PyInit__json"])();var _PyInit__lsprof=Module["_PyInit__lsprof"]=()=>(_PyInit__lsprof=Module["_PyInit__lsprof"]=wasmExports["PyInit__lsprof"])();var _PyInit__opcode=Module["_PyInit__opcode"]=()=>(_PyInit__opcode=Module["_PyInit__opcode"]=wasmExports["PyInit__opcode"])();var _PyInit__pickle=Module["_PyInit__pickle"]=()=>(_PyInit__pickle=Module["_PyInit__pickle"]=wasmExports["PyInit__pickle"])();var _PyInit__queue=Module["_PyInit__queue"]=()=>(_PyInit__queue=Module["_PyInit__queue"]=wasmExports["PyInit__queue"])();var _PyInit__random=Module["_PyInit__random"]=()=>(_PyInit__random=Module["_PyInit__random"]=wasmExports["PyInit__random"])();var _PyInit__struct=Module["_PyInit__struct"]=()=>(_PyInit__struct=Module["_PyInit__struct"]=wasmExports["PyInit__struct"])();var _PyInit__zoneinfo=Module["_PyInit__zoneinfo"]=()=>(_PyInit__zoneinfo=Module["_PyInit__zoneinfo"]=wasmExports["PyInit__zoneinfo"])();var _PyInit_audioop=Module["_PyInit_audioop"]=()=>(_PyInit_audioop=Module["_PyInit_audioop"]=wasmExports["PyInit_audioop"])();var _PyInit_math=Module["_PyInit_math"]=()=>(_PyInit_math=Module["_PyInit_math"]=wasmExports["PyInit_math"])();var _PyInit_cmath=Module["_PyInit_cmath"]=()=>(_PyInit_cmath=Module["_PyInit_cmath"]=wasmExports["PyInit_cmath"])();var _PyInit__statistics=Module["_PyInit__statistics"]=()=>(_PyInit__statistics=Module["_PyInit__statistics"]=wasmExports["PyInit__statistics"])();var _PyInit__datetime=Module["_PyInit__datetime"]=()=>(_PyInit__datetime=Module["_PyInit__datetime"]=wasmExports["PyInit__datetime"])();var _PyInit__decimal=Module["_PyInit__decimal"]=()=>(_PyInit__decimal=Module["_PyInit__decimal"]=wasmExports["PyInit__decimal"])();var _PyInit_binascii=Module["_PyInit_binascii"]=()=>(_PyInit_binascii=Module["_PyInit_binascii"]=wasmExports["PyInit_binascii"])();var _PyInit__md5=Module["_PyInit__md5"]=()=>(_PyInit__md5=Module["_PyInit__md5"]=wasmExports["PyInit__md5"])();var _PyInit__sha1=Module["_PyInit__sha1"]=()=>(_PyInit__sha1=Module["_PyInit__sha1"]=wasmExports["PyInit__sha1"])();var _PyInit__sha2=Module["_PyInit__sha2"]=()=>(_PyInit__sha2=Module["_PyInit__sha2"]=wasmExports["PyInit__sha2"])();var _PyInit__sha3=Module["_PyInit__sha3"]=()=>(_PyInit__sha3=Module["_PyInit__sha3"]=wasmExports["PyInit__sha3"])();var _PyInit__blake2=Module["_PyInit__blake2"]=()=>(_PyInit__blake2=Module["_PyInit__blake2"]=wasmExports["PyInit__blake2"])();var _PyInit_pyexpat=Module["_PyInit_pyexpat"]=()=>(_PyInit_pyexpat=Module["_PyInit_pyexpat"]=wasmExports["PyInit_pyexpat"])();var _PyInit__elementtree=Module["_PyInit__elementtree"]=()=>(_PyInit__elementtree=Module["_PyInit__elementtree"]=wasmExports["PyInit__elementtree"])();var _PyInit__codecs_cn=Module["_PyInit__codecs_cn"]=()=>(_PyInit__codecs_cn=Module["_PyInit__codecs_cn"]=wasmExports["PyInit__codecs_cn"])();var _PyInit__codecs_hk=Module["_PyInit__codecs_hk"]=()=>(_PyInit__codecs_hk=Module["_PyInit__codecs_hk"]=wasmExports["PyInit__codecs_hk"])();var _PyInit__codecs_iso2022=Module["_PyInit__codecs_iso2022"]=()=>(_PyInit__codecs_iso2022=Module["_PyInit__codecs_iso2022"]=wasmExports["PyInit__codecs_iso2022"])();var _PyInit__codecs_jp=Module["_PyInit__codecs_jp"]=()=>(_PyInit__codecs_jp=Module["_PyInit__codecs_jp"]=wasmExports["PyInit__codecs_jp"])();var _PyInit__codecs_kr=Module["_PyInit__codecs_kr"]=()=>(_PyInit__codecs_kr=Module["_PyInit__codecs_kr"]=wasmExports["PyInit__codecs_kr"])();var _PyInit__codecs_tw=Module["_PyInit__codecs_tw"]=()=>(_PyInit__codecs_tw=Module["_PyInit__codecs_tw"]=wasmExports["PyInit__codecs_tw"])();var _PyInit__multibytecodec=Module["_PyInit__multibytecodec"]=()=>(_PyInit__multibytecodec=Module["_PyInit__multibytecodec"]=wasmExports["PyInit__multibytecodec"])();var _PyInit_unicodedata=Module["_PyInit_unicodedata"]=()=>(_PyInit_unicodedata=Module["_PyInit_unicodedata"]=wasmExports["PyInit_unicodedata"])();var _PyInit__crypt=Module["_PyInit__crypt"]=()=>(_PyInit__crypt=Module["_PyInit__crypt"]=wasmExports["PyInit__crypt"])();var _PyInit_mmap=Module["_PyInit_mmap"]=()=>(_PyInit_mmap=Module["_PyInit_mmap"]=wasmExports["PyInit_mmap"])();var _PyInit_select=Module["_PyInit_select"]=()=>(_PyInit_select=Module["_PyInit_select"]=wasmExports["PyInit_select"])();var _PyInit__socket=Module["_PyInit__socket"]=()=>(_PyInit__socket=Module["_PyInit__socket"]=wasmExports["PyInit__socket"])();var _PyInit_atexit=Module["_PyInit_atexit"]=()=>(_PyInit_atexit=Module["_PyInit_atexit"]=wasmExports["PyInit_atexit"])();var _PyInit_faulthandler=Module["_PyInit_faulthandler"]=()=>(_PyInit_faulthandler=Module["_PyInit_faulthandler"]=wasmExports["PyInit_faulthandler"])();var _PyInit_posix=Module["_PyInit_posix"]=()=>(_PyInit_posix=Module["_PyInit_posix"]=wasmExports["PyInit_posix"])();var _PyInit__signal=Module["_PyInit__signal"]=()=>(_PyInit__signal=Module["_PyInit__signal"]=wasmExports["PyInit__signal"])();var _PyInit__tracemalloc=Module["_PyInit__tracemalloc"]=()=>(_PyInit__tracemalloc=Module["_PyInit__tracemalloc"]=wasmExports["PyInit__tracemalloc"])();var _PyInit__codecs=Module["_PyInit__codecs"]=()=>(_PyInit__codecs=Module["_PyInit__codecs"]=wasmExports["PyInit__codecs"])();var _PyInit__collections=Module["_PyInit__collections"]=()=>(_PyInit__collections=Module["_PyInit__collections"]=wasmExports["PyInit__collections"])();var _PyInit_errno=Module["_PyInit_errno"]=()=>(_PyInit_errno=Module["_PyInit_errno"]=wasmExports["PyInit_errno"])();var _PyInit__io=Module["_PyInit__io"]=()=>(_PyInit__io=Module["_PyInit__io"]=wasmExports["PyInit__io"])();var _PyInit_itertools=Module["_PyInit_itertools"]=()=>(_PyInit_itertools=Module["_PyInit_itertools"]=wasmExports["PyInit_itertools"])();var _PyInit__sre=Module["_PyInit__sre"]=()=>(_PyInit__sre=Module["_PyInit__sre"]=wasmExports["PyInit__sre"])();var _PyInit__thread=Module["_PyInit__thread"]=()=>(_PyInit__thread=Module["_PyInit__thread"]=wasmExports["PyInit__thread"])();var _PyInit_time=Module["_PyInit_time"]=()=>(_PyInit_time=Module["_PyInit_time"]=wasmExports["PyInit_time"])();var _PyInit__typing=Module["_PyInit__typing"]=()=>(_PyInit__typing=Module["_PyInit__typing"]=wasmExports["PyInit__typing"])();var _PyInit__weakref=Module["_PyInit__weakref"]=()=>(_PyInit__weakref=Module["_PyInit__weakref"]=wasmExports["PyInit__weakref"])();var _PyInit__abc=Module["_PyInit__abc"]=()=>(_PyInit__abc=Module["_PyInit__abc"]=wasmExports["PyInit__abc"])();var _PyInit__functools=Module["_PyInit__functools"]=()=>(_PyInit__functools=Module["_PyInit__functools"]=wasmExports["PyInit__functools"])();var _PyInit__locale=Module["_PyInit__locale"]=()=>(_PyInit__locale=Module["_PyInit__locale"]=wasmExports["PyInit__locale"])();var _PyInit__operator=Module["_PyInit__operator"]=()=>(_PyInit__operator=Module["_PyInit__operator"]=wasmExports["PyInit__operator"])();var _PyInit__stat=Module["_PyInit__stat"]=()=>(_PyInit__stat=Module["_PyInit__stat"]=wasmExports["PyInit__stat"])();var _PyInit__symtable=Module["_PyInit__symtable"]=()=>(_PyInit__symtable=Module["_PyInit__symtable"]=wasmExports["PyInit__symtable"])();var _PyInit_gc=Module["_PyInit_gc"]=()=>(_PyInit_gc=Module["_PyInit_gc"]=wasmExports["PyInit_gc"])();var _Py_RunMain=Module["_Py_RunMain"]=()=>(_Py_RunMain=Module["_Py_RunMain"]=wasmExports["Py_RunMain"])();var _perror=Module["_perror"]=a0=>(_perror=Module["_perror"]=wasmExports["perror"])(a0);var _kill=Module["_kill"]=(a0,a1)=>(_kill=Module["_kill"]=wasmExports["kill"])(a0,a1);var _Py_Main=Module["_Py_Main"]=(a0,a1)=>(_Py_Main=Module["_Py_Main"]=wasmExports["Py_Main"])(a0,a1);var _Py_BytesMain=Module["_Py_BytesMain"]=(a0,a1)=>(_Py_BytesMain=Module["_Py_BytesMain"]=wasmExports["Py_BytesMain"])(a0,a1);var _PyGC_Enable=Module["_PyGC_Enable"]=()=>(_PyGC_Enable=Module["_PyGC_Enable"]=wasmExports["PyGC_Enable"])();var _PyGC_Disable=Module["_PyGC_Disable"]=()=>(_PyGC_Disable=Module["_PyGC_Disable"]=wasmExports["PyGC_Disable"])();var _PyGC_IsEnabled=Module["_PyGC_IsEnabled"]=()=>(_PyGC_IsEnabled=Module["_PyGC_IsEnabled"]=wasmExports["PyGC_IsEnabled"])();var _PyUnstable_Object_GC_NewWithExtraData=Module["_PyUnstable_Object_GC_NewWithExtraData"]=(a0,a1)=>(_PyUnstable_Object_GC_NewWithExtraData=Module["_PyUnstable_Object_GC_NewWithExtraData"]=wasmExports["PyUnstable_Object_GC_NewWithExtraData"])(a0,a1);var _PyObject_GC_IsTracked=Module["_PyObject_GC_IsTracked"]=a0=>(_PyObject_GC_IsTracked=Module["_PyObject_GC_IsTracked"]=wasmExports["PyObject_GC_IsTracked"])(a0);var _PyObject_GC_IsFinalized=Module["_PyObject_GC_IsFinalized"]=a0=>(_PyObject_GC_IsFinalized=Module["_PyObject_GC_IsFinalized"]=wasmExports["PyObject_GC_IsFinalized"])(a0);var _PyUnstable_GC_VisitObjects=Module["_PyUnstable_GC_VisitObjects"]=(a0,a1)=>(_PyUnstable_GC_VisitObjects=Module["_PyUnstable_GC_VisitObjects"]=wasmExports["PyUnstable_GC_VisitObjects"])(a0,a1);var _strcat=Module["_strcat"]=(a0,a1)=>(_strcat=Module["_strcat"]=wasmExports["strcat"])(a0,a1);var _ffi_closure_alloc=Module["_ffi_closure_alloc"]=(a0,a1)=>(_ffi_closure_alloc=Module["_ffi_closure_alloc"]=wasmExports["ffi_closure_alloc"])(a0,a1);var _ffi_prep_cif=Module["_ffi_prep_cif"]=(a0,a1,a2,a3,a4)=>(_ffi_prep_cif=Module["_ffi_prep_cif"]=wasmExports["ffi_prep_cif"])(a0,a1,a2,a3,a4);var _ffi_prep_closure_loc=Module["_ffi_prep_closure_loc"]=(a0,a1,a2,a3,a4)=>(_ffi_prep_closure_loc=Module["_ffi_prep_closure_loc"]=wasmExports["ffi_prep_closure_loc"])(a0,a1,a2,a3,a4);var _ffi_closure_free=Module["_ffi_closure_free"]=a0=>(_ffi_closure_free=Module["_ffi_closure_free"]=wasmExports["ffi_closure_free"])(a0);var _ffi_prep_cif_var=Module["_ffi_prep_cif_var"]=(a0,a1,a2,a3,a4,a5)=>(_ffi_prep_cif_var=Module["_ffi_prep_cif_var"]=wasmExports["ffi_prep_cif_var"])(a0,a1,a2,a3,a4,a5);var _ffi_call=Module["_ffi_call"]=(a0,a1,a2,a3)=>(_ffi_call=Module["_ffi_call"]=wasmExports["ffi_call"])(a0,a1,a2,a3);var _dlclose=Module["_dlclose"]=a0=>(_dlclose=Module["_dlclose"]=wasmExports["dlclose"])(a0);var ___extenddftf2=Module["___extenddftf2"]=(a0,a1)=>(___extenddftf2=Module["___extenddftf2"]=wasmExports["__extenddftf2"])(a0,a1);var ___trunctfdf2=Module["___trunctfdf2"]=(a0,a1)=>(___trunctfdf2=Module["___trunctfdf2"]=wasmExports["__trunctfdf2"])(a0,a1);var __Py_Gid_Converter=Module["__Py_Gid_Converter"]=(a0,a1)=>(__Py_Gid_Converter=Module["__Py_Gid_Converter"]=wasmExports["_Py_Gid_Converter"])(a0,a1);var __Py_Uid_Converter=Module["__Py_Uid_Converter"]=(a0,a1)=>(__Py_Uid_Converter=Module["__Py_Uid_Converter"]=wasmExports["_Py_Uid_Converter"])(a0,a1);var _PyOS_BeforeFork=Module["_PyOS_BeforeFork"]=()=>(_PyOS_BeforeFork=Module["_PyOS_BeforeFork"]=wasmExports["PyOS_BeforeFork"])();var _PyOS_AfterFork_Parent=Module["_PyOS_AfterFork_Parent"]=()=>(_PyOS_AfterFork_Parent=Module["_PyOS_AfterFork_Parent"]=wasmExports["PyOS_AfterFork_Parent"])();var _fork=Module["_fork"]=()=>(_fork=Module["_fork"]=wasmExports["fork"])();var _PyOS_AfterFork_Child=Module["_PyOS_AfterFork_Child"]=()=>(_PyOS_AfterFork_Child=Module["_PyOS_AfterFork_Child"]=wasmExports["PyOS_AfterFork_Child"])();var __exit=Module["__exit"]=a0=>(__exit=Module["__exit"]=wasmExports["_exit"])(a0);var _dup=Module["_dup"]=a0=>(_dup=Module["_dup"]=wasmExports["dup"])(a0);var _dup2=Module["_dup2"]=(a0,a1)=>(_dup2=Module["_dup2"]=wasmExports["dup2"])(a0,a1);var _chdir=Module["_chdir"]=a0=>(_chdir=Module["_chdir"]=wasmExports["chdir"])(a0);var _umask=Module["_umask"]=a0=>(_umask=Module["_umask"]=wasmExports["umask"])(a0);var __Py_RestoreSignals=Module["__Py_RestoreSignals"]=()=>(__Py_RestoreSignals=Module["__Py_RestoreSignals"]=wasmExports["_Py_RestoreSignals"])();var _setsid=Module["_setsid"]=()=>(_setsid=Module["_setsid"]=wasmExports["setsid"])();var _setpgid=Module["_setpgid"]=(a0,a1)=>(_setpgid=Module["_setpgid"]=wasmExports["setpgid"])(a0,a1);var _setregid=Module["_setregid"]=(a0,a1)=>(_setregid=Module["_setregid"]=wasmExports["setregid"])(a0,a1);var _setreuid=Module["_setreuid"]=(a0,a1)=>(_setreuid=Module["_setreuid"]=wasmExports["setreuid"])(a0,a1);var _execve=Module["_execve"]=(a0,a1,a2)=>(_execve=Module["_execve"]=wasmExports["execve"])(a0,a1,a2);var _execv=Module["_execv"]=(a0,a1)=>(_execv=Module["_execv"]=wasmExports["execv"])(a0,a1);var _opendir=Module["_opendir"]=a0=>(_opendir=Module["_opendir"]=wasmExports["opendir"])(a0);var _sysconf=Module["_sysconf"]=a0=>(_sysconf=Module["_sysconf"]=wasmExports["sysconf"])(a0);var _dirfd=Module["_dirfd"]=a0=>(_dirfd=Module["_dirfd"]=wasmExports["dirfd"])(a0);var _readdir=Module["_readdir"]=a0=>(_readdir=Module["_readdir"]=wasmExports["readdir"])(a0);var _closedir=Module["_closedir"]=a0=>(_closedir=Module["_closedir"]=wasmExports["closedir"])(a0);var _BZ2_bzCompressEnd=Module["_BZ2_bzCompressEnd"]=a0=>(_BZ2_bzCompressEnd=Module["_BZ2_bzCompressEnd"]=wasmExports["BZ2_bzCompressEnd"])(a0);var _BZ2_bzCompressInit=Module["_BZ2_bzCompressInit"]=(a0,a1,a2,a3)=>(_BZ2_bzCompressInit=Module["_BZ2_bzCompressInit"]=wasmExports["BZ2_bzCompressInit"])(a0,a1,a2,a3);var _BZ2_bzCompress=Module["_BZ2_bzCompress"]=(a0,a1)=>(_BZ2_bzCompress=Module["_BZ2_bzCompress"]=wasmExports["BZ2_bzCompress"])(a0,a1);var _BZ2_bzDecompressEnd=Module["_BZ2_bzDecompressEnd"]=a0=>(_BZ2_bzDecompressEnd=Module["_BZ2_bzDecompressEnd"]=wasmExports["BZ2_bzDecompressEnd"])(a0);var _BZ2_bzDecompressInit=Module["_BZ2_bzDecompressInit"]=(a0,a1,a2)=>(_BZ2_bzDecompressInit=Module["_BZ2_bzDecompressInit"]=wasmExports["BZ2_bzDecompressInit"])(a0,a1,a2);var _BZ2_bzDecompress=Module["_BZ2_bzDecompress"]=a0=>(_BZ2_bzDecompress=Module["_BZ2_bzDecompress"]=wasmExports["BZ2_bzDecompress"])(a0);var _adler32=Module["_adler32"]=(a0,a1,a2)=>(_adler32=Module["_adler32"]=wasmExports["adler32"])(a0,a1,a2);var _deflateInit2_=Module["_deflateInit2_"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(_deflateInit2_=Module["_deflateInit2_"]=wasmExports["deflateInit2_"])(a0,a1,a2,a3,a4,a5,a6,a7);var _deflateEnd=Module["_deflateEnd"]=a0=>(_deflateEnd=Module["_deflateEnd"]=wasmExports["deflateEnd"])(a0);var _deflate=Module["_deflate"]=(a0,a1)=>(_deflate=Module["_deflate"]=wasmExports["deflate"])(a0,a1);var _deflateSetDictionary=Module["_deflateSetDictionary"]=(a0,a1,a2)=>(_deflateSetDictionary=Module["_deflateSetDictionary"]=wasmExports["deflateSetDictionary"])(a0,a1,a2);var _crc32=Module["_crc32"]=(a0,a1,a2)=>(_crc32=Module["_crc32"]=wasmExports["crc32"])(a0,a1,a2);var _inflateInit2_=Module["_inflateInit2_"]=(a0,a1,a2,a3)=>(_inflateInit2_=Module["_inflateInit2_"]=wasmExports["inflateInit2_"])(a0,a1,a2,a3);var _inflateEnd=Module["_inflateEnd"]=a0=>(_inflateEnd=Module["_inflateEnd"]=wasmExports["inflateEnd"])(a0);var _inflate=Module["_inflate"]=(a0,a1)=>(_inflate=Module["_inflate"]=wasmExports["inflate"])(a0,a1);var _inflateSetDictionary=Module["_inflateSetDictionary"]=(a0,a1,a2)=>(_inflateSetDictionary=Module["_inflateSetDictionary"]=wasmExports["inflateSetDictionary"])(a0,a1,a2);var _zlibVersion=Module["_zlibVersion"]=()=>(_zlibVersion=Module["_zlibVersion"]=wasmExports["zlibVersion"])();var _deflateCopy=Module["_deflateCopy"]=(a0,a1)=>(_deflateCopy=Module["_deflateCopy"]=wasmExports["deflateCopy"])(a0,a1);var _inflateCopy=Module["_inflateCopy"]=(a0,a1)=>(_inflateCopy=Module["_inflateCopy"]=wasmExports["inflateCopy"])(a0,a1);var _acos=Module["_acos"]=a0=>(_acos=Module["_acos"]=wasmExports["acos"])(a0);var _acosh=Module["_acosh"]=a0=>(_acosh=Module["_acosh"]=wasmExports["acosh"])(a0);var _asin=Module["_asin"]=a0=>(_asin=Module["_asin"]=wasmExports["asin"])(a0);var _asinh=Module["_asinh"]=a0=>(_asinh=Module["_asinh"]=wasmExports["asinh"])(a0);var _atan=Module["_atan"]=a0=>(_atan=Module["_atan"]=wasmExports["atan"])(a0);var _atanh=Module["_atanh"]=a0=>(_atanh=Module["_atanh"]=wasmExports["atanh"])(a0);var _cbrt=Module["_cbrt"]=a0=>(_cbrt=Module["_cbrt"]=wasmExports["cbrt"])(a0);var _copysign=Module["_copysign"]=(a0,a1)=>(_copysign=Module["_copysign"]=wasmExports["copysign"])(a0,a1);var _cosh=Module["_cosh"]=a0=>(_cosh=Module["_cosh"]=wasmExports["cosh"])(a0);var _erf=Module["_erf"]=a0=>(_erf=Module["_erf"]=wasmExports["erf"])(a0);var _erfc=Module["_erfc"]=a0=>(_erfc=Module["_erfc"]=wasmExports["erfc"])(a0);var _exp2=Module["_exp2"]=a0=>(_exp2=Module["_exp2"]=wasmExports["exp2"])(a0);var _expm1=Module["_expm1"]=a0=>(_expm1=Module["_expm1"]=wasmExports["expm1"])(a0);var _fabs=Module["_fabs"]=a0=>(_fabs=Module["_fabs"]=wasmExports["fabs"])(a0);var _sinh=Module["_sinh"]=a0=>(_sinh=Module["_sinh"]=wasmExports["sinh"])(a0);var _sqrt=Module["_sqrt"]=a0=>(_sqrt=Module["_sqrt"]=wasmExports["sqrt"])(a0);var _tan=Module["_tan"]=a0=>(_tan=Module["_tan"]=wasmExports["tan"])(a0);var _tanh=Module["_tanh"]=a0=>(_tanh=Module["_tanh"]=wasmExports["tanh"])(a0);var _fma=Module["_fma"]=(a0,a1,a2)=>(_fma=Module["_fma"]=wasmExports["fma"])(a0,a1,a2);var _nextafter=Module["_nextafter"]=(a0,a1)=>(_nextafter=Module["_nextafter"]=wasmExports["nextafter"])(a0,a1);var _log1p=Module["_log1p"]=a0=>(_log1p=Module["_log1p"]=wasmExports["log1p"])(a0);var _log10=Module["_log10"]=a0=>(_log10=Module["_log10"]=wasmExports["log10"])(a0);var _log2=Module["_log2"]=a0=>(_log2=Module["_log2"]=wasmExports["log2"])(a0);var _explicit_bzero=Module["_explicit_bzero"]=(a0,a1)=>(_explicit_bzero=Module["_explicit_bzero"]=wasmExports["explicit_bzero"])(a0,a1);var _strncat=Module["_strncat"]=(a0,a1,a2)=>(_strncat=Module["_strncat"]=wasmExports["strncat"])(a0,a1,a2);var _crypt_r=Module["_crypt_r"]=(a0,a1,a2)=>(_crypt_r=Module["_crypt_r"]=wasmExports["crypt_r"])(a0,a1,a2);var _mmap=Module["_mmap"]=(a0,a1,a2,a3,a4,a5)=>(_mmap=Module["_mmap"]=wasmExports["mmap"])(a0,a1,a2,a3,a4,a5);var _munmap=Module["_munmap"]=(a0,a1)=>(_munmap=Module["_munmap"]=wasmExports["munmap"])(a0,a1);var _msync=Module["_msync"]=(a0,a1,a2)=>(_msync=Module["_msync"]=wasmExports["msync"])(a0,a1,a2);var _madvise=Module["_madvise"]=(a0,a1,a2)=>(_madvise=Module["_madvise"]=wasmExports["madvise"])(a0,a1,a2);var _ftruncate=Module["_ftruncate"]=(a0,a1)=>(_ftruncate=Module["_ftruncate"]=wasmExports["ftruncate"])(a0,a1);var _mremap=Module["_mremap"]=(a0,a1,a2,a3,a4)=>(_mremap=Module["_mremap"]=wasmExports["mremap"])(a0,a1,a2,a3,a4);var _poll=Module["_poll"]=(a0,a1,a2)=>(_poll=Module["_poll"]=wasmExports["poll"])(a0,a1,a2);var _select=Module["_select"]=(a0,a1,a2,a3,a4)=>(_select=Module["_select"]=wasmExports["select"])(a0,a1,a2,a3,a4);var _inet_ntop=Module["_inet_ntop"]=(a0,a1,a2,a3)=>(_inet_ntop=Module["_inet_ntop"]=wasmExports["inet_ntop"])(a0,a1,a2,a3);var _gethostbyname=Module["_gethostbyname"]=a0=>(_gethostbyname=Module["_gethostbyname"]=wasmExports["gethostbyname"])(a0);var _gethostbyaddr=Module["_gethostbyaddr"]=(a0,a1,a2)=>(_gethostbyaddr=Module["_gethostbyaddr"]=wasmExports["gethostbyaddr"])(a0,a1,a2);var _gethostname=Module["_gethostname"]=(a0,a1)=>(_gethostname=Module["_gethostname"]=wasmExports["gethostname"])(a0,a1);var _getservbyname=Module["_getservbyname"]=(a0,a1)=>(_getservbyname=Module["_getservbyname"]=wasmExports["getservbyname"])(a0,a1);var _ntohs=a0=>(_ntohs=wasmExports["ntohs"])(a0);var _htons=a0=>(_htons=wasmExports["htons"])(a0);var _getservbyport=Module["_getservbyport"]=(a0,a1)=>(_getservbyport=Module["_getservbyport"]=wasmExports["getservbyport"])(a0,a1);var _ntohl=Module["_ntohl"]=a0=>(_ntohl=Module["_ntohl"]=wasmExports["ntohl"])(a0);var _htonl=a0=>(_htonl=wasmExports["htonl"])(a0);var _inet_aton=Module["_inet_aton"]=(a0,a1)=>(_inet_aton=Module["_inet_aton"]=wasmExports["inet_aton"])(a0,a1);var _inet_ntoa=Module["_inet_ntoa"]=a0=>(_inet_ntoa=Module["_inet_ntoa"]=wasmExports["inet_ntoa"])(a0);var _inet_pton=Module["_inet_pton"]=(a0,a1,a2)=>(_inet_pton=Module["_inet_pton"]=wasmExports["inet_pton"])(a0,a1,a2);var _gai_strerror=Module["_gai_strerror"]=a0=>(_gai_strerror=Module["_gai_strerror"]=wasmExports["gai_strerror"])(a0);var _freeaddrinfo=Module["_freeaddrinfo"]=a0=>(_freeaddrinfo=Module["_freeaddrinfo"]=wasmExports["freeaddrinfo"])(a0);var _if_nameindex=Module["_if_nameindex"]=()=>(_if_nameindex=Module["_if_nameindex"]=wasmExports["if_nameindex"])();var _if_freenameindex=Module["_if_freenameindex"]=a0=>(_if_freenameindex=Module["_if_freenameindex"]=wasmExports["if_freenameindex"])(a0);var _if_nametoindex=Module["_if_nametoindex"]=a0=>(_if_nametoindex=Module["_if_nametoindex"]=wasmExports["if_nametoindex"])(a0);var _if_indextoname=Module["_if_indextoname"]=(a0,a1)=>(_if_indextoname=Module["_if_indextoname"]=wasmExports["if_indextoname"])(a0,a1);var ___h_errno_location=Module["___h_errno_location"]=()=>(___h_errno_location=Module["___h_errno_location"]=wasmExports["__h_errno_location"])();var _hstrerror=Module["_hstrerror"]=a0=>(_hstrerror=Module["_hstrerror"]=wasmExports["hstrerror"])(a0);var _getsockname=Module["_getsockname"]=(a0,a1,a2)=>(_getsockname=Module["_getsockname"]=wasmExports["getsockname"])(a0,a1,a2);var _socket=Module["_socket"]=(a0,a1,a2)=>(_socket=Module["_socket"]=wasmExports["socket"])(a0,a1,a2);var _getsockopt=Module["_getsockopt"]=(a0,a1,a2,a3,a4)=>(_getsockopt=Module["_getsockopt"]=wasmExports["getsockopt"])(a0,a1,a2,a3,a4);var _bind=Module["_bind"]=(a0,a1,a2)=>(_bind=Module["_bind"]=wasmExports["bind"])(a0,a1,a2);var _getpeername=Module["_getpeername"]=(a0,a1,a2)=>(_getpeername=Module["_getpeername"]=wasmExports["getpeername"])(a0,a1,a2);var _listen=Module["_listen"]=(a0,a1)=>(_listen=Module["_listen"]=wasmExports["listen"])(a0,a1);var _setsockopt=Module["_setsockopt"]=(a0,a1,a2,a3,a4)=>(_setsockopt=Module["_setsockopt"]=wasmExports["setsockopt"])(a0,a1,a2,a3,a4);var _accept4=Module["_accept4"]=(a0,a1,a2,a3)=>(_accept4=Module["_accept4"]=wasmExports["accept4"])(a0,a1,a2,a3);var _accept=Module["_accept"]=(a0,a1,a2)=>(_accept=Module["_accept"]=wasmExports["accept"])(a0,a1,a2);var _connect=Module["_connect"]=(a0,a1,a2)=>(_connect=Module["_connect"]=wasmExports["connect"])(a0,a1,a2);var _recv=Module["_recv"]=(a0,a1,a2,a3)=>(_recv=Module["_recv"]=wasmExports["recv"])(a0,a1,a2,a3);var _recvfrom=Module["_recvfrom"]=(a0,a1,a2,a3,a4,a5)=>(_recvfrom=Module["_recvfrom"]=wasmExports["recvfrom"])(a0,a1,a2,a3,a4,a5);var _send=Module["_send"]=(a0,a1,a2,a3)=>(_send=Module["_send"]=wasmExports["send"])(a0,a1,a2,a3);var _sendto=Module["_sendto"]=(a0,a1,a2,a3,a4,a5)=>(_sendto=Module["_sendto"]=wasmExports["sendto"])(a0,a1,a2,a3,a4,a5);var _recvmsg=Module["_recvmsg"]=(a0,a1,a2)=>(_recvmsg=Module["_recvmsg"]=wasmExports["recvmsg"])(a0,a1,a2);var _sendmsg=Module["_sendmsg"]=(a0,a1,a2)=>(_sendmsg=Module["_sendmsg"]=wasmExports["sendmsg"])(a0,a1,a2);var __Py_AtExit=Module["__Py_AtExit"]=(a0,a1,a2)=>(__Py_AtExit=Module["__Py_AtExit"]=wasmExports["_Py_AtExit"])(a0,a1,a2);var _getrlimit=Module["_getrlimit"]=(a0,a1)=>(_getrlimit=Module["_getrlimit"]=wasmExports["getrlimit"])(a0,a1);var _setrlimit=Module["_setrlimit"]=(a0,a1)=>(_setrlimit=Module["_setrlimit"]=wasmExports["setrlimit"])(a0,a1);var _raise=Module["_raise"]=a0=>(_raise=Module["_raise"]=wasmExports["raise"])(a0);var _sigfillset=Module["_sigfillset"]=a0=>(_sigfillset=Module["_sigfillset"]=wasmExports["sigfillset"])(a0);var _pthread_sigmask=Module["_pthread_sigmask"]=(a0,a1,a2)=>(_pthread_sigmask=Module["_pthread_sigmask"]=wasmExports["pthread_sigmask"])(a0,a1,a2);var _PyOS_AfterFork=Module["_PyOS_AfterFork"]=()=>(_PyOS_AfterFork=Module["_PyOS_AfterFork"]=wasmExports["PyOS_AfterFork"])();var __PyLong_FromUid=Module["__PyLong_FromUid"]=a0=>(__PyLong_FromUid=Module["__PyLong_FromUid"]=wasmExports["_PyLong_FromUid"])(a0);var __PyLong_FromGid=Module["__PyLong_FromGid"]=a0=>(__PyLong_FromGid=Module["__PyLong_FromGid"]=wasmExports["_PyLong_FromGid"])(a0);var __Py_Sigset_Converter=Module["__Py_Sigset_Converter"]=(a0,a1)=>(__Py_Sigset_Converter=Module["__Py_Sigset_Converter"]=wasmExports["_Py_Sigset_Converter"])(a0,a1);var _sigemptyset=Module["_sigemptyset"]=a0=>(_sigemptyset=Module["_sigemptyset"]=wasmExports["sigemptyset"])(a0);var _sigaddset=Module["_sigaddset"]=(a0,a1)=>(_sigaddset=Module["_sigaddset"]=wasmExports["sigaddset"])(a0,a1);var _access=Module["_access"]=(a0,a1)=>(_access=Module["_access"]=wasmExports["access"])(a0,a1);var _ttyname_r=Module["_ttyname_r"]=(a0,a1,a2)=>(_ttyname_r=Module["_ttyname_r"]=wasmExports["ttyname_r"])(a0,a1,a2);var _fchdir=Module["_fchdir"]=a0=>(_fchdir=Module["_fchdir"]=wasmExports["fchdir"])(a0);var _fchmod=Module["_fchmod"]=(a0,a1)=>(_fchmod=Module["_fchmod"]=wasmExports["fchmod"])(a0,a1);var _fchmodat=Module["_fchmodat"]=(a0,a1,a2,a3)=>(_fchmodat=Module["_fchmodat"]=wasmExports["fchmodat"])(a0,a1,a2,a3);var _chmod=Module["_chmod"]=(a0,a1)=>(_chmod=Module["_chmod"]=wasmExports["chmod"])(a0,a1);var _fchown=Module["_fchown"]=(a0,a1,a2)=>(_fchown=Module["_fchown"]=wasmExports["fchown"])(a0,a1,a2);var _fchownat=Module["_fchownat"]=(a0,a1,a2,a3,a4)=>(_fchownat=Module["_fchownat"]=wasmExports["fchownat"])(a0,a1,a2,a3,a4);var _chown=Module["_chown"]=(a0,a1,a2)=>(_chown=Module["_chown"]=wasmExports["chown"])(a0,a1,a2);var _chroot=Module["_chroot"]=a0=>(_chroot=Module["_chroot"]=wasmExports["chroot"])(a0);var _ctermid=Module["_ctermid"]=a0=>(_ctermid=Module["_ctermid"]=wasmExports["ctermid"])(a0);var _fdopendir=Module["_fdopendir"]=a0=>(_fdopendir=Module["_fdopendir"]=wasmExports["fdopendir"])(a0);var _rewinddir=Module["_rewinddir"]=a0=>(_rewinddir=Module["_rewinddir"]=wasmExports["rewinddir"])(a0);var _mkdirat=Module["_mkdirat"]=(a0,a1,a2)=>(_mkdirat=Module["_mkdirat"]=wasmExports["mkdirat"])(a0,a1,a2);var _mkdir=Module["_mkdir"]=(a0,a1)=>(_mkdir=Module["_mkdir"]=wasmExports["mkdir"])(a0,a1);var _getpriority=Module["_getpriority"]=(a0,a1)=>(_getpriority=Module["_getpriority"]=wasmExports["getpriority"])(a0,a1);var _readlinkat=Module["_readlinkat"]=(a0,a1,a2,a3)=>(_readlinkat=Module["_readlinkat"]=wasmExports["readlinkat"])(a0,a1,a2,a3);var _unlinkat=Module["_unlinkat"]=(a0,a1,a2)=>(_unlinkat=Module["_unlinkat"]=wasmExports["unlinkat"])(a0,a1,a2);var _rmdir=Module["_rmdir"]=a0=>(_rmdir=Module["_rmdir"]=wasmExports["rmdir"])(a0);var _symlink=Module["_symlink"]=(a0,a1)=>(_symlink=Module["_symlink"]=wasmExports["symlink"])(a0,a1);var _system=Module["_system"]=a0=>(_system=Module["_system"]=wasmExports["system"])(a0);var _uname=Module["_uname"]=a0=>(_uname=Module["_uname"]=wasmExports["uname"])(a0);var _futimesat=Module["_futimesat"]=(a0,a1,a2)=>(_futimesat=Module["_futimesat"]=wasmExports["futimesat"])(a0,a1,a2);var _futimens=Module["_futimens"]=(a0,a1)=>(_futimens=Module["_futimens"]=wasmExports["futimens"])(a0,a1);var _times=Module["_times"]=a0=>(_times=Module["_times"]=wasmExports["times"])(a0);var _fexecve=Module["_fexecve"]=(a0,a1,a2)=>(_fexecve=Module["_fexecve"]=wasmExports["fexecve"])(a0,a1,a2);var _sched_yield=Module["_sched_yield"]=()=>(_sched_yield=Module["_sched_yield"]=wasmExports["sched_yield"])();var _login_tty=Module["_login_tty"]=a0=>(_login_tty=Module["_login_tty"]=wasmExports["login_tty"])(a0);var _getgid=Module["_getgid"]=()=>(_getgid=Module["_getgid"]=wasmExports["getgid"])();var _getpgrp=Module["_getpgrp"]=()=>(_getpgrp=Module["_getpgrp"]=wasmExports["getpgrp"])();var _getppid=Module["_getppid"]=()=>(_getppid=Module["_getppid"]=wasmExports["getppid"])();var _getuid=Module["_getuid"]=()=>(_getuid=Module["_getuid"]=wasmExports["getuid"])();var _getlogin=Module["_getlogin"]=()=>(_getlogin=Module["_getlogin"]=wasmExports["getlogin"])();var _killpg=Module["_killpg"]=(a0,a1)=>(_killpg=Module["_killpg"]=wasmExports["killpg"])(a0,a1);var _setuid=Module["_setuid"]=a0=>(_setuid=Module["_setuid"]=wasmExports["setuid"])(a0);var _setgid=Module["_setgid"]=a0=>(_setgid=Module["_setgid"]=wasmExports["setgid"])(a0);var _getpgid=Module["_getpgid"]=a0=>(_getpgid=Module["_getpgid"]=wasmExports["getpgid"])(a0);var _setpgrp=Module["_setpgrp"]=()=>(_setpgrp=Module["_setpgrp"]=wasmExports["setpgrp"])();var _wait=Module["_wait"]=a0=>(_wait=Module["_wait"]=wasmExports["wait"])(a0);var _waitid=Module["_waitid"]=(a0,a1,a2,a3)=>(_waitid=Module["_waitid"]=wasmExports["waitid"])(a0,a1,a2,a3);var _waitpid=Module["_waitpid"]=(a0,a1,a2)=>(_waitpid=Module["_waitpid"]=wasmExports["waitpid"])(a0,a1,a2);var _getsid=Module["_getsid"]=a0=>(_getsid=Module["_getsid"]=wasmExports["getsid"])(a0);var _tcgetpgrp=Module["_tcgetpgrp"]=a0=>(_tcgetpgrp=Module["_tcgetpgrp"]=wasmExports["tcgetpgrp"])(a0);var _tcsetpgrp=Module["_tcsetpgrp"]=(a0,a1)=>(_tcsetpgrp=Module["_tcsetpgrp"]=wasmExports["tcsetpgrp"])(a0,a1);var _openat=Module["_openat"]=(a0,a1,a2,a3)=>(_openat=Module["_openat"]=wasmExports["openat"])(a0,a1,a2,a3);var _dup3=Module["_dup3"]=(a0,a1,a2)=>(_dup3=Module["_dup3"]=wasmExports["dup3"])(a0,a1,a2);var _lockf=Module["_lockf"]=(a0,a1,a2)=>(_lockf=Module["_lockf"]=wasmExports["lockf"])(a0,a1,a2);var _readv=Module["_readv"]=(a0,a1,a2)=>(_readv=Module["_readv"]=wasmExports["readv"])(a0,a1,a2);var _pread=Module["_pread"]=(a0,a1,a2,a3)=>(_pread=Module["_pread"]=wasmExports["pread"])(a0,a1,a2,a3);var _writev=Module["_writev"]=(a0,a1,a2)=>(_writev=Module["_writev"]=wasmExports["writev"])(a0,a1,a2);var _pwrite=Module["_pwrite"]=(a0,a1,a2,a3)=>(_pwrite=Module["_pwrite"]=wasmExports["pwrite"])(a0,a1,a2,a3);var _pipe=Module["_pipe"]=a0=>(_pipe=Module["_pipe"]=wasmExports["pipe"])(a0);var _truncate=Module["_truncate"]=(a0,a1)=>(_truncate=Module["_truncate"]=wasmExports["truncate"])(a0,a1);var _posix_fadvise=Module["_posix_fadvise"]=(a0,a1,a2,a3)=>(_posix_fadvise=Module["_posix_fadvise"]=wasmExports["posix_fadvise"])(a0,a1,a2,a3);var _unsetenv=Module["_unsetenv"]=a0=>(_unsetenv=Module["_unsetenv"]=wasmExports["unsetenv"])(a0);var _fsync=Module["_fsync"]=a0=>(_fsync=Module["_fsync"]=wasmExports["fsync"])(a0);var _sync=Module["_sync"]=()=>(_sync=Module["_sync"]=wasmExports["sync"])();var _fdatasync=Module["_fdatasync"]=a0=>(_fdatasync=Module["_fdatasync"]=wasmExports["fdatasync"])(a0);var _fstatvfs=Module["_fstatvfs"]=(a0,a1)=>(_fstatvfs=Module["_fstatvfs"]=wasmExports["fstatvfs"])(a0,a1);var _statvfs=Module["_statvfs"]=(a0,a1)=>(_statvfs=Module["_statvfs"]=wasmExports["statvfs"])(a0,a1);var _fpathconf=Module["_fpathconf"]=(a0,a1)=>(_fpathconf=Module["_fpathconf"]=wasmExports["fpathconf"])(a0,a1);var _pathconf=Module["_pathconf"]=(a0,a1)=>(_pathconf=Module["_pathconf"]=wasmExports["pathconf"])(a0,a1);var _getloadavg=Module["_getloadavg"]=(a0,a1)=>(_getloadavg=Module["_getloadavg"]=wasmExports["getloadavg"])(a0,a1);var _lstat=Module["_lstat"]=(a0,a1)=>(_lstat=Module["_lstat"]=wasmExports["lstat"])(a0,a1);var _fstatat=Module["_fstatat"]=(a0,a1,a2,a3)=>(_fstatat=Module["_fstatat"]=wasmExports["fstatat"])(a0,a1,a2,a3);var _renameat=Module["_renameat"]=(a0,a1,a2,a3)=>(_renameat=Module["_renameat"]=wasmExports["renameat"])(a0,a1,a2,a3);var _rename=Module["_rename"]=(a0,a1)=>(_rename=Module["_rename"]=wasmExports["rename"])(a0,a1);var _unlink=Module["_unlink"]=a0=>(_unlink=Module["_unlink"]=wasmExports["unlink"])(a0);var _utimes=Module["_utimes"]=(a0,a1)=>(_utimes=Module["_utimes"]=wasmExports["utimes"])(a0,a1);var _qsort=Module["_qsort"]=(a0,a1,a2,a3)=>(_qsort=Module["_qsort"]=wasmExports["qsort"])(a0,a1,a2,a3);var __PyErr_CheckSignals=Module["__PyErr_CheckSignals"]=()=>(__PyErr_CheckSignals=Module["__PyErr_CheckSignals"]=wasmExports["_PyErr_CheckSignals"])();var _PyErr_SetInterrupt=Module["_PyErr_SetInterrupt"]=()=>(_PyErr_SetInterrupt=Module["_PyErr_SetInterrupt"]=wasmExports["PyErr_SetInterrupt"])();var _PyOS_InterruptOccurred=Module["_PyOS_InterruptOccurred"]=()=>(_PyOS_InterruptOccurred=Module["_PyOS_InterruptOccurred"]=wasmExports["PyOS_InterruptOccurred"])();var __PyOS_IsMainThread=Module["__PyOS_IsMainThread"]=()=>(__PyOS_IsMainThread=Module["__PyOS_IsMainThread"]=wasmExports["_PyOS_IsMainThread"])();var _getitimer=Module["_getitimer"]=(a0,a1)=>(_getitimer=Module["_getitimer"]=wasmExports["getitimer"])(a0,a1);var _strsignal=Module["_strsignal"]=a0=>(_strsignal=Module["_strsignal"]=wasmExports["strsignal"])(a0);var _strstr=Module["_strstr"]=(a0,a1)=>(_strstr=Module["_strstr"]=wasmExports["strstr"])(a0,a1);var _pause=Module["_pause"]=()=>(_pause=Module["_pause"]=wasmExports["pause"])();var _sigpending=Module["_sigpending"]=a0=>(_sigpending=Module["_sigpending"]=wasmExports["sigpending"])(a0);var _sigwait=Module["_sigwait"]=(a0,a1)=>(_sigwait=Module["_sigwait"]=wasmExports["sigwait"])(a0,a1);var _sigwaitinfo=Module["_sigwaitinfo"]=(a0,a1)=>(_sigwaitinfo=Module["_sigwaitinfo"]=wasmExports["sigwaitinfo"])(a0,a1);var _sigtimedwait=Module["_sigtimedwait"]=(a0,a1,a2)=>(_sigtimedwait=Module["_sigtimedwait"]=wasmExports["sigtimedwait"])(a0,a1,a2);var _sigismember=Module["_sigismember"]=(a0,a1)=>(_sigismember=Module["_sigismember"]=wasmExports["sigismember"])(a0,a1);var ___libc_current_sigrtmin=Module["___libc_current_sigrtmin"]=()=>(___libc_current_sigrtmin=Module["___libc_current_sigrtmin"]=wasmExports["__libc_current_sigrtmin"])();var ___libc_current_sigrtmax=Module["___libc_current_sigrtmax"]=()=>(___libc_current_sigrtmax=Module["___libc_current_sigrtmax"]=wasmExports["__libc_current_sigrtmax"])();var _isalnum=Module["_isalnum"]=a0=>(_isalnum=Module["_isalnum"]=wasmExports["isalnum"])(a0);var _toupper=Module["_toupper"]=a0=>(_toupper=Module["_toupper"]=wasmExports["toupper"])(a0);var _clock_settime=Module["_clock_settime"]=(a0,a1)=>(_clock_settime=Module["_clock_settime"]=wasmExports["clock_settime"])(a0,a1);var _pthread_getcpuclockid=Module["_pthread_getcpuclockid"]=(a0,a1)=>(_pthread_getcpuclockid=Module["_pthread_getcpuclockid"]=wasmExports["pthread_getcpuclockid"])(a0,a1);var _clock_nanosleep=Module["_clock_nanosleep"]=(a0,a1,a2,a3)=>(_clock_nanosleep=Module["_clock_nanosleep"]=wasmExports["clock_nanosleep"])(a0,a1,a2,a3);var _time=Module["_time"]=a0=>(_time=Module["_time"]=wasmExports["time"])(a0);var _mktime=Module["_mktime"]=a0=>(_mktime=Module["_mktime"]=wasmExports["mktime"])(a0);var _clock=Module["_clock"]=()=>(_clock=Module["_clock"]=wasmExports["clock"])();var _wcscoll=Module["_wcscoll"]=(a0,a1)=>(_wcscoll=Module["_wcscoll"]=wasmExports["wcscoll"])(a0,a1);var _wcsxfrm=Module["_wcsxfrm"]=(a0,a1,a2)=>(_wcsxfrm=Module["_wcsxfrm"]=wasmExports["wcsxfrm"])(a0,a1,a2);var _gettext=Module["_gettext"]=a0=>(_gettext=Module["_gettext"]=wasmExports["gettext"])(a0);var _dgettext=Module["_dgettext"]=(a0,a1)=>(_dgettext=Module["_dgettext"]=wasmExports["dgettext"])(a0,a1);var _dcgettext=Module["_dcgettext"]=(a0,a1,a2)=>(_dcgettext=Module["_dcgettext"]=wasmExports["dcgettext"])(a0,a1,a2);var _textdomain=Module["_textdomain"]=a0=>(_textdomain=Module["_textdomain"]=wasmExports["textdomain"])(a0);var _bindtextdomain=Module["_bindtextdomain"]=(a0,a1)=>(_bindtextdomain=Module["_bindtextdomain"]=wasmExports["bindtextdomain"])(a0,a1);var _bind_textdomain_codeset=Module["_bind_textdomain_codeset"]=(a0,a1)=>(_bind_textdomain_codeset=Module["_bind_textdomain_codeset"]=wasmExports["bind_textdomain_codeset"])(a0,a1);var _gettimeofday=Module["_gettimeofday"]=(a0,a1)=>(_gettimeofday=Module["_gettimeofday"]=wasmExports["gettimeofday"])(a0,a1);var ___small_fprintf=Module["___small_fprintf"]=(a0,a1,a2)=>(___small_fprintf=Module["___small_fprintf"]=wasmExports["__small_fprintf"])(a0,a1,a2);var __Py_Get_Getpath_CodeObject=Module["__Py_Get_Getpath_CodeObject"]=()=>(__Py_Get_Getpath_CodeObject=Module["__Py_Get_Getpath_CodeObject"]=wasmExports["_Py_Get_Getpath_CodeObject"])();var _ffi_prep_closure=Module["_ffi_prep_closure"]=(a0,a1,a2,a3)=>(_ffi_prep_closure=Module["_ffi_prep_closure"]=wasmExports["ffi_prep_closure"])(a0,a1,a2,a3);var _ffi_get_struct_offsets=Module["_ffi_get_struct_offsets"]=(a0,a1,a2)=>(_ffi_get_struct_offsets=Module["_ffi_get_struct_offsets"]=wasmExports["ffi_get_struct_offsets"])(a0,a1,a2);var _ffi_java_raw_size=Module["_ffi_java_raw_size"]=a0=>(_ffi_java_raw_size=Module["_ffi_java_raw_size"]=wasmExports["ffi_java_raw_size"])(a0);var _ffi_java_raw_to_ptrarray=Module["_ffi_java_raw_to_ptrarray"]=(a0,a1,a2)=>(_ffi_java_raw_to_ptrarray=Module["_ffi_java_raw_to_ptrarray"]=wasmExports["ffi_java_raw_to_ptrarray"])(a0,a1,a2);var _ffi_java_ptrarray_to_raw=Module["_ffi_java_ptrarray_to_raw"]=(a0,a1,a2)=>(_ffi_java_ptrarray_to_raw=Module["_ffi_java_ptrarray_to_raw"]=wasmExports["ffi_java_ptrarray_to_raw"])(a0,a1,a2);var _ffi_java_raw_call=Module["_ffi_java_raw_call"]=(a0,a1,a2,a3)=>(_ffi_java_raw_call=Module["_ffi_java_raw_call"]=wasmExports["ffi_java_raw_call"])(a0,a1,a2,a3);var _ffi_prep_java_raw_closure_loc=Module["_ffi_prep_java_raw_closure_loc"]=(a0,a1,a2,a3,a4)=>(_ffi_prep_java_raw_closure_loc=Module["_ffi_prep_java_raw_closure_loc"]=wasmExports["ffi_prep_java_raw_closure_loc"])(a0,a1,a2,a3,a4);var _ffi_prep_java_raw_closure=Module["_ffi_prep_java_raw_closure"]=(a0,a1,a2,a3)=>(_ffi_prep_java_raw_closure=Module["_ffi_prep_java_raw_closure"]=wasmExports["ffi_prep_java_raw_closure"])(a0,a1,a2,a3);var _ffi_tramp_is_supported=Module["_ffi_tramp_is_supported"]=()=>(_ffi_tramp_is_supported=Module["_ffi_tramp_is_supported"]=wasmExports["ffi_tramp_is_supported"])();var _ffi_tramp_alloc=Module["_ffi_tramp_alloc"]=a0=>(_ffi_tramp_alloc=Module["_ffi_tramp_alloc"]=wasmExports["ffi_tramp_alloc"])(a0);var _ffi_tramp_set_parms=Module["_ffi_tramp_set_parms"]=(a0,a1,a2)=>(_ffi_tramp_set_parms=Module["_ffi_tramp_set_parms"]=wasmExports["ffi_tramp_set_parms"])(a0,a1,a2);var _ffi_tramp_get_addr=Module["_ffi_tramp_get_addr"]=a0=>(_ffi_tramp_get_addr=Module["_ffi_tramp_get_addr"]=wasmExports["ffi_tramp_get_addr"])(a0);var _ffi_tramp_free=Module["_ffi_tramp_free"]=a0=>(_ffi_tramp_free=Module["_ffi_tramp_free"]=wasmExports["ffi_tramp_free"])(a0);var __hiwire_immortal_add=Module["__hiwire_immortal_add"]=a0=>(__hiwire_immortal_add=Module["__hiwire_immortal_add"]=wasmExports["_hiwire_immortal_add"])(a0);var __hiwire_immortal_get=Module["__hiwire_immortal_get"]=a0=>(__hiwire_immortal_get=Module["__hiwire_immortal_get"]=wasmExports["_hiwire_immortal_get"])(a0);var __hiwire_get=Module["__hiwire_get"]=a0=>(__hiwire_get=Module["__hiwire_get"]=wasmExports["_hiwire_get"])(a0);var __hiwire_set=Module["__hiwire_set"]=(a0,a1)=>(__hiwire_set=Module["__hiwire_set"]=wasmExports["_hiwire_set"])(a0,a1);var _hiwire_num_refs=Module["_hiwire_num_refs"]=()=>(_hiwire_num_refs=Module["_hiwire_num_refs"]=wasmExports["hiwire_num_refs"])();var __hiwire_slot_info=Module["__hiwire_slot_info"]=a0=>(__hiwire_slot_info=Module["__hiwire_slot_info"]=wasmExports["_hiwire_slot_info"])(a0);var __hiwire_delete=Module["__hiwire_delete"]=a0=>(__hiwire_delete=Module["__hiwire_delete"]=wasmExports["_hiwire_delete"])(a0);var __hiwire_immortal_table_init=Module["__hiwire_immortal_table_init"]=()=>(__hiwire_immortal_table_init=Module["__hiwire_immortal_table_init"]=wasmExports["_hiwire_immortal_table_init"])();var _emscripten_GetProcAddress=Module["_emscripten_GetProcAddress"]=a0=>(_emscripten_GetProcAddress=Module["_emscripten_GetProcAddress"]=wasmExports["emscripten_GetProcAddress"])(a0);var _emscripten_webgl1_get_proc_address=Module["_emscripten_webgl1_get_proc_address"]=a0=>(_emscripten_webgl1_get_proc_address=Module["_emscripten_webgl1_get_proc_address"]=wasmExports["emscripten_webgl1_get_proc_address"])(a0);var __webgl1_match_ext_proc_address_without_suffix=Module["__webgl1_match_ext_proc_address_without_suffix"]=a0=>(__webgl1_match_ext_proc_address_without_suffix=Module["__webgl1_match_ext_proc_address_without_suffix"]=wasmExports["_webgl1_match_ext_proc_address_without_suffix"])(a0);var _emscripten_webgl_get_proc_address=Module["_emscripten_webgl_get_proc_address"]=a0=>(_emscripten_webgl_get_proc_address=Module["_emscripten_webgl_get_proc_address"]=wasmExports["emscripten_webgl_get_proc_address"])(a0);var _SDL_GL_GetProcAddress=Module["_SDL_GL_GetProcAddress"]=a0=>(_SDL_GL_GetProcAddress=Module["_SDL_GL_GetProcAddress"]=wasmExports["SDL_GL_GetProcAddress"])(a0);var _eglGetProcAddress=Module["_eglGetProcAddress"]=a0=>(_eglGetProcAddress=Module["_eglGetProcAddress"]=wasmExports["eglGetProcAddress"])(a0);var _glfwGetProcAddress=Module["_glfwGetProcAddress"]=a0=>(_glfwGetProcAddress=Module["_glfwGetProcAddress"]=wasmExports["glfwGetProcAddress"])(a0);var _emscripten_webgl_init_context_attributes=Module["_emscripten_webgl_init_context_attributes"]=a0=>(_emscripten_webgl_init_context_attributes=Module["_emscripten_webgl_init_context_attributes"]=wasmExports["emscripten_webgl_init_context_attributes"])(a0);var _emscripten_is_main_runtime_thread=Module["_emscripten_is_main_runtime_thread"]=()=>(_emscripten_is_main_runtime_thread=Module["_emscripten_is_main_runtime_thread"]=wasmExports["emscripten_is_main_runtime_thread"])();var _adler32_z=Module["_adler32_z"]=(a0,a1,a2)=>(_adler32_z=Module["_adler32_z"]=wasmExports["adler32_z"])(a0,a1,a2);var _adler32_combine=Module["_adler32_combine"]=(a0,a1,a2)=>(_adler32_combine=Module["_adler32_combine"]=wasmExports["adler32_combine"])(a0,a1,a2);var _adler32_combine64=Module["_adler32_combine64"]=(a0,a1,a2)=>(_adler32_combine64=Module["_adler32_combine64"]=wasmExports["adler32_combine64"])(a0,a1,a2);var _compress2=Module["_compress2"]=(a0,a1,a2,a3,a4)=>(_compress2=Module["_compress2"]=wasmExports["compress2"])(a0,a1,a2,a3,a4);var _deflateInit_=Module["_deflateInit_"]=(a0,a1,a2,a3)=>(_deflateInit_=Module["_deflateInit_"]=wasmExports["deflateInit_"])(a0,a1,a2,a3);var _compress=Module["_compress"]=(a0,a1,a2,a3)=>(_compress=Module["_compress"]=wasmExports["compress"])(a0,a1,a2,a3);var _compressBound=Module["_compressBound"]=a0=>(_compressBound=Module["_compressBound"]=wasmExports["compressBound"])(a0);var _get_crc_table=Module["_get_crc_table"]=()=>(_get_crc_table=Module["_get_crc_table"]=wasmExports["get_crc_table"])();var _crc32_z=Module["_crc32_z"]=(a0,a1,a2)=>(_crc32_z=Module["_crc32_z"]=wasmExports["crc32_z"])(a0,a1,a2);var _crc32_combine64=Module["_crc32_combine64"]=(a0,a1,a2)=>(_crc32_combine64=Module["_crc32_combine64"]=wasmExports["crc32_combine64"])(a0,a1,a2);var _crc32_combine=Module["_crc32_combine"]=(a0,a1,a2)=>(_crc32_combine=Module["_crc32_combine"]=wasmExports["crc32_combine"])(a0,a1,a2);var _crc32_combine_gen64=Module["_crc32_combine_gen64"]=a0=>(_crc32_combine_gen64=Module["_crc32_combine_gen64"]=wasmExports["crc32_combine_gen64"])(a0);var _crc32_combine_gen=Module["_crc32_combine_gen"]=a0=>(_crc32_combine_gen=Module["_crc32_combine_gen"]=wasmExports["crc32_combine_gen"])(a0);var _crc32_combine_op=Module["_crc32_combine_op"]=(a0,a1,a2)=>(_crc32_combine_op=Module["_crc32_combine_op"]=wasmExports["crc32_combine_op"])(a0,a1,a2);var _zcalloc=Module["_zcalloc"]=(a0,a1,a2)=>(_zcalloc=Module["_zcalloc"]=wasmExports["zcalloc"])(a0,a1,a2);var _zcfree=Module["_zcfree"]=(a0,a1)=>(_zcfree=Module["_zcfree"]=wasmExports["zcfree"])(a0,a1);var _deflateReset=Module["_deflateReset"]=a0=>(_deflateReset=Module["_deflateReset"]=wasmExports["deflateReset"])(a0);var _deflateResetKeep=Module["_deflateResetKeep"]=a0=>(_deflateResetKeep=Module["_deflateResetKeep"]=wasmExports["deflateResetKeep"])(a0);var _deflateGetDictionary=Module["_deflateGetDictionary"]=(a0,a1,a2)=>(_deflateGetDictionary=Module["_deflateGetDictionary"]=wasmExports["deflateGetDictionary"])(a0,a1,a2);var __tr_init=Module["__tr_init"]=a0=>(__tr_init=Module["__tr_init"]=wasmExports["_tr_init"])(a0);var _deflateSetHeader=Module["_deflateSetHeader"]=(a0,a1)=>(_deflateSetHeader=Module["_deflateSetHeader"]=wasmExports["deflateSetHeader"])(a0,a1);var _deflatePending=Module["_deflatePending"]=(a0,a1,a2)=>(_deflatePending=Module["_deflatePending"]=wasmExports["deflatePending"])(a0,a1,a2);var _deflatePrime=Module["_deflatePrime"]=(a0,a1,a2)=>(_deflatePrime=Module["_deflatePrime"]=wasmExports["deflatePrime"])(a0,a1,a2);var __tr_flush_bits=Module["__tr_flush_bits"]=a0=>(__tr_flush_bits=Module["__tr_flush_bits"]=wasmExports["_tr_flush_bits"])(a0);var _deflateParams=Module["_deflateParams"]=(a0,a1,a2)=>(_deflateParams=Module["_deflateParams"]=wasmExports["deflateParams"])(a0,a1,a2);var __tr_align=Module["__tr_align"]=a0=>(__tr_align=Module["__tr_align"]=wasmExports["_tr_align"])(a0);var __tr_stored_block=Module["__tr_stored_block"]=(a0,a1,a2,a3)=>(__tr_stored_block=Module["__tr_stored_block"]=wasmExports["_tr_stored_block"])(a0,a1,a2,a3);var _deflateTune=Module["_deflateTune"]=(a0,a1,a2,a3,a4)=>(_deflateTune=Module["_deflateTune"]=wasmExports["deflateTune"])(a0,a1,a2,a3,a4);var _deflateBound=Module["_deflateBound"]=(a0,a1)=>(_deflateBound=Module["_deflateBound"]=wasmExports["deflateBound"])(a0,a1);var __tr_flush_block=Module["__tr_flush_block"]=(a0,a1,a2,a3)=>(__tr_flush_block=Module["__tr_flush_block"]=wasmExports["_tr_flush_block"])(a0,a1,a2,a3);var _gzclose=Module["_gzclose"]=a0=>(_gzclose=Module["_gzclose"]=wasmExports["gzclose"])(a0);var _gzclose_r=Module["_gzclose_r"]=a0=>(_gzclose_r=Module["_gzclose_r"]=wasmExports["gzclose_r"])(a0);var _gzclose_w=Module["_gzclose_w"]=a0=>(_gzclose_w=Module["_gzclose_w"]=wasmExports["gzclose_w"])(a0);var _gzopen=Module["_gzopen"]=(a0,a1)=>(_gzopen=Module["_gzopen"]=wasmExports["gzopen"])(a0,a1);var _gzopen64=Module["_gzopen64"]=(a0,a1)=>(_gzopen64=Module["_gzopen64"]=wasmExports["gzopen64"])(a0,a1);var _gzdopen=Module["_gzdopen"]=(a0,a1)=>(_gzdopen=Module["_gzdopen"]=wasmExports["gzdopen"])(a0,a1);var _gzbuffer=Module["_gzbuffer"]=(a0,a1)=>(_gzbuffer=Module["_gzbuffer"]=wasmExports["gzbuffer"])(a0,a1);var _gzrewind=Module["_gzrewind"]=a0=>(_gzrewind=Module["_gzrewind"]=wasmExports["gzrewind"])(a0);var _gzseek64=Module["_gzseek64"]=(a0,a1,a2)=>(_gzseek64=Module["_gzseek64"]=wasmExports["gzseek64"])(a0,a1,a2);var _gz_error=Module["_gz_error"]=(a0,a1,a2)=>(_gz_error=Module["_gz_error"]=wasmExports["gz_error"])(a0,a1,a2);var _gzseek=Module["_gzseek"]=(a0,a1,a2)=>(_gzseek=Module["_gzseek"]=wasmExports["gzseek"])(a0,a1,a2);var _gztell64=Module["_gztell64"]=a0=>(_gztell64=Module["_gztell64"]=wasmExports["gztell64"])(a0);var _gztell=Module["_gztell"]=a0=>(_gztell=Module["_gztell"]=wasmExports["gztell"])(a0);var _gzoffset64=Module["_gzoffset64"]=a0=>(_gzoffset64=Module["_gzoffset64"]=wasmExports["gzoffset64"])(a0);var _gzoffset=Module["_gzoffset"]=a0=>(_gzoffset=Module["_gzoffset"]=wasmExports["gzoffset"])(a0);var _gzeof=Module["_gzeof"]=a0=>(_gzeof=Module["_gzeof"]=wasmExports["gzeof"])(a0);var _gzerror=Module["_gzerror"]=(a0,a1)=>(_gzerror=Module["_gzerror"]=wasmExports["gzerror"])(a0,a1);var _gzclearerr=Module["_gzclearerr"]=a0=>(_gzclearerr=Module["_gzclearerr"]=wasmExports["gzclearerr"])(a0);var _gzread=Module["_gzread"]=(a0,a1,a2)=>(_gzread=Module["_gzread"]=wasmExports["gzread"])(a0,a1,a2);var _gzfread=Module["_gzfread"]=(a0,a1,a2,a3)=>(_gzfread=Module["_gzfread"]=wasmExports["gzfread"])(a0,a1,a2,a3);var _gzgetc=Module["_gzgetc"]=a0=>(_gzgetc=Module["_gzgetc"]=wasmExports["gzgetc"])(a0);var _gzgetc_=Module["_gzgetc_"]=a0=>(_gzgetc_=Module["_gzgetc_"]=wasmExports["gzgetc_"])(a0);var _gzungetc=Module["_gzungetc"]=(a0,a1)=>(_gzungetc=Module["_gzungetc"]=wasmExports["gzungetc"])(a0,a1);var _gzgets=Module["_gzgets"]=(a0,a1,a2)=>(_gzgets=Module["_gzgets"]=wasmExports["gzgets"])(a0,a1,a2);var _gzdirect=Module["_gzdirect"]=a0=>(_gzdirect=Module["_gzdirect"]=wasmExports["gzdirect"])(a0);var _inflateReset=Module["_inflateReset"]=a0=>(_inflateReset=Module["_inflateReset"]=wasmExports["inflateReset"])(a0);var _gzwrite=Module["_gzwrite"]=(a0,a1,a2)=>(_gzwrite=Module["_gzwrite"]=wasmExports["gzwrite"])(a0,a1,a2);var _gzfwrite=Module["_gzfwrite"]=(a0,a1,a2,a3)=>(_gzfwrite=Module["_gzfwrite"]=wasmExports["gzfwrite"])(a0,a1,a2,a3);var _gzputc=Module["_gzputc"]=(a0,a1)=>(_gzputc=Module["_gzputc"]=wasmExports["gzputc"])(a0,a1);var _gzputs=Module["_gzputs"]=(a0,a1)=>(_gzputs=Module["_gzputs"]=wasmExports["gzputs"])(a0,a1);var _gzvprintf=Module["_gzvprintf"]=(a0,a1,a2)=>(_gzvprintf=Module["_gzvprintf"]=wasmExports["gzvprintf"])(a0,a1,a2);var _gzprintf=Module["_gzprintf"]=(a0,a1,a2)=>(_gzprintf=Module["_gzprintf"]=wasmExports["gzprintf"])(a0,a1,a2);var _gzflush=Module["_gzflush"]=(a0,a1)=>(_gzflush=Module["_gzflush"]=wasmExports["gzflush"])(a0,a1);var _gzsetparams=Module["_gzsetparams"]=(a0,a1,a2)=>(_gzsetparams=Module["_gzsetparams"]=wasmExports["gzsetparams"])(a0,a1,a2);var _inflateBackInit_=Module["_inflateBackInit_"]=(a0,a1,a2,a3,a4)=>(_inflateBackInit_=Module["_inflateBackInit_"]=wasmExports["inflateBackInit_"])(a0,a1,a2,a3,a4);var _inflateBack=Module["_inflateBack"]=(a0,a1,a2,a3,a4)=>(_inflateBack=Module["_inflateBack"]=wasmExports["inflateBack"])(a0,a1,a2,a3,a4);var _inflate_table=Module["_inflate_table"]=(a0,a1,a2,a3,a4,a5)=>(_inflate_table=Module["_inflate_table"]=wasmExports["inflate_table"])(a0,a1,a2,a3,a4,a5);var _inflate_fast=Module["_inflate_fast"]=(a0,a1)=>(_inflate_fast=Module["_inflate_fast"]=wasmExports["inflate_fast"])(a0,a1);var _inflateBackEnd=Module["_inflateBackEnd"]=a0=>(_inflateBackEnd=Module["_inflateBackEnd"]=wasmExports["inflateBackEnd"])(a0);var _inflateResetKeep=Module["_inflateResetKeep"]=a0=>(_inflateResetKeep=Module["_inflateResetKeep"]=wasmExports["inflateResetKeep"])(a0);var _inflateReset2=Module["_inflateReset2"]=(a0,a1)=>(_inflateReset2=Module["_inflateReset2"]=wasmExports["inflateReset2"])(a0,a1);var _inflateInit_=Module["_inflateInit_"]=(a0,a1,a2)=>(_inflateInit_=Module["_inflateInit_"]=wasmExports["inflateInit_"])(a0,a1,a2);var _inflatePrime=Module["_inflatePrime"]=(a0,a1,a2)=>(_inflatePrime=Module["_inflatePrime"]=wasmExports["inflatePrime"])(a0,a1,a2);var _inflateGetDictionary=Module["_inflateGetDictionary"]=(a0,a1,a2)=>(_inflateGetDictionary=Module["_inflateGetDictionary"]=wasmExports["inflateGetDictionary"])(a0,a1,a2);var _inflateGetHeader=Module["_inflateGetHeader"]=(a0,a1)=>(_inflateGetHeader=Module["_inflateGetHeader"]=wasmExports["inflateGetHeader"])(a0,a1);var _inflateSync=Module["_inflateSync"]=a0=>(_inflateSync=Module["_inflateSync"]=wasmExports["inflateSync"])(a0);var _inflateSyncPoint=Module["_inflateSyncPoint"]=a0=>(_inflateSyncPoint=Module["_inflateSyncPoint"]=wasmExports["inflateSyncPoint"])(a0);var _inflateUndermine=Module["_inflateUndermine"]=(a0,a1)=>(_inflateUndermine=Module["_inflateUndermine"]=wasmExports["inflateUndermine"])(a0,a1);var _inflateValidate=Module["_inflateValidate"]=(a0,a1)=>(_inflateValidate=Module["_inflateValidate"]=wasmExports["inflateValidate"])(a0,a1);var _inflateMark=Module["_inflateMark"]=a0=>(_inflateMark=Module["_inflateMark"]=wasmExports["inflateMark"])(a0);var _inflateCodesUsed=Module["_inflateCodesUsed"]=a0=>(_inflateCodesUsed=Module["_inflateCodesUsed"]=wasmExports["inflateCodesUsed"])(a0);var __tr_tally=Module["__tr_tally"]=(a0,a1,a2)=>(__tr_tally=Module["__tr_tally"]=wasmExports["_tr_tally"])(a0,a1,a2);var _uncompress2=Module["_uncompress2"]=(a0,a1,a2,a3)=>(_uncompress2=Module["_uncompress2"]=wasmExports["uncompress2"])(a0,a1,a2,a3);var _uncompress=Module["_uncompress"]=(a0,a1,a2,a3)=>(_uncompress=Module["_uncompress"]=wasmExports["uncompress"])(a0,a1,a2,a3);var _zlibCompileFlags=Module["_zlibCompileFlags"]=()=>(_zlibCompileFlags=Module["_zlibCompileFlags"]=wasmExports["zlibCompileFlags"])();var _zError=Module["_zError"]=a0=>(_zError=Module["_zError"]=wasmExports["zError"])(a0);var _BZ2_blockSort=Module["_BZ2_blockSort"]=a0=>(_BZ2_blockSort=Module["_BZ2_blockSort"]=wasmExports["BZ2_blockSort"])(a0);var _BZ2_bz__AssertH__fail=Module["_BZ2_bz__AssertH__fail"]=a0=>(_BZ2_bz__AssertH__fail=Module["_BZ2_bz__AssertH__fail"]=wasmExports["BZ2_bz__AssertH__fail"])(a0);var _BZ2_bzlibVersion=Module["_BZ2_bzlibVersion"]=()=>(_BZ2_bzlibVersion=Module["_BZ2_bzlibVersion"]=wasmExports["BZ2_bzlibVersion"])();var _BZ2_compressBlock=Module["_BZ2_compressBlock"]=(a0,a1)=>(_BZ2_compressBlock=Module["_BZ2_compressBlock"]=wasmExports["BZ2_compressBlock"])(a0,a1);var _BZ2_indexIntoF=Module["_BZ2_indexIntoF"]=(a0,a1)=>(_BZ2_indexIntoF=Module["_BZ2_indexIntoF"]=wasmExports["BZ2_indexIntoF"])(a0,a1);var _BZ2_decompress=Module["_BZ2_decompress"]=a0=>(_BZ2_decompress=Module["_BZ2_decompress"]=wasmExports["BZ2_decompress"])(a0);var _BZ2_bzWriteOpen=Module["_BZ2_bzWriteOpen"]=(a0,a1,a2,a3,a4)=>(_BZ2_bzWriteOpen=Module["_BZ2_bzWriteOpen"]=wasmExports["BZ2_bzWriteOpen"])(a0,a1,a2,a3,a4);var _BZ2_bzWrite=Module["_BZ2_bzWrite"]=(a0,a1,a2,a3)=>(_BZ2_bzWrite=Module["_BZ2_bzWrite"]=wasmExports["BZ2_bzWrite"])(a0,a1,a2,a3);var _BZ2_bzWriteClose=Module["_BZ2_bzWriteClose"]=(a0,a1,a2,a3,a4)=>(_BZ2_bzWriteClose=Module["_BZ2_bzWriteClose"]=wasmExports["BZ2_bzWriteClose"])(a0,a1,a2,a3,a4);var _BZ2_bzWriteClose64=Module["_BZ2_bzWriteClose64"]=(a0,a1,a2,a3,a4,a5,a6)=>(_BZ2_bzWriteClose64=Module["_BZ2_bzWriteClose64"]=wasmExports["BZ2_bzWriteClose64"])(a0,a1,a2,a3,a4,a5,a6);var _BZ2_bzReadOpen=Module["_BZ2_bzReadOpen"]=(a0,a1,a2,a3,a4,a5)=>(_BZ2_bzReadOpen=Module["_BZ2_bzReadOpen"]=wasmExports["BZ2_bzReadOpen"])(a0,a1,a2,a3,a4,a5);var _BZ2_bzReadClose=Module["_BZ2_bzReadClose"]=(a0,a1)=>(_BZ2_bzReadClose=Module["_BZ2_bzReadClose"]=wasmExports["BZ2_bzReadClose"])(a0,a1);var _BZ2_bzRead=Module["_BZ2_bzRead"]=(a0,a1,a2,a3)=>(_BZ2_bzRead=Module["_BZ2_bzRead"]=wasmExports["BZ2_bzRead"])(a0,a1,a2,a3);var _fgetc=Module["_fgetc"]=a0=>(_fgetc=Module["_fgetc"]=wasmExports["fgetc"])(a0);var _BZ2_bzReadGetUnused=Module["_BZ2_bzReadGetUnused"]=(a0,a1,a2,a3)=>(_BZ2_bzReadGetUnused=Module["_BZ2_bzReadGetUnused"]=wasmExports["BZ2_bzReadGetUnused"])(a0,a1,a2,a3);var _BZ2_bzBuffToBuffCompress=Module["_BZ2_bzBuffToBuffCompress"]=(a0,a1,a2,a3,a4,a5,a6)=>(_BZ2_bzBuffToBuffCompress=Module["_BZ2_bzBuffToBuffCompress"]=wasmExports["BZ2_bzBuffToBuffCompress"])(a0,a1,a2,a3,a4,a5,a6);var _BZ2_bzBuffToBuffDecompress=Module["_BZ2_bzBuffToBuffDecompress"]=(a0,a1,a2,a3,a4,a5)=>(_BZ2_bzBuffToBuffDecompress=Module["_BZ2_bzBuffToBuffDecompress"]=wasmExports["BZ2_bzBuffToBuffDecompress"])(a0,a1,a2,a3,a4,a5);var _BZ2_bzopen=Module["_BZ2_bzopen"]=(a0,a1)=>(_BZ2_bzopen=Module["_BZ2_bzopen"]=wasmExports["BZ2_bzopen"])(a0,a1);var _BZ2_bzdopen=Module["_BZ2_bzdopen"]=(a0,a1)=>(_BZ2_bzdopen=Module["_BZ2_bzdopen"]=wasmExports["BZ2_bzdopen"])(a0,a1);var _BZ2_bzread=Module["_BZ2_bzread"]=(a0,a1,a2)=>(_BZ2_bzread=Module["_BZ2_bzread"]=wasmExports["BZ2_bzread"])(a0,a1,a2);var _BZ2_bzwrite=Module["_BZ2_bzwrite"]=(a0,a1,a2)=>(_BZ2_bzwrite=Module["_BZ2_bzwrite"]=wasmExports["BZ2_bzwrite"])(a0,a1,a2);var _BZ2_bzflush=Module["_BZ2_bzflush"]=a0=>(_BZ2_bzflush=Module["_BZ2_bzflush"]=wasmExports["BZ2_bzflush"])(a0);var _BZ2_bzclose=Module["_BZ2_bzclose"]=a0=>(_BZ2_bzclose=Module["_BZ2_bzclose"]=wasmExports["BZ2_bzclose"])(a0);var _BZ2_bzerror=Module["_BZ2_bzerror"]=(a0,a1)=>(_BZ2_bzerror=Module["_BZ2_bzerror"]=wasmExports["BZ2_bzerror"])(a0,a1);var _BZ2_bsInitWrite=Module["_BZ2_bsInitWrite"]=a0=>(_BZ2_bsInitWrite=Module["_BZ2_bsInitWrite"]=wasmExports["BZ2_bsInitWrite"])(a0);var _BZ2_hbMakeCodeLengths=Module["_BZ2_hbMakeCodeLengths"]=(a0,a1,a2,a3)=>(_BZ2_hbMakeCodeLengths=Module["_BZ2_hbMakeCodeLengths"]=wasmExports["BZ2_hbMakeCodeLengths"])(a0,a1,a2,a3);var _BZ2_hbAssignCodes=Module["_BZ2_hbAssignCodes"]=(a0,a1,a2,a3,a4)=>(_BZ2_hbAssignCodes=Module["_BZ2_hbAssignCodes"]=wasmExports["BZ2_hbAssignCodes"])(a0,a1,a2,a3,a4);var _BZ2_hbCreateDecodeTables=Module["_BZ2_hbCreateDecodeTables"]=(a0,a1,a2,a3,a4,a5,a6)=>(_BZ2_hbCreateDecodeTables=Module["_BZ2_hbCreateDecodeTables"]=wasmExports["BZ2_hbCreateDecodeTables"])(a0,a1,a2,a3,a4,a5,a6);var __emscripten_memcpy_bulkmem=Module["__emscripten_memcpy_bulkmem"]=(a0,a1,a2)=>(__emscripten_memcpy_bulkmem=Module["__emscripten_memcpy_bulkmem"]=wasmExports["_emscripten_memcpy_bulkmem"])(a0,a1,a2);var _emscripten_builtin_memcpy=Module["_emscripten_builtin_memcpy"]=(a0,a1,a2)=>(_emscripten_builtin_memcpy=Module["_emscripten_builtin_memcpy"]=wasmExports["emscripten_builtin_memcpy"])(a0,a1,a2);var ___memset=Module["___memset"]=(a0,a1,a2)=>(___memset=Module["___memset"]=wasmExports["__memset"])(a0,a1,a2);var __emscripten_memset_bulkmem=Module["__emscripten_memset_bulkmem"]=(a0,a1,a2)=>(__emscripten_memset_bulkmem=Module["__emscripten_memset_bulkmem"]=wasmExports["_emscripten_memset_bulkmem"])(a0,a1,a2);var _emscripten_builtin_memset=Module["_emscripten_builtin_memset"]=(a0,a1,a2)=>(_emscripten_builtin_memset=Module["_emscripten_builtin_memset"]=wasmExports["emscripten_builtin_memset"])(a0,a1,a2);var _getdate=Module["_getdate"]=a0=>(_getdate=Module["_getdate"]=wasmExports["getdate"])(a0);var _stime=Module["_stime"]=a0=>(_stime=Module["_stime"]=wasmExports["stime"])(a0);var _clock_getcpuclockid=Module["_clock_getcpuclockid"]=(a0,a1)=>(_clock_getcpuclockid=Module["_clock_getcpuclockid"]=wasmExports["clock_getcpuclockid"])(a0,a1);var _getpwnam=Module["_getpwnam"]=a0=>(_getpwnam=Module["_getpwnam"]=wasmExports["getpwnam"])(a0);var _getpwuid=Module["_getpwuid"]=a0=>(_getpwuid=Module["_getpwuid"]=wasmExports["getpwuid"])(a0);var _getpwnam_r=Module["_getpwnam_r"]=(a0,a1,a2,a3,a4)=>(_getpwnam_r=Module["_getpwnam_r"]=wasmExports["getpwnam_r"])(a0,a1,a2,a3,a4);var _getpwuid_r=Module["_getpwuid_r"]=(a0,a1,a2,a3,a4)=>(_getpwuid_r=Module["_getpwuid_r"]=wasmExports["getpwuid_r"])(a0,a1,a2,a3,a4);var _setpwent=Module["_setpwent"]=()=>(_setpwent=Module["_setpwent"]=wasmExports["setpwent"])();var _endpwent=Module["_endpwent"]=()=>(_endpwent=Module["_endpwent"]=wasmExports["endpwent"])();var _getpwent=Module["_getpwent"]=()=>(_getpwent=Module["_getpwent"]=wasmExports["getpwent"])();var _getgrnam=Module["_getgrnam"]=a0=>(_getgrnam=Module["_getgrnam"]=wasmExports["getgrnam"])(a0);var _getgrgid=Module["_getgrgid"]=a0=>(_getgrgid=Module["_getgrgid"]=wasmExports["getgrgid"])(a0);var _getgrnam_r=Module["_getgrnam_r"]=(a0,a1,a2,a3,a4)=>(_getgrnam_r=Module["_getgrnam_r"]=wasmExports["getgrnam_r"])(a0,a1,a2,a3,a4);var _getgrgid_r=Module["_getgrgid_r"]=(a0,a1,a2,a3,a4)=>(_getgrgid_r=Module["_getgrgid_r"]=wasmExports["getgrgid_r"])(a0,a1,a2,a3,a4);var _getgrent=Module["_getgrent"]=()=>(_getgrent=Module["_getgrent"]=wasmExports["getgrent"])();var _endgrent=Module["_endgrent"]=()=>(_endgrent=Module["_endgrent"]=wasmExports["endgrent"])();var _setgrent=Module["_setgrent"]=()=>(_setgrent=Module["_setgrent"]=wasmExports["setgrent"])();var _flock=Module["_flock"]=(a0,a1)=>(_flock=Module["_flock"]=wasmExports["flock"])(a0,a1);var _vfork=Module["_vfork"]=()=>(_vfork=Module["_vfork"]=wasmExports["vfork"])();var _posix_spawn=Module["_posix_spawn"]=(a0,a1,a2,a3,a4,a5)=>(_posix_spawn=Module["_posix_spawn"]=wasmExports["posix_spawn"])(a0,a1,a2,a3,a4,a5);var _popen=Module["_popen"]=(a0,a1)=>(_popen=Module["_popen"]=wasmExports["popen"])(a0,a1);var _pclose=Module["_pclose"]=a0=>(_pclose=Module["_pclose"]=wasmExports["pclose"])(a0);var _setgroups=Module["_setgroups"]=(a0,a1)=>(_setgroups=Module["_setgroups"]=wasmExports["setgroups"])(a0,a1);var _sigaltstack=Module["_sigaltstack"]=(a0,a1)=>(_sigaltstack=Module["_sigaltstack"]=wasmExports["sigaltstack"])(a0,a1);var ___syscall_uname=Module["___syscall_uname"]=a0=>(___syscall_uname=Module["___syscall_uname"]=wasmExports["__syscall_uname"])(a0);var ___syscall_setpgid=Module["___syscall_setpgid"]=(a0,a1)=>(___syscall_setpgid=Module["___syscall_setpgid"]=wasmExports["__syscall_setpgid"])(a0,a1);var ___syscall_sync=Module["___syscall_sync"]=()=>(___syscall_sync=Module["___syscall_sync"]=wasmExports["__syscall_sync"])();var ___syscall_getsid=Module["___syscall_getsid"]=a0=>(___syscall_getsid=Module["___syscall_getsid"]=wasmExports["__syscall_getsid"])(a0);var ___syscall_getpgid=Module["___syscall_getpgid"]=a0=>(___syscall_getpgid=Module["___syscall_getpgid"]=wasmExports["__syscall_getpgid"])(a0);var ___syscall_getpid=Module["___syscall_getpid"]=()=>(___syscall_getpid=Module["___syscall_getpid"]=wasmExports["__syscall_getpid"])();var ___syscall_getppid=Module["___syscall_getppid"]=()=>(___syscall_getppid=Module["___syscall_getppid"]=wasmExports["__syscall_getppid"])();var ___syscall_linkat=Module["___syscall_linkat"]=(a0,a1,a2,a3,a4)=>(___syscall_linkat=Module["___syscall_linkat"]=wasmExports["__syscall_linkat"])(a0,a1,a2,a3,a4);var ___syscall_getgroups32=Module["___syscall_getgroups32"]=(a0,a1)=>(___syscall_getgroups32=Module["___syscall_getgroups32"]=wasmExports["__syscall_getgroups32"])(a0,a1);var ___syscall_setsid=Module["___syscall_setsid"]=()=>(___syscall_setsid=Module["___syscall_setsid"]=wasmExports["__syscall_setsid"])();var ___syscall_umask=Module["___syscall_umask"]=a0=>(___syscall_umask=Module["___syscall_umask"]=wasmExports["__syscall_umask"])(a0);var ___syscall_setrlimit=Module["___syscall_setrlimit"]=(a0,a1)=>(___syscall_setrlimit=Module["___syscall_setrlimit"]=wasmExports["__syscall_setrlimit"])(a0,a1);var ___syscall_getrusage=Module["___syscall_getrusage"]=(a0,a1)=>(___syscall_getrusage=Module["___syscall_getrusage"]=wasmExports["__syscall_getrusage"])(a0,a1);var ___syscall_getpriority=Module["___syscall_getpriority"]=(a0,a1)=>(___syscall_getpriority=Module["___syscall_getpriority"]=wasmExports["__syscall_getpriority"])(a0,a1);var ___syscall_setpriority=Module["___syscall_setpriority"]=(a0,a1,a2)=>(___syscall_setpriority=Module["___syscall_setpriority"]=wasmExports["__syscall_setpriority"])(a0,a1,a2);var ___syscall_setdomainname=Module["___syscall_setdomainname"]=(a0,a1)=>(___syscall_setdomainname=Module["___syscall_setdomainname"]=wasmExports["__syscall_setdomainname"])(a0,a1);var ___syscall_getuid32=Module["___syscall_getuid32"]=()=>(___syscall_getuid32=Module["___syscall_getuid32"]=wasmExports["__syscall_getuid32"])();var ___syscall_getgid32=Module["___syscall_getgid32"]=()=>(___syscall_getgid32=Module["___syscall_getgid32"]=wasmExports["__syscall_getgid32"])();var ___syscall_geteuid32=Module["___syscall_geteuid32"]=()=>(___syscall_geteuid32=Module["___syscall_geteuid32"]=wasmExports["__syscall_geteuid32"])();var ___syscall_getegid32=Module["___syscall_getegid32"]=()=>(___syscall_getegid32=Module["___syscall_getegid32"]=wasmExports["__syscall_getegid32"])();var ___syscall_getresuid32=Module["___syscall_getresuid32"]=(a0,a1,a2)=>(___syscall_getresuid32=Module["___syscall_getresuid32"]=wasmExports["__syscall_getresuid32"])(a0,a1,a2);var ___syscall_getresgid32=Module["___syscall_getresgid32"]=(a0,a1,a2)=>(___syscall_getresgid32=Module["___syscall_getresgid32"]=wasmExports["__syscall_getresgid32"])(a0,a1,a2);var ___syscall_pause=Module["___syscall_pause"]=()=>(___syscall_pause=Module["___syscall_pause"]=wasmExports["__syscall_pause"])();var ___syscall_madvise=Module["___syscall_madvise"]=(a0,a1,a2)=>(___syscall_madvise=Module["___syscall_madvise"]=wasmExports["__syscall_madvise"])(a0,a1,a2);var ___syscall_mlock=Module["___syscall_mlock"]=(a0,a1)=>(___syscall_mlock=Module["___syscall_mlock"]=wasmExports["__syscall_mlock"])(a0,a1);var ___syscall_munlock=Module["___syscall_munlock"]=(a0,a1)=>(___syscall_munlock=Module["___syscall_munlock"]=wasmExports["__syscall_munlock"])(a0,a1);var ___syscall_mprotect=Module["___syscall_mprotect"]=(a0,a1,a2)=>(___syscall_mprotect=Module["___syscall_mprotect"]=wasmExports["__syscall_mprotect"])(a0,a1,a2);var ___syscall_mremap=Module["___syscall_mremap"]=(a0,a1,a2,a3,a4)=>(___syscall_mremap=Module["___syscall_mremap"]=wasmExports["__syscall_mremap"])(a0,a1,a2,a3,a4);var ___syscall_mlockall=Module["___syscall_mlockall"]=a0=>(___syscall_mlockall=Module["___syscall_mlockall"]=wasmExports["__syscall_mlockall"])(a0);var ___syscall_munlockall=Module["___syscall_munlockall"]=()=>(___syscall_munlockall=Module["___syscall_munlockall"]=wasmExports["__syscall_munlockall"])();var ___syscall_prlimit64=Module["___syscall_prlimit64"]=(a0,a1,a2,a3)=>(___syscall_prlimit64=Module["___syscall_prlimit64"]=wasmExports["__syscall_prlimit64"])(a0,a1,a2,a3);var ___syscall_ugetrlimit=Module["___syscall_ugetrlimit"]=(a0,a1)=>(___syscall_ugetrlimit=Module["___syscall_ugetrlimit"]=wasmExports["__syscall_ugetrlimit"])(a0,a1);var ___syscall_setsockopt=Module["___syscall_setsockopt"]=(a0,a1,a2,a3,a4,a5)=>(___syscall_setsockopt=Module["___syscall_setsockopt"]=wasmExports["__syscall_setsockopt"])(a0,a1,a2,a3,a4,a5);var ___syscall_acct=Module["___syscall_acct"]=a0=>(___syscall_acct=Module["___syscall_acct"]=wasmExports["__syscall_acct"])(a0);var ___syscall_mincore=Module["___syscall_mincore"]=(a0,a1,a2)=>(___syscall_mincore=Module["___syscall_mincore"]=wasmExports["__syscall_mincore"])(a0,a1,a2);var ___syscall_pipe2=Module["___syscall_pipe2"]=(a0,a1)=>(___syscall_pipe2=Module["___syscall_pipe2"]=wasmExports["__syscall_pipe2"])(a0,a1);var ___syscall_pselect6=Module["___syscall_pselect6"]=(a0,a1,a2,a3,a4,a5)=>(___syscall_pselect6=Module["___syscall_pselect6"]=wasmExports["__syscall_pselect6"])(a0,a1,a2,a3,a4,a5);var ___syscall_recvmmsg=Module["___syscall_recvmmsg"]=(a0,a1,a2,a3,a4)=>(___syscall_recvmmsg=Module["___syscall_recvmmsg"]=wasmExports["__syscall_recvmmsg"])(a0,a1,a2,a3,a4);var ___syscall_sendmmsg=Module["___syscall_sendmmsg"]=(a0,a1,a2,a3,a4)=>(___syscall_sendmmsg=Module["___syscall_sendmmsg"]=wasmExports["__syscall_sendmmsg"])(a0,a1,a2,a3,a4);var ___syscall_shutdown=Module["___syscall_shutdown"]=(a0,a1,a2,a3,a4,a5)=>(___syscall_shutdown=Module["___syscall_shutdown"]=wasmExports["__syscall_shutdown"])(a0,a1,a2,a3,a4,a5);var ___syscall_socketpair=Module["___syscall_socketpair"]=(a0,a1,a2,a3,a4,a5)=>(___syscall_socketpair=Module["___syscall_socketpair"]=wasmExports["__syscall_socketpair"])(a0,a1,a2,a3,a4,a5);var ___syscall_wait4=Module["___syscall_wait4"]=(a0,a1,a2,a3)=>(___syscall_wait4=Module["___syscall_wait4"]=wasmExports["__syscall_wait4"])(a0,a1,a2,a3);var _atexit=Module["_atexit"]=a0=>(_atexit=Module["_atexit"]=wasmExports["atexit"])(a0);var ___cxa_atexit=Module["___cxa_atexit"]=(a0,a1,a2)=>(___cxa_atexit=Module["___cxa_atexit"]=wasmExports["__cxa_atexit"])(a0,a1,a2);var ___cxa_finalize=Module["___cxa_finalize"]=a0=>(___cxa_finalize=Module["___cxa_finalize"]=wasmExports["__cxa_finalize"])(a0);var __Exit=Module["__Exit"]=a0=>(__Exit=Module["__Exit"]=wasmExports["_Exit"])(a0);var _cosf=Module["_cosf"]=a0=>(_cosf=Module["_cosf"]=wasmExports["cosf"])(a0);var _sinf=Module["_sinf"]=a0=>(_sinf=Module["_sinf"]=wasmExports["sinf"])(a0);var _expf=Module["_expf"]=a0=>(_expf=Module["_expf"]=wasmExports["expf"])(a0);var ___multf3=Module["___multf3"]=(a0,a1,a2,a3,a4)=>(___multf3=Module["___multf3"]=wasmExports["__multf3"])(a0,a1,a2,a3,a4);var ___addtf3=Module["___addtf3"]=(a0,a1,a2,a3,a4)=>(___addtf3=Module["___addtf3"]=wasmExports["__addtf3"])(a0,a1,a2,a3,a4);var ___subtf3=Module["___subtf3"]=(a0,a1,a2,a3,a4)=>(___subtf3=Module["___subtf3"]=wasmExports["__subtf3"])(a0,a1,a2,a3,a4);var ___ctype_b_loc=Module["___ctype_b_loc"]=()=>(___ctype_b_loc=Module["___ctype_b_loc"]=wasmExports["__ctype_b_loc"])();var ___ctype_get_mb_cur_max=Module["___ctype_get_mb_cur_max"]=()=>(___ctype_get_mb_cur_max=Module["___ctype_get_mb_cur_max"]=wasmExports["__ctype_get_mb_cur_max"])();var ___get_tp=Module["___get_tp"]=()=>(___get_tp=Module["___get_tp"]=wasmExports["__get_tp"])();var ___ctype_tolower_loc=Module["___ctype_tolower_loc"]=()=>(___ctype_tolower_loc=Module["___ctype_tolower_loc"]=wasmExports["__ctype_tolower_loc"])();var ___ctype_toupper_loc=Module["___ctype_toupper_loc"]=()=>(___ctype_toupper_loc=Module["___ctype_toupper_loc"]=wasmExports["__ctype_toupper_loc"])();var ___emscripten_environ_constructor=Module["___emscripten_environ_constructor"]=()=>(___emscripten_environ_constructor=Module["___emscripten_environ_constructor"]=wasmExports["__emscripten_environ_constructor"])();var _emscripten_builtin_malloc=Module["_emscripten_builtin_malloc"]=a0=>(_emscripten_builtin_malloc=Module["_emscripten_builtin_malloc"]=wasmExports["emscripten_builtin_malloc"])(a0);var ___flt_rounds=Module["___flt_rounds"]=()=>(___flt_rounds=Module["___flt_rounds"]=wasmExports["__flt_rounds"])();var _fegetround=Module["_fegetround"]=()=>(_fegetround=Module["_fegetround"]=wasmExports["fegetround"])();var ___fmodeflags=Module["___fmodeflags"]=a0=>(___fmodeflags=Module["___fmodeflags"]=wasmExports["__fmodeflags"])(a0);var ___fpclassify=Module["___fpclassify"]=a0=>(___fpclassify=Module["___fpclassify"]=wasmExports["__fpclassify"])(a0);var ___fpclassifyf=Module["___fpclassifyf"]=a0=>(___fpclassifyf=Module["___fpclassifyf"]=wasmExports["__fpclassifyf"])(a0);var ___fpclassifyl=Module["___fpclassifyl"]=(a0,a1)=>(___fpclassifyl=Module["___fpclassifyl"]=wasmExports["__fpclassifyl"])(a0,a1);var ___divtf3=Module["___divtf3"]=(a0,a1,a2,a3,a4)=>(___divtf3=Module["___divtf3"]=wasmExports["__divtf3"])(a0,a1,a2,a3,a4);var ___mo_lookup=Module["___mo_lookup"]=(a0,a1,a2)=>(___mo_lookup=Module["___mo_lookup"]=wasmExports["__mo_lookup"])(a0,a1,a2);var ___overflow=Module["___overflow"]=(a0,a1)=>(___overflow=Module["___overflow"]=wasmExports["__overflow"])(a0,a1);var _scalbn=Module["_scalbn"]=(a0,a1)=>(_scalbn=Module["_scalbn"]=wasmExports["scalbn"])(a0,a1);var _floor=Module["_floor"]=a0=>(_floor=Module["_floor"]=wasmExports["floor"])(a0);var ___lttf2=Module["___lttf2"]=(a0,a1,a2,a3)=>(___lttf2=Module["___lttf2"]=wasmExports["__lttf2"])(a0,a1,a2,a3);var ___fixtfdi=Module["___fixtfdi"]=(a0,a1)=>(___fixtfdi=Module["___fixtfdi"]=wasmExports["__fixtfdi"])(a0,a1);var ___gttf2=Module["___gttf2"]=(a0,a1,a2,a3)=>(___gttf2=Module["___gttf2"]=wasmExports["__gttf2"])(a0,a1,a2,a3);var ___fixtfsi=Module["___fixtfsi"]=(a0,a1)=>(___fixtfsi=Module["___fixtfsi"]=wasmExports["__fixtfsi"])(a0,a1);var ___floatsitf=Module["___floatsitf"]=(a0,a1)=>(___floatsitf=Module["___floatsitf"]=wasmExports["__floatsitf"])(a0,a1);var ___signbit=Module["___signbit"]=a0=>(___signbit=Module["___signbit"]=wasmExports["__signbit"])(a0);var ___signbitf=Module["___signbitf"]=a0=>(___signbitf=Module["___signbitf"]=wasmExports["__signbitf"])(a0);var ___signbitl=Module["___signbitl"]=(a0,a1)=>(___signbitl=Module["___signbitl"]=wasmExports["__signbitl"])(a0,a1);var ___wasi_syscall_ret=Module["___wasi_syscall_ret"]=a0=>(___wasi_syscall_ret=Module["___wasi_syscall_ret"]=wasmExports["__wasi_syscall_ret"])(a0);var ___synccall=Module["___synccall"]=(a0,a1)=>(___synccall=Module["___synccall"]=wasmExports["__synccall"])(a0,a1);var _fabsl=Module["_fabsl"]=(a0,a1,a2)=>(_fabsl=Module["_fabsl"]=wasmExports["fabsl"])(a0,a1,a2);var ___getf2=Module["___getf2"]=(a0,a1,a2,a3)=>(___getf2=Module["___getf2"]=wasmExports["__getf2"])(a0,a1,a2,a3);var ___uflow=Module["___uflow"]=a0=>(___uflow=Module["___uflow"]=wasmExports["__uflow"])(a0);var ___fxstat=Module["___fxstat"]=(a0,a1,a2)=>(___fxstat=Module["___fxstat"]=wasmExports["__fxstat"])(a0,a1,a2);var ___fxstatat=Module["___fxstatat"]=(a0,a1,a2,a3,a4)=>(___fxstatat=Module["___fxstatat"]=wasmExports["__fxstatat"])(a0,a1,a2,a3,a4);var ___lxstat=Module["___lxstat"]=(a0,a1,a2)=>(___lxstat=Module["___lxstat"]=wasmExports["__lxstat"])(a0,a1,a2);var ___xstat=Module["___xstat"]=(a0,a1,a2)=>(___xstat=Module["___xstat"]=wasmExports["__xstat"])(a0,a1,a2);var ___xmknod=Module["___xmknod"]=(a0,a1,a2,a3)=>(___xmknod=Module["___xmknod"]=wasmExports["__xmknod"])(a0,a1,a2,a3);var _mknod=Module["_mknod"]=(a0,a1,a2)=>(_mknod=Module["_mknod"]=wasmExports["mknod"])(a0,a1,a2);var ___xmknodat=Module["___xmknodat"]=(a0,a1,a2,a3,a4)=>(___xmknodat=Module["___xmknodat"]=wasmExports["__xmknodat"])(a0,a1,a2,a3,a4);var _mknodat=Module["_mknodat"]=(a0,a1,a2,a3)=>(_mknodat=Module["_mknodat"]=wasmExports["mknodat"])(a0,a1,a2,a3);var _a64l=Module["_a64l"]=a0=>(_a64l=Module["_a64l"]=wasmExports["a64l"])(a0);var _l64a=Module["_l64a"]=a0=>(_l64a=Module["_l64a"]=wasmExports["l64a"])(a0);var _abs=Module["_abs"]=a0=>(_abs=Module["_abs"]=wasmExports["abs"])(a0);var _acct=Module["_acct"]=a0=>(_acct=Module["_acct"]=wasmExports["acct"])(a0);var _acosf=Module["_acosf"]=a0=>(_acosf=Module["_acosf"]=wasmExports["acosf"])(a0);var _sqrtf=Module["_sqrtf"]=a0=>(_sqrtf=Module["_sqrtf"]=wasmExports["sqrtf"])(a0);var _acoshf=Module["_acoshf"]=a0=>(_acoshf=Module["_acoshf"]=wasmExports["acoshf"])(a0);var _log1pf=Module["_log1pf"]=a0=>(_log1pf=Module["_log1pf"]=wasmExports["log1pf"])(a0);var _logf=Module["_logf"]=a0=>(_logf=Module["_logf"]=wasmExports["logf"])(a0);var _acoshl=Module["_acoshl"]=(a0,a1,a2)=>(_acoshl=Module["_acoshl"]=wasmExports["acoshl"])(a0,a1,a2);var _acosl=Module["_acosl"]=(a0,a1,a2)=>(_acosl=Module["_acosl"]=wasmExports["acosl"])(a0,a1,a2);var ___eqtf2=Module["___eqtf2"]=(a0,a1,a2,a3)=>(___eqtf2=Module["___eqtf2"]=wasmExports["__eqtf2"])(a0,a1,a2,a3);var ___netf2=Module["___netf2"]=(a0,a1,a2,a3)=>(___netf2=Module["___netf2"]=wasmExports["__netf2"])(a0,a1,a2,a3);var _sqrtl=Module["_sqrtl"]=(a0,a1,a2)=>(_sqrtl=Module["_sqrtl"]=wasmExports["sqrtl"])(a0,a1,a2);var _alarm=Module["_alarm"]=a0=>(_alarm=Module["_alarm"]=wasmExports["alarm"])(a0);var _setitimer=Module["_setitimer"]=(a0,a1,a2)=>(_setitimer=Module["_setitimer"]=wasmExports["setitimer"])(a0,a1,a2);var _aligned_alloc=Module["_aligned_alloc"]=(a0,a1)=>(_aligned_alloc=Module["_aligned_alloc"]=wasmExports["aligned_alloc"])(a0,a1);var _posix_memalign=Module["_posix_memalign"]=(a0,a1,a2)=>(_posix_memalign=Module["_posix_memalign"]=wasmExports["posix_memalign"])(a0,a1,a2);var _alphasort=Module["_alphasort"]=(a0,a1)=>(_alphasort=Module["_alphasort"]=wasmExports["alphasort"])(a0,a1);var _strcoll=Module["_strcoll"]=(a0,a1)=>(_strcoll=Module["_strcoll"]=wasmExports["strcoll"])(a0,a1);var _asctime=Module["_asctime"]=a0=>(_asctime=Module["_asctime"]=wasmExports["asctime"])(a0);var ___nl_langinfo_l=Module["___nl_langinfo_l"]=(a0,a1)=>(___nl_langinfo_l=Module["___nl_langinfo_l"]=wasmExports["__nl_langinfo_l"])(a0,a1);var _asctime_r=Module["_asctime_r"]=(a0,a1)=>(_asctime_r=Module["_asctime_r"]=wasmExports["asctime_r"])(a0,a1);var _asinf=Module["_asinf"]=a0=>(_asinf=Module["_asinf"]=wasmExports["asinf"])(a0);var _fabsf=Module["_fabsf"]=a0=>(_fabsf=Module["_fabsf"]=wasmExports["fabsf"])(a0);var _asinhf=Module["_asinhf"]=a0=>(_asinhf=Module["_asinhf"]=wasmExports["asinhf"])(a0);var _asinhl=Module["_asinhl"]=(a0,a1,a2)=>(_asinhl=Module["_asinhl"]=wasmExports["asinhl"])(a0,a1,a2);var _asinl=Module["_asinl"]=(a0,a1,a2)=>(_asinl=Module["_asinl"]=wasmExports["asinl"])(a0,a1,a2);var _asprintf=Module["_asprintf"]=(a0,a1,a2)=>(_asprintf=Module["_asprintf"]=wasmExports["asprintf"])(a0,a1,a2);var _vasprintf=Module["_vasprintf"]=(a0,a1,a2)=>(_vasprintf=Module["_vasprintf"]=wasmExports["vasprintf"])(a0,a1,a2);var ___lock=Module["___lock"]=a0=>(___lock=Module["___lock"]=wasmExports["__lock"])(a0);var ___unlock=Module["___unlock"]=a0=>(___unlock=Module["___unlock"]=wasmExports["__unlock"])(a0);var _at_quick_exit=Module["_at_quick_exit"]=a0=>(_at_quick_exit=Module["_at_quick_exit"]=wasmExports["at_quick_exit"])(a0);var _atan2f=Module["_atan2f"]=(a0,a1)=>(_atan2f=Module["_atan2f"]=wasmExports["atan2f"])(a0,a1);var _atanf=Module["_atanf"]=a0=>(_atanf=Module["_atanf"]=wasmExports["atanf"])(a0);var _atan2l=Module["_atan2l"]=(a0,a1,a2,a3,a4)=>(_atan2l=Module["_atan2l"]=wasmExports["atan2l"])(a0,a1,a2,a3,a4);var _atanl=Module["_atanl"]=(a0,a1,a2)=>(_atanl=Module["_atanl"]=wasmExports["atanl"])(a0,a1,a2);var _atanhf=Module["_atanhf"]=a0=>(_atanhf=Module["_atanhf"]=wasmExports["atanhf"])(a0);var _atanhl=Module["_atanhl"]=(a0,a1,a2)=>(_atanhl=Module["_atanhl"]=wasmExports["atanhl"])(a0,a1,a2);var _log1pl=Module["_log1pl"]=(a0,a1,a2)=>(_log1pl=Module["_log1pl"]=wasmExports["log1pl"])(a0,a1,a2);var ____cxa_finalize=Module["____cxa_finalize"]=a0=>(____cxa_finalize=Module["____cxa_finalize"]=wasmExports["___cxa_finalize"])(a0);var ____cxa_atexit=Module["____cxa_atexit"]=(a0,a1,a2)=>(____cxa_atexit=Module["____cxa_atexit"]=wasmExports["___cxa_atexit"])(a0,a1,a2);var ___libc_calloc=Module["___libc_calloc"]=(a0,a1)=>(___libc_calloc=Module["___libc_calloc"]=wasmExports["__libc_calloc"])(a0,a1);var ___atexit=Module["___atexit"]=a0=>(___atexit=Module["___atexit"]=wasmExports["__atexit"])(a0);var _atof=Module["_atof"]=a0=>(_atof=Module["_atof"]=wasmExports["atof"])(a0);var _strtod=Module["_strtod"]=(a0,a1)=>(_strtod=Module["_strtod"]=wasmExports["strtod"])(a0,a1);var _atoi=Module["_atoi"]=a0=>(_atoi=Module["_atoi"]=wasmExports["atoi"])(a0);var _atol=Module["_atol"]=a0=>(_atol=Module["_atol"]=wasmExports["atol"])(a0);var _atoll=Module["_atoll"]=a0=>(_atoll=Module["_atoll"]=wasmExports["atoll"])(a0);var _basename=Module["_basename"]=a0=>(_basename=Module["_basename"]=wasmExports["basename"])(a0);var ___xpg_basename=Module["___xpg_basename"]=a0=>(___xpg_basename=Module["___xpg_basename"]=wasmExports["__xpg_basename"])(a0);var _bcmp=Module["_bcmp"]=(a0,a1,a2)=>(_bcmp=Module["_bcmp"]=wasmExports["bcmp"])(a0,a1,a2);var _bcopy=Module["_bcopy"]=(a0,a1,a2)=>(_bcopy=Module["_bcopy"]=wasmExports["bcopy"])(a0,a1,a2);var _strcasecmp=Module["_strcasecmp"]=(a0,a1)=>(_strcasecmp=Module["_strcasecmp"]=wasmExports["strcasecmp"])(a0,a1);var _bsearch=Module["_bsearch"]=(a0,a1,a2,a3,a4)=>(_bsearch=Module["_bsearch"]=wasmExports["bsearch"])(a0,a1,a2,a3,a4);var _btowc=Module["_btowc"]=a0=>(_btowc=Module["_btowc"]=wasmExports["btowc"])(a0);var _bzero=Module["_bzero"]=(a0,a1)=>(_bzero=Module["_bzero"]=wasmExports["bzero"])(a0,a1);var _c16rtomb=Module["_c16rtomb"]=(a0,a1,a2)=>(_c16rtomb=Module["_c16rtomb"]=wasmExports["c16rtomb"])(a0,a1,a2);var _wcrtomb=Module["_wcrtomb"]=(a0,a1,a2)=>(_wcrtomb=Module["_wcrtomb"]=wasmExports["wcrtomb"])(a0,a1,a2);var _c32rtomb=Module["_c32rtomb"]=(a0,a1,a2)=>(_c32rtomb=Module["_c32rtomb"]=wasmExports["c32rtomb"])(a0,a1,a2);var _cabs=Module["_cabs"]=a0=>(_cabs=Module["_cabs"]=wasmExports["cabs"])(a0);var _cabsf=Module["_cabsf"]=a0=>(_cabsf=Module["_cabsf"]=wasmExports["cabsf"])(a0);var _hypotf=Module["_hypotf"]=(a0,a1)=>(_hypotf=Module["_hypotf"]=wasmExports["hypotf"])(a0,a1);var _cabsl=Module["_cabsl"]=(a0,a1)=>(_cabsl=Module["_cabsl"]=wasmExports["cabsl"])(a0,a1);var _hypotl=Module["_hypotl"]=(a0,a1,a2,a3,a4)=>(_hypotl=Module["_hypotl"]=wasmExports["hypotl"])(a0,a1,a2,a3,a4);var _cacos=Module["_cacos"]=(a0,a1)=>(_cacos=Module["_cacos"]=wasmExports["cacos"])(a0,a1);var _casin=Module["_casin"]=(a0,a1)=>(_casin=Module["_casin"]=wasmExports["casin"])(a0,a1);var _cacosf=Module["_cacosf"]=(a0,a1)=>(_cacosf=Module["_cacosf"]=wasmExports["cacosf"])(a0,a1);var _casinf=Module["_casinf"]=(a0,a1)=>(_casinf=Module["_casinf"]=wasmExports["casinf"])(a0,a1);var _cacosh=Module["_cacosh"]=(a0,a1)=>(_cacosh=Module["_cacosh"]=wasmExports["cacosh"])(a0,a1);var _cacoshf=Module["_cacoshf"]=(a0,a1)=>(_cacoshf=Module["_cacoshf"]=wasmExports["cacoshf"])(a0,a1);var _cacoshl=Module["_cacoshl"]=(a0,a1)=>(_cacoshl=Module["_cacoshl"]=wasmExports["cacoshl"])(a0,a1);var _cacosl=Module["_cacosl"]=(a0,a1)=>(_cacosl=Module["_cacosl"]=wasmExports["cacosl"])(a0,a1);var _casinl=Module["_casinl"]=(a0,a1)=>(_casinl=Module["_casinl"]=wasmExports["casinl"])(a0,a1);var _call_once=Module["_call_once"]=(a0,a1)=>(_call_once=Module["_call_once"]=wasmExports["call_once"])(a0,a1);var _carg=Module["_carg"]=a0=>(_carg=Module["_carg"]=wasmExports["carg"])(a0);var _cargf=Module["_cargf"]=a0=>(_cargf=Module["_cargf"]=wasmExports["cargf"])(a0);var _cargl=Module["_cargl"]=(a0,a1)=>(_cargl=Module["_cargl"]=wasmExports["cargl"])(a0,a1);var _csqrt=Module["_csqrt"]=(a0,a1)=>(_csqrt=Module["_csqrt"]=wasmExports["csqrt"])(a0,a1);var _clog=Module["_clog"]=(a0,a1)=>(_clog=Module["_clog"]=wasmExports["clog"])(a0,a1);var _csqrtf=Module["_csqrtf"]=(a0,a1)=>(_csqrtf=Module["_csqrtf"]=wasmExports["csqrtf"])(a0,a1);var _clogf=Module["_clogf"]=(a0,a1)=>(_clogf=Module["_clogf"]=wasmExports["clogf"])(a0,a1);var _casinh=Module["_casinh"]=(a0,a1)=>(_casinh=Module["_casinh"]=wasmExports["casinh"])(a0,a1);var _casinhf=Module["_casinhf"]=(a0,a1)=>(_casinhf=Module["_casinhf"]=wasmExports["casinhf"])(a0,a1);var _casinhl=Module["_casinhl"]=(a0,a1)=>(_casinhl=Module["_casinhl"]=wasmExports["casinhl"])(a0,a1);var _csqrtl=Module["_csqrtl"]=(a0,a1)=>(_csqrtl=Module["_csqrtl"]=wasmExports["csqrtl"])(a0,a1);var _clogl=Module["_clogl"]=(a0,a1)=>(_clogl=Module["_clogl"]=wasmExports["clogl"])(a0,a1);var _catan=Module["_catan"]=(a0,a1)=>(_catan=Module["_catan"]=wasmExports["catan"])(a0,a1);var _catanf=Module["_catanf"]=(a0,a1)=>(_catanf=Module["_catanf"]=wasmExports["catanf"])(a0,a1);var _catanh=Module["_catanh"]=(a0,a1)=>(_catanh=Module["_catanh"]=wasmExports["catanh"])(a0,a1);var _catanhf=Module["_catanhf"]=(a0,a1)=>(_catanhf=Module["_catanhf"]=wasmExports["catanhf"])(a0,a1);var _catanhl=Module["_catanhl"]=(a0,a1)=>(_catanhl=Module["_catanhl"]=wasmExports["catanhl"])(a0,a1);var _catanl=Module["_catanl"]=(a0,a1)=>(_catanl=Module["_catanl"]=wasmExports["catanl"])(a0,a1);var _logl=Module["_logl"]=(a0,a1,a2)=>(_logl=Module["_logl"]=wasmExports["logl"])(a0,a1,a2);var ___trunctfsf2=Module["___trunctfsf2"]=(a0,a1)=>(___trunctfsf2=Module["___trunctfsf2"]=wasmExports["__trunctfsf2"])(a0,a1);var ___extendsftf2=Module["___extendsftf2"]=(a0,a1)=>(___extendsftf2=Module["___extendsftf2"]=wasmExports["__extendsftf2"])(a0,a1);var _catclose=Module["_catclose"]=a0=>(_catclose=Module["_catclose"]=wasmExports["catclose"])(a0);var _catgets=Module["_catgets"]=(a0,a1,a2,a3)=>(_catgets=Module["_catgets"]=wasmExports["catgets"])(a0,a1,a2,a3);var _catopen=Module["_catopen"]=(a0,a1)=>(_catopen=Module["_catopen"]=wasmExports["catopen"])(a0,a1);var _cbrtf=Module["_cbrtf"]=a0=>(_cbrtf=Module["_cbrtf"]=wasmExports["cbrtf"])(a0);var _cbrtl=Module["_cbrtl"]=(a0,a1,a2)=>(_cbrtl=Module["_cbrtl"]=wasmExports["cbrtl"])(a0,a1,a2);var _ccos=Module["_ccos"]=(a0,a1)=>(_ccos=Module["_ccos"]=wasmExports["ccos"])(a0,a1);var _ccosh=Module["_ccosh"]=(a0,a1)=>(_ccosh=Module["_ccosh"]=wasmExports["ccosh"])(a0,a1);var _ccosf=Module["_ccosf"]=(a0,a1)=>(_ccosf=Module["_ccosf"]=wasmExports["ccosf"])(a0,a1);var _ccoshf=Module["_ccoshf"]=(a0,a1)=>(_ccoshf=Module["_ccoshf"]=wasmExports["ccoshf"])(a0,a1);var _coshf=Module["_coshf"]=a0=>(_coshf=Module["_coshf"]=wasmExports["coshf"])(a0);var _sinhf=Module["_sinhf"]=a0=>(_sinhf=Module["_sinhf"]=wasmExports["sinhf"])(a0);var _copysignf=Module["_copysignf"]=(a0,a1)=>(_copysignf=Module["_copysignf"]=wasmExports["copysignf"])(a0,a1);var _ccoshl=Module["_ccoshl"]=(a0,a1)=>(_ccoshl=Module["_ccoshl"]=wasmExports["ccoshl"])(a0,a1);var _ccosl=Module["_ccosl"]=(a0,a1)=>(_ccosl=Module["_ccosl"]=wasmExports["ccosl"])(a0,a1);var _ceil=Module["_ceil"]=a0=>(_ceil=Module["_ceil"]=wasmExports["ceil"])(a0);var _ceilf=Module["_ceilf"]=a0=>(_ceilf=Module["_ceilf"]=wasmExports["ceilf"])(a0);var _ceill=Module["_ceill"]=(a0,a1,a2)=>(_ceill=Module["_ceill"]=wasmExports["ceill"])(a0,a1,a2);var _cexp=Module["_cexp"]=(a0,a1)=>(_cexp=Module["_cexp"]=wasmExports["cexp"])(a0,a1);var _cexpf=Module["_cexpf"]=(a0,a1)=>(_cexpf=Module["_cexpf"]=wasmExports["cexpf"])(a0,a1);var _cexpl=Module["_cexpl"]=(a0,a1)=>(_cexpl=Module["_cexpl"]=wasmExports["cexpl"])(a0,a1);var _cfgetospeed=Module["_cfgetospeed"]=a0=>(_cfgetospeed=Module["_cfgetospeed"]=wasmExports["cfgetospeed"])(a0);var _cfgetispeed=Module["_cfgetispeed"]=a0=>(_cfgetispeed=Module["_cfgetispeed"]=wasmExports["cfgetispeed"])(a0);var _cfmakeraw=Module["_cfmakeraw"]=a0=>(_cfmakeraw=Module["_cfmakeraw"]=wasmExports["cfmakeraw"])(a0);var _cfsetospeed=Module["_cfsetospeed"]=(a0,a1)=>(_cfsetospeed=Module["_cfsetospeed"]=wasmExports["cfsetospeed"])(a0,a1);var _cfsetispeed=Module["_cfsetispeed"]=(a0,a1)=>(_cfsetispeed=Module["_cfsetispeed"]=wasmExports["cfsetispeed"])(a0,a1);var _cfsetspeed=Module["_cfsetspeed"]=(a0,a1)=>(_cfsetspeed=Module["_cfsetspeed"]=wasmExports["cfsetspeed"])(a0,a1);var _cimag=Module["_cimag"]=a0=>(_cimag=Module["_cimag"]=wasmExports["cimag"])(a0);var _cimagf=Module["_cimagf"]=a0=>(_cimagf=Module["_cimagf"]=wasmExports["cimagf"])(a0);var _cimagl=Module["_cimagl"]=(a0,a1)=>(_cimagl=Module["_cimagl"]=wasmExports["cimagl"])(a0,a1);var _clearenv=Module["_clearenv"]=()=>(_clearenv=Module["_clearenv"]=wasmExports["clearenv"])();var _clearerr_unlocked=Module["_clearerr_unlocked"]=a0=>(_clearerr_unlocked=Module["_clearerr_unlocked"]=wasmExports["clearerr_unlocked"])(a0);var _emscripten_thread_sleep=Module["_emscripten_thread_sleep"]=a0=>(_emscripten_thread_sleep=Module["_emscripten_thread_sleep"]=wasmExports["emscripten_thread_sleep"])(a0);var _cnd_broadcast=Module["_cnd_broadcast"]=a0=>(_cnd_broadcast=Module["_cnd_broadcast"]=wasmExports["cnd_broadcast"])(a0);var _cnd_destroy=Module["_cnd_destroy"]=a0=>(_cnd_destroy=Module["_cnd_destroy"]=wasmExports["cnd_destroy"])(a0);var _cnd_init=Module["_cnd_init"]=a0=>(_cnd_init=Module["_cnd_init"]=wasmExports["cnd_init"])(a0);var _cnd_signal=Module["_cnd_signal"]=a0=>(_cnd_signal=Module["_cnd_signal"]=wasmExports["cnd_signal"])(a0);var _cnd_timedwait=Module["_cnd_timedwait"]=(a0,a1,a2)=>(_cnd_timedwait=Module["_cnd_timedwait"]=wasmExports["cnd_timedwait"])(a0,a1,a2);var _cnd_wait=Module["_cnd_wait"]=(a0,a1)=>(_cnd_wait=Module["_cnd_wait"]=wasmExports["cnd_wait"])(a0,a1);var _conj=Module["_conj"]=(a0,a1)=>(_conj=Module["_conj"]=wasmExports["conj"])(a0,a1);var _conjf=Module["_conjf"]=(a0,a1)=>(_conjf=Module["_conjf"]=wasmExports["conjf"])(a0,a1);var _conjl=Module["_conjl"]=(a0,a1)=>(_conjl=Module["_conjl"]=wasmExports["conjl"])(a0,a1);var _copysignl=Module["_copysignl"]=(a0,a1,a2,a3,a4)=>(_copysignl=Module["_copysignl"]=wasmExports["copysignl"])(a0,a1,a2,a3,a4);var _expm1f=Module["_expm1f"]=a0=>(_expm1f=Module["_expm1f"]=wasmExports["expm1f"])(a0);var _coshl=Module["_coshl"]=(a0,a1,a2)=>(_coshl=Module["_coshl"]=wasmExports["coshl"])(a0,a1,a2);var _cosl=Module["_cosl"]=(a0,a1,a2)=>(_cosl=Module["_cosl"]=wasmExports["cosl"])(a0,a1,a2);var _cpow=Module["_cpow"]=(a0,a1,a2)=>(_cpow=Module["_cpow"]=wasmExports["cpow"])(a0,a1,a2);var ___muldc3=Module["___muldc3"]=(a0,a1,a2,a3,a4)=>(___muldc3=Module["___muldc3"]=wasmExports["__muldc3"])(a0,a1,a2,a3,a4);var _cpowf=Module["_cpowf"]=(a0,a1,a2)=>(_cpowf=Module["_cpowf"]=wasmExports["cpowf"])(a0,a1,a2);var ___mulsc3=Module["___mulsc3"]=(a0,a1,a2,a3,a4)=>(___mulsc3=Module["___mulsc3"]=wasmExports["__mulsc3"])(a0,a1,a2,a3,a4);var _cpowl=Module["_cpowl"]=(a0,a1,a2)=>(_cpowl=Module["_cpowl"]=wasmExports["cpowl"])(a0,a1,a2);var ___unordtf2=Module["___unordtf2"]=(a0,a1,a2,a3)=>(___unordtf2=Module["___unordtf2"]=wasmExports["__unordtf2"])(a0,a1,a2,a3);var ___multc3=Module["___multc3"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(___multc3=Module["___multc3"]=wasmExports["__multc3"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var _cproj=Module["_cproj"]=(a0,a1)=>(_cproj=Module["_cproj"]=wasmExports["cproj"])(a0,a1);var _cprojf=Module["_cprojf"]=(a0,a1)=>(_cprojf=Module["_cprojf"]=wasmExports["cprojf"])(a0,a1);var _cprojl=Module["_cprojl"]=(a0,a1)=>(_cprojl=Module["_cprojl"]=wasmExports["cprojl"])(a0,a1);var _creal=Module["_creal"]=a0=>(_creal=Module["_creal"]=wasmExports["creal"])(a0);var _crealf=Module["_crealf"]=a0=>(_crealf=Module["_crealf"]=wasmExports["crealf"])(a0);var _creall=Module["_creall"]=(a0,a1)=>(_creall=Module["_creall"]=wasmExports["creall"])(a0,a1);var _creat=Module["_creat"]=(a0,a1)=>(_creat=Module["_creat"]=wasmExports["creat"])(a0,a1);var _crypt=Module["_crypt"]=(a0,a1)=>(_crypt=Module["_crypt"]=wasmExports["crypt"])(a0,a1);var ___crypt_blowfish=Module["___crypt_blowfish"]=(a0,a1,a2)=>(___crypt_blowfish=Module["___crypt_blowfish"]=wasmExports["__crypt_blowfish"])(a0,a1,a2);var ___crypt_des=Module["___crypt_des"]=(a0,a1,a2)=>(___crypt_des=Module["___crypt_des"]=wasmExports["__crypt_des"])(a0,a1,a2);var ___crypt_md5=Module["___crypt_md5"]=(a0,a1,a2)=>(___crypt_md5=Module["___crypt_md5"]=wasmExports["__crypt_md5"])(a0,a1,a2);var _strnlen=Module["_strnlen"]=(a0,a1)=>(_strnlen=Module["_strnlen"]=wasmExports["strnlen"])(a0,a1);var ___crypt_sha256=Module["___crypt_sha256"]=(a0,a1,a2)=>(___crypt_sha256=Module["___crypt_sha256"]=wasmExports["__crypt_sha256"])(a0,a1,a2);var ___crypt_sha512=Module["___crypt_sha512"]=(a0,a1,a2)=>(___crypt_sha512=Module["___crypt_sha512"]=wasmExports["__crypt_sha512"])(a0,a1,a2);var _sprintf=Module["_sprintf"]=(a0,a1,a2)=>(_sprintf=Module["_sprintf"]=wasmExports["sprintf"])(a0,a1,a2);var _csin=Module["_csin"]=(a0,a1)=>(_csin=Module["_csin"]=wasmExports["csin"])(a0,a1);var _csinh=Module["_csinh"]=(a0,a1)=>(_csinh=Module["_csinh"]=wasmExports["csinh"])(a0,a1);var _csinf=Module["_csinf"]=(a0,a1)=>(_csinf=Module["_csinf"]=wasmExports["csinf"])(a0,a1);var _csinhf=Module["_csinhf"]=(a0,a1)=>(_csinhf=Module["_csinhf"]=wasmExports["csinhf"])(a0,a1);var _csinhl=Module["_csinhl"]=(a0,a1)=>(_csinhl=Module["_csinhl"]=wasmExports["csinhl"])(a0,a1);var _csinl=Module["_csinl"]=(a0,a1)=>(_csinl=Module["_csinl"]=wasmExports["csinl"])(a0,a1);var _ctan=Module["_ctan"]=(a0,a1)=>(_ctan=Module["_ctan"]=wasmExports["ctan"])(a0,a1);var _ctanh=Module["_ctanh"]=(a0,a1)=>(_ctanh=Module["_ctanh"]=wasmExports["ctanh"])(a0,a1);var _ctanf=Module["_ctanf"]=(a0,a1)=>(_ctanf=Module["_ctanf"]=wasmExports["ctanf"])(a0,a1);var _ctanhf=Module["_ctanhf"]=(a0,a1)=>(_ctanhf=Module["_ctanhf"]=wasmExports["ctanhf"])(a0,a1);var _tanf=Module["_tanf"]=a0=>(_tanf=Module["_tanf"]=wasmExports["tanf"])(a0);var _ctanhl=Module["_ctanhl"]=(a0,a1)=>(_ctanhl=Module["_ctanhl"]=wasmExports["ctanhl"])(a0,a1);var _ctanl=Module["_ctanl"]=(a0,a1)=>(_ctanl=Module["_ctanl"]=wasmExports["ctanl"])(a0,a1);var _ctime=Module["_ctime"]=a0=>(_ctime=Module["_ctime"]=wasmExports["ctime"])(a0);var _localtime=Module["_localtime"]=a0=>(_localtime=Module["_localtime"]=wasmExports["localtime"])(a0);var _ctime_r=Module["_ctime_r"]=(a0,a1)=>(_ctime_r=Module["_ctime_r"]=wasmExports["ctime_r"])(a0,a1);var _dcngettext=Module["_dcngettext"]=(a0,a1,a2,a3,a4)=>(_dcngettext=Module["_dcngettext"]=wasmExports["dcngettext"])(a0,a1,a2,a3,a4);var ___gettextdomain=Module["___gettextdomain"]=()=>(___gettextdomain=Module["___gettextdomain"]=wasmExports["__gettextdomain"])();var _dngettext=Module["_dngettext"]=(a0,a1,a2,a3)=>(_dngettext=Module["_dngettext"]=wasmExports["dngettext"])(a0,a1,a2,a3);var _difftime=Module["_difftime"]=(a0,a1)=>(_difftime=Module["_difftime"]=wasmExports["difftime"])(a0,a1);var _dirname=Module["_dirname"]=a0=>(_dirname=Module["_dirname"]=wasmExports["dirname"])(a0);var _div=Module["_div"]=(a0,a1,a2)=>(_div=Module["_div"]=wasmExports["div"])(a0,a1,a2);var _dladdr=Module["_dladdr"]=(a0,a1)=>(_dladdr=Module["_dladdr"]=wasmExports["dladdr"])(a0,a1);var ___libc_free=Module["___libc_free"]=a0=>(___libc_free=Module["___libc_free"]=wasmExports["__libc_free"])(a0);var ___libc_malloc=Module["___libc_malloc"]=a0=>(___libc_malloc=Module["___libc_malloc"]=wasmExports["__libc_malloc"])(a0);var ___dl_seterr=(a0,a1)=>(___dl_seterr=wasmExports["__dl_seterr"])(a0,a1);var _dn_comp=Module["_dn_comp"]=(a0,a1,a2,a3,a4)=>(_dn_comp=Module["_dn_comp"]=wasmExports["dn_comp"])(a0,a1,a2,a3,a4);var _dn_expand=Module["_dn_expand"]=(a0,a1,a2,a3,a4)=>(_dn_expand=Module["_dn_expand"]=wasmExports["dn_expand"])(a0,a1,a2,a3,a4);var _dn_skipname=Module["_dn_skipname"]=(a0,a1)=>(_dn_skipname=Module["_dn_skipname"]=wasmExports["dn_skipname"])(a0,a1);var _dprintf=Module["_dprintf"]=(a0,a1,a2)=>(_dprintf=Module["_dprintf"]=wasmExports["dprintf"])(a0,a1,a2);var _vdprintf=Module["_vdprintf"]=(a0,a1,a2)=>(_vdprintf=Module["_vdprintf"]=wasmExports["vdprintf"])(a0,a1,a2);var _erand48=Module["_erand48"]=a0=>(_erand48=Module["_erand48"]=wasmExports["erand48"])(a0);var _drand48=Module["_drand48"]=()=>(_drand48=Module["_drand48"]=wasmExports["drand48"])();var ___wasi_fd_is_valid=Module["___wasi_fd_is_valid"]=a0=>(___wasi_fd_is_valid=Module["___wasi_fd_is_valid"]=wasmExports["__wasi_fd_is_valid"])(a0);var ___duplocale=Module["___duplocale"]=a0=>(___duplocale=Module["___duplocale"]=wasmExports["__duplocale"])(a0);var _duplocale=Module["_duplocale"]=a0=>(_duplocale=Module["_duplocale"]=wasmExports["duplocale"])(a0);var _new_dlevent=Module["_new_dlevent"]=(a0,a1)=>(_new_dlevent=Module["_new_dlevent"]=wasmExports["new_dlevent"])(a0,a1);var _pthread_setcancelstate=Module["_pthread_setcancelstate"]=(a0,a1)=>(_pthread_setcancelstate=Module["_pthread_setcancelstate"]=wasmExports["pthread_setcancelstate"])(a0,a1);var _emscripten_dlopen=Module["_emscripten_dlopen"]=(a0,a1,a2,a3,a4)=>(_emscripten_dlopen=Module["_emscripten_dlopen"]=wasmExports["emscripten_dlopen"])(a0,a1,a2,a3,a4);var _emscripten_dlopen_promise=Module["_emscripten_dlopen_promise"]=(a0,a1)=>(_emscripten_dlopen_promise=Module["_emscripten_dlopen_promise"]=wasmExports["emscripten_dlopen_promise"])(a0,a1);var _strspn=Module["_strspn"]=(a0,a1)=>(_strspn=Module["_strspn"]=wasmExports["strspn"])(a0,a1);var _ecvt=Module["_ecvt"]=(a0,a1,a2,a3)=>(_ecvt=Module["_ecvt"]=wasmExports["ecvt"])(a0,a1,a2,a3);var _emscripten_console_logf=Module["_emscripten_console_logf"]=(a0,a1)=>(_emscripten_console_logf=Module["_emscripten_console_logf"]=wasmExports["emscripten_console_logf"])(a0,a1);var _emscripten_console_errorf=Module["_emscripten_console_errorf"]=(a0,a1)=>(_emscripten_console_errorf=Module["_emscripten_console_errorf"]=wasmExports["emscripten_console_errorf"])(a0,a1);var _emscripten_console_warnf=Module["_emscripten_console_warnf"]=(a0,a1)=>(_emscripten_console_warnf=Module["_emscripten_console_warnf"]=wasmExports["emscripten_console_warnf"])(a0,a1);var _emscripten_outf=Module["_emscripten_outf"]=(a0,a1)=>(_emscripten_outf=Module["_emscripten_outf"]=wasmExports["emscripten_outf"])(a0,a1);var _emscripten_errf=Module["_emscripten_errf"]=(a0,a1)=>(_emscripten_errf=Module["_emscripten_errf"]=wasmExports["emscripten_errf"])(a0,a1);var _emscripten_fiber_init=Module["_emscripten_fiber_init"]=(a0,a1,a2,a3,a4,a5,a6)=>(_emscripten_fiber_init=Module["_emscripten_fiber_init"]=wasmExports["emscripten_fiber_init"])(a0,a1,a2,a3,a4,a5,a6);var _emscripten_fiber_init_from_current_context=Module["_emscripten_fiber_init_from_current_context"]=(a0,a1,a2)=>(_emscripten_fiber_init_from_current_context=Module["_emscripten_fiber_init_from_current_context"]=wasmExports["emscripten_fiber_init_from_current_context"])(a0,a1,a2);var _emscripten_stack_get_base=Module["_emscripten_stack_get_base"]=()=>(_emscripten_stack_get_base=Module["_emscripten_stack_get_base"]=wasmExports["emscripten_stack_get_base"])();var _emscripten_stack_get_end=Module["_emscripten_stack_get_end"]=()=>(_emscripten_stack_get_end=Module["_emscripten_stack_get_end"]=wasmExports["emscripten_stack_get_end"])();var _emscripten_get_heap_size=Module["_emscripten_get_heap_size"]=()=>(_emscripten_get_heap_size=Module["_emscripten_get_heap_size"]=wasmExports["emscripten_get_heap_size"])();var ___syscall_munmap=Module["___syscall_munmap"]=(a0,a1)=>(___syscall_munmap=Module["___syscall_munmap"]=wasmExports["__syscall_munmap"])(a0,a1);var _emscripten_builtin_free=Module["_emscripten_builtin_free"]=a0=>(_emscripten_builtin_free=Module["_emscripten_builtin_free"]=wasmExports["emscripten_builtin_free"])(a0);var ___syscall_msync=Module["___syscall_msync"]=(a0,a1,a2)=>(___syscall_msync=Module["___syscall_msync"]=wasmExports["__syscall_msync"])(a0,a1,a2);var ___syscall_mmap2=Module["___syscall_mmap2"]=(a0,a1,a2,a3,a4,a5)=>(___syscall_mmap2=Module["___syscall_mmap2"]=wasmExports["__syscall_mmap2"])(a0,a1,a2,a3,a4,a5);var _emscripten_builtin_memalign=(a0,a1)=>(_emscripten_builtin_memalign=wasmExports["emscripten_builtin_memalign"])(a0,a1);var _emscripten_scan_stack=Module["_emscripten_scan_stack"]=a0=>(_emscripten_scan_stack=Module["_emscripten_scan_stack"]=wasmExports["emscripten_scan_stack"])(a0);var _emscripten_stack_get_current=()=>(_emscripten_stack_get_current=wasmExports["emscripten_stack_get_current"])();var ___clock=Module["___clock"]=()=>(___clock=Module["___clock"]=wasmExports["__clock"])();var ___time=Module["___time"]=a0=>(___time=Module["___time"]=wasmExports["__time"])(a0);var ___clock_getres=Module["___clock_getres"]=(a0,a1)=>(___clock_getres=Module["___clock_getres"]=wasmExports["__clock_getres"])(a0,a1);var ___gettimeofday=Module["___gettimeofday"]=(a0,a1)=>(___gettimeofday=Module["___gettimeofday"]=wasmExports["__gettimeofday"])(a0,a1);var _dysize=Module["_dysize"]=a0=>(_dysize=Module["_dysize"]=wasmExports["dysize"])(a0);var _setkey=Module["_setkey"]=a0=>(_setkey=Module["_setkey"]=wasmExports["setkey"])(a0);var _encrypt=Module["_encrypt"]=(a0,a1)=>(_encrypt=Module["_encrypt"]=wasmExports["encrypt"])(a0,a1);var _sethostent=Module["_sethostent"]=a0=>(_sethostent=Module["_sethostent"]=wasmExports["sethostent"])(a0);var _gethostent=Module["_gethostent"]=()=>(_gethostent=Module["_gethostent"]=wasmExports["gethostent"])();var _getnetent=Module["_getnetent"]=()=>(_getnetent=Module["_getnetent"]=wasmExports["getnetent"])();var _endhostent=Module["_endhostent"]=()=>(_endhostent=Module["_endhostent"]=wasmExports["endhostent"])();var _setnetent=Module["_setnetent"]=a0=>(_setnetent=Module["_setnetent"]=wasmExports["setnetent"])(a0);var _endnetent=Module["_endnetent"]=()=>(_endnetent=Module["_endnetent"]=wasmExports["endnetent"])();var _erff=Module["_erff"]=a0=>(_erff=Module["_erff"]=wasmExports["erff"])(a0);var _erfcf=Module["_erfcf"]=a0=>(_erfcf=Module["_erfcf"]=wasmExports["erfcf"])(a0);var _erfl=Module["_erfl"]=(a0,a1,a2)=>(_erfl=Module["_erfl"]=wasmExports["erfl"])(a0,a1,a2);var _erfcl=Module["_erfcl"]=(a0,a1,a2)=>(_erfcl=Module["_erfcl"]=wasmExports["erfcl"])(a0,a1,a2);var _vwarn=Module["_vwarn"]=(a0,a1)=>(_vwarn=Module["_vwarn"]=wasmExports["vwarn"])(a0,a1);var _fprintf=Module["_fprintf"]=(a0,a1,a2)=>(_fprintf=Module["_fprintf"]=wasmExports["fprintf"])(a0,a1,a2);var _vwarnx=Module["_vwarnx"]=(a0,a1)=>(_vwarnx=Module["_vwarnx"]=wasmExports["vwarnx"])(a0,a1);var _putc=Module["_putc"]=(a0,a1)=>(_putc=Module["_putc"]=wasmExports["putc"])(a0,a1);var _verr=Module["_verr"]=(a0,a1,a2)=>(_verr=Module["_verr"]=wasmExports["verr"])(a0,a1,a2);var _verrx=Module["_verrx"]=(a0,a1,a2)=>(_verrx=Module["_verrx"]=wasmExports["verrx"])(a0,a1,a2);var _warn=Module["_warn"]=(a0,a1)=>(_warn=Module["_warn"]=wasmExports["warn"])(a0,a1);var _warnx=Module["_warnx"]=(a0,a1)=>(_warnx=Module["_warnx"]=wasmExports["warnx"])(a0,a1);var _err=Module["_err"]=(a0,a1,a2)=>(_err=Module["_err"]=wasmExports["err"])(a0,a1,a2);var _errx=Module["_errx"]=(a0,a1,a2)=>(_errx=Module["_errx"]=wasmExports["errx"])(a0,a1,a2);var _ether_aton_r=Module["_ether_aton_r"]=(a0,a1)=>(_ether_aton_r=Module["_ether_aton_r"]=wasmExports["ether_aton_r"])(a0,a1);var _ether_aton=Module["_ether_aton"]=a0=>(_ether_aton=Module["_ether_aton"]=wasmExports["ether_aton"])(a0);var _ether_ntoa_r=Module["_ether_ntoa_r"]=(a0,a1)=>(_ether_ntoa_r=Module["_ether_ntoa_r"]=wasmExports["ether_ntoa_r"])(a0,a1);var _ether_ntoa=Module["_ether_ntoa"]=a0=>(_ether_ntoa=Module["_ether_ntoa"]=wasmExports["ether_ntoa"])(a0);var _ether_line=Module["_ether_line"]=(a0,a1,a2)=>(_ether_line=Module["_ether_line"]=wasmExports["ether_line"])(a0,a1,a2);var _ether_ntohost=Module["_ether_ntohost"]=(a0,a1)=>(_ether_ntohost=Module["_ether_ntohost"]=wasmExports["ether_ntohost"])(a0,a1);var _ether_hostton=Module["_ether_hostton"]=(a0,a1)=>(_ether_hostton=Module["_ether_hostton"]=wasmExports["ether_hostton"])(a0,a1);var _execl=Module["_execl"]=(a0,a1,a2)=>(_execl=Module["_execl"]=wasmExports["execl"])(a0,a1,a2);var _execle=Module["_execle"]=(a0,a1,a2)=>(_execle=Module["_execle"]=wasmExports["execle"])(a0,a1,a2);var _execlp=Module["_execlp"]=(a0,a1,a2)=>(_execlp=Module["_execlp"]=wasmExports["execlp"])(a0,a1,a2);var _execvp=Module["_execvp"]=(a0,a1)=>(_execvp=Module["_execvp"]=wasmExports["execvp"])(a0,a1);var _execvpe=Module["_execvpe"]=(a0,a1,a2)=>(_execvpe=Module["_execvpe"]=wasmExports["execvpe"])(a0,a1,a2);var _exp10=Module["_exp10"]=a0=>(_exp10=Module["_exp10"]=wasmExports["exp10"])(a0);var _pow10=Module["_pow10"]=a0=>(_pow10=Module["_pow10"]=wasmExports["pow10"])(a0);var _exp10f=Module["_exp10f"]=a0=>(_exp10f=Module["_exp10f"]=wasmExports["exp10f"])(a0);var _modff=Module["_modff"]=(a0,a1)=>(_modff=Module["_modff"]=wasmExports["modff"])(a0,a1);var _exp2f=Module["_exp2f"]=a0=>(_exp2f=Module["_exp2f"]=wasmExports["exp2f"])(a0);var _pow10f=Module["_pow10f"]=a0=>(_pow10f=Module["_pow10f"]=wasmExports["pow10f"])(a0);var _exp10l=Module["_exp10l"]=(a0,a1,a2)=>(_exp10l=Module["_exp10l"]=wasmExports["exp10l"])(a0,a1,a2);var _modfl=Module["_modfl"]=(a0,a1,a2,a3)=>(_modfl=Module["_modfl"]=wasmExports["modfl"])(a0,a1,a2,a3);var _exp2l=Module["_exp2l"]=(a0,a1,a2)=>(_exp2l=Module["_exp2l"]=wasmExports["exp2l"])(a0,a1,a2);var _powl=Module["_powl"]=(a0,a1,a2,a3,a4)=>(_powl=Module["_powl"]=wasmExports["powl"])(a0,a1,a2,a3,a4);var _pow10l=Module["_pow10l"]=(a0,a1,a2)=>(_pow10l=Module["_pow10l"]=wasmExports["pow10l"])(a0,a1,a2);var ___letf2=Module["___letf2"]=(a0,a1,a2,a3)=>(___letf2=Module["___letf2"]=wasmExports["__letf2"])(a0,a1,a2,a3);var _scalbnl=Module["_scalbnl"]=(a0,a1,a2,a3)=>(_scalbnl=Module["_scalbnl"]=wasmExports["scalbnl"])(a0,a1,a2,a3);var _expl=Module["_expl"]=(a0,a1,a2)=>(_expl=Module["_expl"]=wasmExports["expl"])(a0,a1,a2);var _expm1l=Module["_expm1l"]=(a0,a1,a2)=>(_expm1l=Module["_expm1l"]=wasmExports["expm1l"])(a0,a1,a2);var __flushlbf=Module["__flushlbf"]=()=>(__flushlbf=Module["__flushlbf"]=wasmExports["_flushlbf"])();var ___fsetlocking=Module["___fsetlocking"]=(a0,a1)=>(___fsetlocking=Module["___fsetlocking"]=wasmExports["__fsetlocking"])(a0,a1);var ___fwriting=Module["___fwriting"]=a0=>(___fwriting=Module["___fwriting"]=wasmExports["__fwriting"])(a0);var ___freading=Module["___freading"]=a0=>(___freading=Module["___freading"]=wasmExports["__freading"])(a0);var ___freadable=Module["___freadable"]=a0=>(___freadable=Module["___freadable"]=wasmExports["__freadable"])(a0);var ___fwritable=Module["___fwritable"]=a0=>(___fwritable=Module["___fwritable"]=wasmExports["__fwritable"])(a0);var ___flbf=Module["___flbf"]=a0=>(___flbf=Module["___flbf"]=wasmExports["__flbf"])(a0);var ___fbufsize=Module["___fbufsize"]=a0=>(___fbufsize=Module["___fbufsize"]=wasmExports["__fbufsize"])(a0);var ___fpending=Module["___fpending"]=a0=>(___fpending=Module["___fpending"]=wasmExports["__fpending"])(a0);var ___fpurge=Module["___fpurge"]=a0=>(___fpurge=Module["___fpurge"]=wasmExports["__fpurge"])(a0);var _fpurge=Module["_fpurge"]=a0=>(_fpurge=Module["_fpurge"]=wasmExports["fpurge"])(a0);var ___freadahead=Module["___freadahead"]=a0=>(___freadahead=Module["___freadahead"]=wasmExports["__freadahead"])(a0);var ___freadptr=Module["___freadptr"]=(a0,a1)=>(___freadptr=Module["___freadptr"]=wasmExports["__freadptr"])(a0,a1);var ___freadptrinc=Module["___freadptrinc"]=(a0,a1)=>(___freadptrinc=Module["___freadptrinc"]=wasmExports["__freadptrinc"])(a0,a1);var ___fseterr=Module["___fseterr"]=a0=>(___fseterr=Module["___fseterr"]=wasmExports["__fseterr"])(a0);var _faccessat=Module["_faccessat"]=(a0,a1,a2,a3)=>(_faccessat=Module["_faccessat"]=wasmExports["faccessat"])(a0,a1,a2,a3);var _fcvt=Module["_fcvt"]=(a0,a1,a2,a3)=>(_fcvt=Module["_fcvt"]=wasmExports["fcvt"])(a0,a1,a2,a3);var _fdim=Module["_fdim"]=(a0,a1)=>(_fdim=Module["_fdim"]=wasmExports["fdim"])(a0,a1);var _fdimf=Module["_fdimf"]=(a0,a1)=>(_fdimf=Module["_fdimf"]=wasmExports["fdimf"])(a0,a1);var _fdiml=Module["_fdiml"]=(a0,a1,a2,a3,a4)=>(_fdiml=Module["_fdiml"]=wasmExports["fdiml"])(a0,a1,a2,a3,a4);var _fegetexceptflag=Module["_fegetexceptflag"]=(a0,a1)=>(_fegetexceptflag=Module["_fegetexceptflag"]=wasmExports["fegetexceptflag"])(a0,a1);var _fetestexcept=Module["_fetestexcept"]=a0=>(_fetestexcept=Module["_fetestexcept"]=wasmExports["fetestexcept"])(a0);var _feholdexcept=Module["_feholdexcept"]=a0=>(_feholdexcept=Module["_feholdexcept"]=wasmExports["feholdexcept"])(a0);var _fegetenv=Module["_fegetenv"]=a0=>(_fegetenv=Module["_fegetenv"]=wasmExports["fegetenv"])(a0);var _feclearexcept=Module["_feclearexcept"]=a0=>(_feclearexcept=Module["_feclearexcept"]=wasmExports["feclearexcept"])(a0);var _feraiseexcept=Module["_feraiseexcept"]=a0=>(_feraiseexcept=Module["_feraiseexcept"]=wasmExports["feraiseexcept"])(a0);var ___fesetround=Module["___fesetround"]=a0=>(___fesetround=Module["___fesetround"]=wasmExports["__fesetround"])(a0);var _fesetenv=Module["_fesetenv"]=a0=>(_fesetenv=Module["_fesetenv"]=wasmExports["fesetenv"])(a0);var _feof_unlocked=Module["_feof_unlocked"]=a0=>(_feof_unlocked=Module["_feof_unlocked"]=wasmExports["feof_unlocked"])(a0);var __IO_feof_unlocked=Module["__IO_feof_unlocked"]=a0=>(__IO_feof_unlocked=Module["__IO_feof_unlocked"]=wasmExports["_IO_feof_unlocked"])(a0);var _ferror_unlocked=Module["_ferror_unlocked"]=a0=>(_ferror_unlocked=Module["_ferror_unlocked"]=wasmExports["ferror_unlocked"])(a0);var __IO_ferror_unlocked=Module["__IO_ferror_unlocked"]=a0=>(__IO_ferror_unlocked=Module["__IO_ferror_unlocked"]=wasmExports["_IO_ferror_unlocked"])(a0);var _fesetexceptflag=Module["_fesetexceptflag"]=(a0,a1)=>(_fesetexceptflag=Module["_fesetexceptflag"]=wasmExports["fesetexceptflag"])(a0,a1);var _fesetround=Module["_fesetround"]=a0=>(_fesetround=Module["_fesetround"]=wasmExports["fesetround"])(a0);var _feupdateenv=Module["_feupdateenv"]=a0=>(_feupdateenv=Module["_feupdateenv"]=wasmExports["feupdateenv"])(a0);var _fflush_unlocked=Module["_fflush_unlocked"]=a0=>(_fflush_unlocked=Module["_fflush_unlocked"]=wasmExports["fflush_unlocked"])(a0);var _ffs=Module["_ffs"]=a0=>(_ffs=Module["_ffs"]=wasmExports["ffs"])(a0);var _ffsl=Module["_ffsl"]=a0=>(_ffsl=Module["_ffsl"]=wasmExports["ffsl"])(a0);var _ffsll=Module["_ffsll"]=a0=>(_ffsll=Module["_ffsll"]=wasmExports["ffsll"])(a0);var _emscripten_futex_wake=Module["_emscripten_futex_wake"]=(a0,a1)=>(_emscripten_futex_wake=Module["_emscripten_futex_wake"]=wasmExports["emscripten_futex_wake"])(a0,a1);var _fgetln=Module["_fgetln"]=(a0,a1)=>(_fgetln=Module["_fgetln"]=wasmExports["fgetln"])(a0,a1);var _getline=Module["_getline"]=(a0,a1,a2)=>(_getline=Module["_getline"]=wasmExports["getline"])(a0,a1,a2);var _fgetpos=Module["_fgetpos"]=(a0,a1)=>(_fgetpos=Module["_fgetpos"]=wasmExports["fgetpos"])(a0,a1);var _fgets_unlocked=Module["_fgets_unlocked"]=(a0,a1,a2)=>(_fgets_unlocked=Module["_fgets_unlocked"]=wasmExports["fgets_unlocked"])(a0,a1,a2);var ___fgetwc_unlocked=Module["___fgetwc_unlocked"]=a0=>(___fgetwc_unlocked=Module["___fgetwc_unlocked"]=wasmExports["__fgetwc_unlocked"])(a0);var _fwide=Module["_fwide"]=(a0,a1)=>(_fwide=Module["_fwide"]=wasmExports["fwide"])(a0,a1);var _mbtowc=Module["_mbtowc"]=(a0,a1,a2)=>(_mbtowc=Module["_mbtowc"]=wasmExports["mbtowc"])(a0,a1,a2);var _fgetwc=Module["_fgetwc"]=a0=>(_fgetwc=Module["_fgetwc"]=wasmExports["fgetwc"])(a0);var _fgetwc_unlocked=Module["_fgetwc_unlocked"]=a0=>(_fgetwc_unlocked=Module["_fgetwc_unlocked"]=wasmExports["fgetwc_unlocked"])(a0);var _getwc_unlocked=Module["_getwc_unlocked"]=a0=>(_getwc_unlocked=Module["_getwc_unlocked"]=wasmExports["getwc_unlocked"])(a0);var _fgetws=Module["_fgetws"]=(a0,a1,a2)=>(_fgetws=Module["_fgetws"]=wasmExports["fgetws"])(a0,a1,a2);var _fgetws_unlocked=Module["_fgetws_unlocked"]=(a0,a1,a2)=>(_fgetws_unlocked=Module["_fgetws_unlocked"]=wasmExports["fgetws_unlocked"])(a0,a1,a2);var _fileno_unlocked=Module["_fileno_unlocked"]=a0=>(_fileno_unlocked=Module["_fileno_unlocked"]=wasmExports["fileno_unlocked"])(a0);var _finite=Module["_finite"]=a0=>(_finite=Module["_finite"]=wasmExports["finite"])(a0);var _finitef=Module["_finitef"]=a0=>(_finitef=Module["_finitef"]=wasmExports["finitef"])(a0);var ___floatunsitf=Module["___floatunsitf"]=(a0,a1)=>(___floatunsitf=Module["___floatunsitf"]=wasmExports["__floatunsitf"])(a0,a1);var _fmodl=Module["_fmodl"]=(a0,a1,a2,a3,a4)=>(_fmodl=Module["_fmodl"]=wasmExports["fmodl"])(a0,a1,a2,a3,a4);var _ftrylockfile=Module["_ftrylockfile"]=a0=>(_ftrylockfile=Module["_ftrylockfile"]=wasmExports["ftrylockfile"])(a0);var _floorf=Module["_floorf"]=a0=>(_floorf=Module["_floorf"]=wasmExports["floorf"])(a0);var _floorl=Module["_floorl"]=(a0,a1,a2)=>(_floorl=Module["_floorl"]=wasmExports["floorl"])(a0,a1,a2);var _fmaf=Module["_fmaf"]=(a0,a1,a2)=>(_fmaf=Module["_fmaf"]=wasmExports["fmaf"])(a0,a1,a2);var _fmal=Module["_fmal"]=(a0,a1,a2,a3,a4,a5,a6)=>(_fmal=Module["_fmal"]=wasmExports["fmal"])(a0,a1,a2,a3,a4,a5,a6);var _frexpl=Module["_frexpl"]=(a0,a1,a2,a3)=>(_frexpl=Module["_frexpl"]=wasmExports["frexpl"])(a0,a1,a2,a3);var _nextafterl=Module["_nextafterl"]=(a0,a1,a2,a3,a4)=>(_nextafterl=Module["_nextafterl"]=wasmExports["nextafterl"])(a0,a1,a2,a3,a4);var _ilogbl=Module["_ilogbl"]=(a0,a1)=>(_ilogbl=Module["_ilogbl"]=wasmExports["ilogbl"])(a0,a1);var _fmax=Module["_fmax"]=(a0,a1)=>(_fmax=Module["_fmax"]=wasmExports["fmax"])(a0,a1);var _fmaxf=Module["_fmaxf"]=(a0,a1)=>(_fmaxf=Module["_fmaxf"]=wasmExports["fmaxf"])(a0,a1);var _fmaxl=Module["_fmaxl"]=(a0,a1,a2,a3,a4)=>(_fmaxl=Module["_fmaxl"]=wasmExports["fmaxl"])(a0,a1,a2,a3,a4);var _fmemopen=Module["_fmemopen"]=(a0,a1,a2)=>(_fmemopen=Module["_fmemopen"]=wasmExports["fmemopen"])(a0,a1,a2);var _fmin=Module["_fmin"]=(a0,a1)=>(_fmin=Module["_fmin"]=wasmExports["fmin"])(a0,a1);var _fminf=Module["_fminf"]=(a0,a1)=>(_fminf=Module["_fminf"]=wasmExports["fminf"])(a0,a1);var _fminl=Module["_fminl"]=(a0,a1,a2,a3,a4)=>(_fminl=Module["_fminl"]=wasmExports["fminl"])(a0,a1,a2,a3,a4);var _fmodf=Module["_fmodf"]=(a0,a1)=>(_fmodf=Module["_fmodf"]=wasmExports["fmodf"])(a0,a1);var _fmtmsg=Module["_fmtmsg"]=(a0,a1,a2,a3,a4,a5)=>(_fmtmsg=Module["_fmtmsg"]=wasmExports["fmtmsg"])(a0,a1,a2,a3,a4,a5);var _fnmatch=Module["_fnmatch"]=(a0,a1,a2)=>(_fnmatch=Module["_fnmatch"]=wasmExports["fnmatch"])(a0,a1,a2);var _towupper=Module["_towupper"]=a0=>(_towupper=Module["_towupper"]=wasmExports["towupper"])(a0);var _towlower=Module["_towlower"]=a0=>(_towlower=Module["_towlower"]=wasmExports["towlower"])(a0);var _wctype=Module["_wctype"]=a0=>(_wctype=Module["_wctype"]=wasmExports["wctype"])(a0);var _iswctype=Module["_iswctype"]=(a0,a1)=>(_iswctype=Module["_iswctype"]=wasmExports["iswctype"])(a0,a1);var _fopencookie=Module["_fopencookie"]=(a0,a1,a2)=>(_fopencookie=Module["_fopencookie"]=wasmExports["fopencookie"])(a0,a1,a2);var _forkpty=Module["_forkpty"]=(a0,a1,a2,a3)=>(_forkpty=Module["_forkpty"]=wasmExports["forkpty"])(a0,a1,a2,a3);var _openpty=Module["_openpty"]=(a0,a1,a2,a3,a4)=>(_openpty=Module["_openpty"]=wasmExports["openpty"])(a0,a1,a2,a3,a4);var _pipe2=Module["_pipe2"]=(a0,a1)=>(_pipe2=Module["_pipe2"]=wasmExports["pipe2"])(a0,a1);var _vfiprintf=Module["_vfiprintf"]=(a0,a1,a2)=>(_vfiprintf=Module["_vfiprintf"]=wasmExports["vfiprintf"])(a0,a1,a2);var ___small_vfprintf=Module["___small_vfprintf"]=(a0,a1,a2)=>(___small_vfprintf=Module["___small_vfprintf"]=wasmExports["__small_vfprintf"])(a0,a1,a2);var _fputs_unlocked=Module["_fputs_unlocked"]=(a0,a1)=>(_fputs_unlocked=Module["_fputs_unlocked"]=wasmExports["fputs_unlocked"])(a0,a1);var ___fputwc_unlocked=Module["___fputwc_unlocked"]=(a0,a1)=>(___fputwc_unlocked=Module["___fputwc_unlocked"]=wasmExports["__fputwc_unlocked"])(a0,a1);var _wctomb=Module["_wctomb"]=(a0,a1)=>(_wctomb=Module["_wctomb"]=wasmExports["wctomb"])(a0,a1);var _fputwc=Module["_fputwc"]=(a0,a1)=>(_fputwc=Module["_fputwc"]=wasmExports["fputwc"])(a0,a1);var _fputwc_unlocked=Module["_fputwc_unlocked"]=(a0,a1)=>(_fputwc_unlocked=Module["_fputwc_unlocked"]=wasmExports["fputwc_unlocked"])(a0,a1);var _putwc_unlocked=Module["_putwc_unlocked"]=(a0,a1)=>(_putwc_unlocked=Module["_putwc_unlocked"]=wasmExports["putwc_unlocked"])(a0,a1);var _fputws=Module["_fputws"]=(a0,a1)=>(_fputws=Module["_fputws"]=wasmExports["fputws"])(a0,a1);var _wcsrtombs=Module["_wcsrtombs"]=(a0,a1,a2,a3)=>(_wcsrtombs=Module["_wcsrtombs"]=wasmExports["wcsrtombs"])(a0,a1,a2,a3);var _fputws_unlocked=Module["_fputws_unlocked"]=(a0,a1)=>(_fputws_unlocked=Module["_fputws_unlocked"]=wasmExports["fputws_unlocked"])(a0,a1);var _fread_unlocked=Module["_fread_unlocked"]=(a0,a1,a2,a3)=>(_fread_unlocked=Module["_fread_unlocked"]=wasmExports["fread_unlocked"])(a0,a1,a2,a3);var _freelocale=Module["_freelocale"]=a0=>(_freelocale=Module["_freelocale"]=wasmExports["freelocale"])(a0);var ___freelocale=Module["___freelocale"]=a0=>(___freelocale=Module["___freelocale"]=wasmExports["__freelocale"])(a0);var _freopen=Module["_freopen"]=(a0,a1,a2)=>(_freopen=Module["_freopen"]=wasmExports["freopen"])(a0,a1,a2);var _frexpf=Module["_frexpf"]=(a0,a1)=>(_frexpf=Module["_frexpf"]=wasmExports["frexpf"])(a0,a1);var _fscanf=Module["_fscanf"]=(a0,a1,a2)=>(_fscanf=Module["_fscanf"]=wasmExports["fscanf"])(a0,a1,a2);var _vfscanf=Module["_vfscanf"]=(a0,a1,a2)=>(_vfscanf=Module["_vfscanf"]=wasmExports["vfscanf"])(a0,a1,a2);var ___isoc99_fscanf=Module["___isoc99_fscanf"]=(a0,a1,a2)=>(___isoc99_fscanf=Module["___isoc99_fscanf"]=wasmExports["__isoc99_fscanf"])(a0,a1,a2);var _fseek=Module["_fseek"]=(a0,a1,a2)=>(_fseek=Module["_fseek"]=wasmExports["fseek"])(a0,a1,a2);var _fseeko=Module["_fseeko"]=(a0,a1,a2)=>(_fseeko=Module["_fseeko"]=wasmExports["fseeko"])(a0,a1,a2);var _fsetpos=Module["_fsetpos"]=(a0,a1)=>(_fsetpos=Module["_fsetpos"]=wasmExports["fsetpos"])(a0,a1);var _ftello=Module["_ftello"]=a0=>(_ftello=Module["_ftello"]=wasmExports["ftello"])(a0);var _ftime=Module["_ftime"]=a0=>(_ftime=Module["_ftime"]=wasmExports["ftime"])(a0);var _utimensat=Module["_utimensat"]=(a0,a1,a2,a3)=>(_utimensat=Module["_utimensat"]=wasmExports["utimensat"])(a0,a1,a2,a3);var _fwprintf=Module["_fwprintf"]=(a0,a1,a2)=>(_fwprintf=Module["_fwprintf"]=wasmExports["fwprintf"])(a0,a1,a2);var _vfwprintf=Module["_vfwprintf"]=(a0,a1,a2)=>(_vfwprintf=Module["_vfwprintf"]=wasmExports["vfwprintf"])(a0,a1,a2);var _fwrite_unlocked=Module["_fwrite_unlocked"]=(a0,a1,a2,a3)=>(_fwrite_unlocked=Module["_fwrite_unlocked"]=wasmExports["fwrite_unlocked"])(a0,a1,a2,a3);var _fwscanf=Module["_fwscanf"]=(a0,a1,a2)=>(_fwscanf=Module["_fwscanf"]=wasmExports["fwscanf"])(a0,a1,a2);var _vfwscanf=Module["_vfwscanf"]=(a0,a1,a2)=>(_vfwscanf=Module["_vfwscanf"]=wasmExports["vfwscanf"])(a0,a1,a2);var ___isoc99_fwscanf=Module["___isoc99_fwscanf"]=(a0,a1,a2)=>(___isoc99_fwscanf=Module["___isoc99_fwscanf"]=wasmExports["__isoc99_fwscanf"])(a0,a1,a2);var _gcvt=Module["_gcvt"]=(a0,a1,a2)=>(_gcvt=Module["_gcvt"]=wasmExports["gcvt"])(a0,a1,a2);var _get_current_dir_name=Module["_get_current_dir_name"]=()=>(_get_current_dir_name=Module["_get_current_dir_name"]=wasmExports["get_current_dir_name"])();var _strdup=Module["_strdup"]=a0=>(_strdup=Module["_strdup"]=wasmExports["strdup"])(a0);var __IO_getc=Module["__IO_getc"]=a0=>(__IO_getc=Module["__IO_getc"]=wasmExports["_IO_getc"])(a0);var _fgetc_unlocked=Module["_fgetc_unlocked"]=a0=>(_fgetc_unlocked=Module["_fgetc_unlocked"]=wasmExports["fgetc_unlocked"])(a0);var __IO_getc_unlocked=Module["__IO_getc_unlocked"]=a0=>(__IO_getc_unlocked=Module["__IO_getc_unlocked"]=wasmExports["_IO_getc_unlocked"])(a0);var _getchar=Module["_getchar"]=()=>(_getchar=Module["_getchar"]=wasmExports["getchar"])();var _getchar_unlocked=Module["_getchar_unlocked"]=()=>(_getchar_unlocked=Module["_getchar_unlocked"]=wasmExports["getchar_unlocked"])();var _getdelim=Module["_getdelim"]=(a0,a1,a2,a3)=>(_getdelim=Module["_getdelim"]=wasmExports["getdelim"])(a0,a1,a2,a3);var ___getdelim=Module["___getdelim"]=(a0,a1,a2,a3)=>(___getdelim=Module["___getdelim"]=wasmExports["__getdelim"])(a0,a1,a2,a3);var _getdents=Module["_getdents"]=(a0,a1,a2)=>(_getdents=Module["_getdents"]=wasmExports["getdents"])(a0,a1,a2);var _getdomainname=Module["_getdomainname"]=(a0,a1)=>(_getdomainname=Module["_getdomainname"]=wasmExports["getdomainname"])(a0,a1);var _getegid=Module["_getegid"]=()=>(_getegid=Module["_getegid"]=wasmExports["getegid"])();var _geteuid=Module["_geteuid"]=()=>(_geteuid=Module["_geteuid"]=wasmExports["geteuid"])();var _getgroups=Module["_getgroups"]=(a0,a1)=>(_getgroups=Module["_getgroups"]=wasmExports["getgroups"])(a0,a1);var _gethostid=Module["_gethostid"]=()=>(_gethostid=Module["_gethostid"]=wasmExports["gethostid"])();var _freeifaddrs=Module["_freeifaddrs"]=a0=>(_freeifaddrs=Module["_freeifaddrs"]=wasmExports["freeifaddrs"])(a0);var _getifaddrs=Module["_getifaddrs"]=a0=>(_getifaddrs=Module["_getifaddrs"]=wasmExports["getifaddrs"])(a0);var ___getitimer=Module["___getitimer"]=(a0,a1,a2)=>(___getitimer=Module["___getitimer"]=wasmExports["__getitimer"])(a0,a1,a2);var _getlogin_r=Module["_getlogin_r"]=(a0,a1)=>(_getlogin_r=Module["_getlogin_r"]=wasmExports["getlogin_r"])(a0,a1);var _getopt=Module["_getopt"]=(a0,a1,a2)=>(_getopt=Module["_getopt"]=wasmExports["getopt"])(a0,a1,a2);var ___posix_getopt=Module["___posix_getopt"]=(a0,a1,a2)=>(___posix_getopt=Module["___posix_getopt"]=wasmExports["__posix_getopt"])(a0,a1,a2);var _getopt_long=Module["_getopt_long"]=(a0,a1,a2,a3,a4)=>(_getopt_long=Module["_getopt_long"]=wasmExports["getopt_long"])(a0,a1,a2,a3,a4);var _getopt_long_only=Module["_getopt_long_only"]=(a0,a1,a2,a3,a4)=>(_getopt_long_only=Module["_getopt_long_only"]=wasmExports["getopt_long_only"])(a0,a1,a2,a3,a4);var _mblen=Module["_mblen"]=(a0,a1)=>(_mblen=Module["_mblen"]=wasmExports["mblen"])(a0,a1);var _getpagesize=Module["_getpagesize"]=()=>(_getpagesize=Module["_getpagesize"]=wasmExports["getpagesize"])();var _getresgid=Module["_getresgid"]=(a0,a1,a2)=>(_getresgid=Module["_getresgid"]=wasmExports["getresgid"])(a0,a1,a2);var _getresuid=Module["_getresuid"]=(a0,a1,a2)=>(_getresuid=Module["_getresuid"]=wasmExports["getresuid"])(a0,a1,a2);var _getrusage=Module["_getrusage"]=(a0,a1)=>(_getrusage=Module["_getrusage"]=wasmExports["getrusage"])(a0,a1);var _gets=Module["_gets"]=a0=>(_gets=Module["_gets"]=wasmExports["gets"])(a0);var _getservbyname_r=Module["_getservbyname_r"]=(a0,a1,a2,a3,a4,a5)=>(_getservbyname_r=Module["_getservbyname_r"]=wasmExports["getservbyname_r"])(a0,a1,a2,a3,a4,a5);var _getservbyport_r=Module["_getservbyport_r"]=(a0,a1,a2,a3,a4,a5)=>(_getservbyport_r=Module["_getservbyport_r"]=wasmExports["getservbyport_r"])(a0,a1,a2,a3,a4,a5);var _getsubopt=Module["_getsubopt"]=(a0,a1,a2)=>(_getsubopt=Module["_getsubopt"]=wasmExports["getsubopt"])(a0,a1,a2);var _gettid=Module["_gettid"]=()=>(_gettid=Module["_gettid"]=wasmExports["gettid"])();var _getw=Module["_getw"]=a0=>(_getw=Module["_getw"]=wasmExports["getw"])(a0);var _getwc=Module["_getwc"]=a0=>(_getwc=Module["_getwc"]=wasmExports["getwc"])(a0);var _getwchar=Module["_getwchar"]=()=>(_getwchar=Module["_getwchar"]=wasmExports["getwchar"])();var _getwchar_unlocked=Module["_getwchar_unlocked"]=()=>(_getwchar_unlocked=Module["_getwchar_unlocked"]=wasmExports["getwchar_unlocked"])();var _glob=Module["_glob"]=(a0,a1,a2,a3)=>(_glob=Module["_glob"]=wasmExports["glob"])(a0,a1,a2,a3);var _globfree=Module["_globfree"]=a0=>(_globfree=Module["_globfree"]=wasmExports["globfree"])(a0);var _gmtime=Module["_gmtime"]=a0=>(_gmtime=Module["_gmtime"]=wasmExports["gmtime"])(a0);var _herror=Module["_herror"]=a0=>(_herror=Module["_herror"]=wasmExports["herror"])(a0);var _hcreate=Module["_hcreate"]=a0=>(_hcreate=Module["_hcreate"]=wasmExports["hcreate"])(a0);var _hdestroy=Module["_hdestroy"]=()=>(_hdestroy=Module["_hdestroy"]=wasmExports["hdestroy"])();var _hsearch=Module["_hsearch"]=(a0,a1)=>(_hsearch=Module["_hsearch"]=wasmExports["hsearch"])(a0,a1);var _hcreate_r=Module["_hcreate_r"]=(a0,a1)=>(_hcreate_r=Module["_hcreate_r"]=wasmExports["hcreate_r"])(a0,a1);var _hdestroy_r=Module["_hdestroy_r"]=a0=>(_hdestroy_r=Module["_hdestroy_r"]=wasmExports["hdestroy_r"])(a0);var _hsearch_r=Module["_hsearch_r"]=(a0,a1,a2,a3)=>(_hsearch_r=Module["_hsearch_r"]=wasmExports["hsearch_r"])(a0,a1,a2,a3);var _iconv_open=Module["_iconv_open"]=(a0,a1)=>(_iconv_open=Module["_iconv_open"]=wasmExports["iconv_open"])(a0,a1);var _iconv=Module["_iconv"]=(a0,a1,a2,a3,a4)=>(_iconv=Module["_iconv"]=wasmExports["iconv"])(a0,a1,a2,a3,a4);var _iconv_close=Module["_iconv_close"]=a0=>(_iconv_close=Module["_iconv_close"]=wasmExports["iconv_close"])(a0);var _ioctl=Module["_ioctl"]=(a0,a1,a2)=>(_ioctl=Module["_ioctl"]=wasmExports["ioctl"])(a0,a1,a2);var _ilogb=Module["_ilogb"]=a0=>(_ilogb=Module["_ilogb"]=wasmExports["ilogb"])(a0);var _ilogbf=Module["_ilogbf"]=a0=>(_ilogbf=Module["_ilogbf"]=wasmExports["ilogbf"])(a0);var _imaxabs=Module["_imaxabs"]=a0=>(_imaxabs=Module["_imaxabs"]=wasmExports["imaxabs"])(a0);var _imaxdiv=Module["_imaxdiv"]=(a0,a1,a2)=>(_imaxdiv=Module["_imaxdiv"]=wasmExports["imaxdiv"])(a0,a1,a2);var _index=Module["_index"]=(a0,a1)=>(_index=Module["_index"]=wasmExports["index"])(a0,a1);var _inet_addr=Module["_inet_addr"]=a0=>(_inet_addr=Module["_inet_addr"]=wasmExports["inet_addr"])(a0);var _inet_network=Module["_inet_network"]=a0=>(_inet_network=Module["_inet_network"]=wasmExports["inet_network"])(a0);var _inet_makeaddr=Module["_inet_makeaddr"]=(a0,a1)=>(_inet_makeaddr=Module["_inet_makeaddr"]=wasmExports["inet_makeaddr"])(a0,a1);var _inet_lnaof=Module["_inet_lnaof"]=a0=>(_inet_lnaof=Module["_inet_lnaof"]=wasmExports["inet_lnaof"])(a0);var _inet_netof=Module["_inet_netof"]=a0=>(_inet_netof=Module["_inet_netof"]=wasmExports["inet_netof"])(a0);var _insque=Module["_insque"]=(a0,a1)=>(_insque=Module["_insque"]=wasmExports["insque"])(a0,a1);var _remque=Module["_remque"]=a0=>(_remque=Module["_remque"]=wasmExports["remque"])(a0);var ___intscan=Module["___intscan"]=(a0,a1,a2,a3)=>(___intscan=Module["___intscan"]=wasmExports["__intscan"])(a0,a1,a2,a3);var ___multi3=Module["___multi3"]=(a0,a1,a2,a3,a4)=>(___multi3=Module["___multi3"]=wasmExports["__multi3"])(a0,a1,a2,a3,a4);var ___isalnum_l=Module["___isalnum_l"]=(a0,a1)=>(___isalnum_l=Module["___isalnum_l"]=wasmExports["__isalnum_l"])(a0,a1);var _isalnum_l=Module["_isalnum_l"]=(a0,a1)=>(_isalnum_l=Module["_isalnum_l"]=wasmExports["isalnum_l"])(a0,a1);var _isalpha=Module["_isalpha"]=a0=>(_isalpha=Module["_isalpha"]=wasmExports["isalpha"])(a0);var ___isalpha_l=Module["___isalpha_l"]=(a0,a1)=>(___isalpha_l=Module["___isalpha_l"]=wasmExports["__isalpha_l"])(a0,a1);var _isalpha_l=Module["_isalpha_l"]=(a0,a1)=>(_isalpha_l=Module["_isalpha_l"]=wasmExports["isalpha_l"])(a0,a1);var _isascii=Module["_isascii"]=a0=>(_isascii=Module["_isascii"]=wasmExports["isascii"])(a0);var _isblank=Module["_isblank"]=a0=>(_isblank=Module["_isblank"]=wasmExports["isblank"])(a0);var ___isblank_l=Module["___isblank_l"]=(a0,a1)=>(___isblank_l=Module["___isblank_l"]=wasmExports["__isblank_l"])(a0,a1);var _isblank_l=Module["_isblank_l"]=(a0,a1)=>(_isblank_l=Module["_isblank_l"]=wasmExports["isblank_l"])(a0,a1);var _iscntrl=Module["_iscntrl"]=a0=>(_iscntrl=Module["_iscntrl"]=wasmExports["iscntrl"])(a0);var ___iscntrl_l=Module["___iscntrl_l"]=(a0,a1)=>(___iscntrl_l=Module["___iscntrl_l"]=wasmExports["__iscntrl_l"])(a0,a1);var _iscntrl_l=Module["_iscntrl_l"]=(a0,a1)=>(_iscntrl_l=Module["_iscntrl_l"]=wasmExports["iscntrl_l"])(a0,a1);var _isdigit=Module["_isdigit"]=a0=>(_isdigit=Module["_isdigit"]=wasmExports["isdigit"])(a0);var ___isdigit_l=Module["___isdigit_l"]=(a0,a1)=>(___isdigit_l=Module["___isdigit_l"]=wasmExports["__isdigit_l"])(a0,a1);var _isdigit_l=Module["_isdigit_l"]=(a0,a1)=>(_isdigit_l=Module["_isdigit_l"]=wasmExports["isdigit_l"])(a0,a1);var _isgraph=Module["_isgraph"]=a0=>(_isgraph=Module["_isgraph"]=wasmExports["isgraph"])(a0);var ___isgraph_l=Module["___isgraph_l"]=(a0,a1)=>(___isgraph_l=Module["___isgraph_l"]=wasmExports["__isgraph_l"])(a0,a1);var _isgraph_l=Module["_isgraph_l"]=(a0,a1)=>(_isgraph_l=Module["_isgraph_l"]=wasmExports["isgraph_l"])(a0,a1);var _islower=Module["_islower"]=a0=>(_islower=Module["_islower"]=wasmExports["islower"])(a0);var ___islower_l=Module["___islower_l"]=(a0,a1)=>(___islower_l=Module["___islower_l"]=wasmExports["__islower_l"])(a0,a1);var _islower_l=Module["_islower_l"]=(a0,a1)=>(_islower_l=Module["_islower_l"]=wasmExports["islower_l"])(a0,a1);var _isprint=Module["_isprint"]=a0=>(_isprint=Module["_isprint"]=wasmExports["isprint"])(a0);var ___isprint_l=Module["___isprint_l"]=(a0,a1)=>(___isprint_l=Module["___isprint_l"]=wasmExports["__isprint_l"])(a0,a1);var _isprint_l=Module["_isprint_l"]=(a0,a1)=>(_isprint_l=Module["_isprint_l"]=wasmExports["isprint_l"])(a0,a1);var _ispunct=Module["_ispunct"]=a0=>(_ispunct=Module["_ispunct"]=wasmExports["ispunct"])(a0);var ___ispunct_l=Module["___ispunct_l"]=(a0,a1)=>(___ispunct_l=Module["___ispunct_l"]=wasmExports["__ispunct_l"])(a0,a1);var _ispunct_l=Module["_ispunct_l"]=(a0,a1)=>(_ispunct_l=Module["_ispunct_l"]=wasmExports["ispunct_l"])(a0,a1);var _issetugid=Module["_issetugid"]=()=>(_issetugid=Module["_issetugid"]=wasmExports["issetugid"])();var _isspace=Module["_isspace"]=a0=>(_isspace=Module["_isspace"]=wasmExports["isspace"])(a0);var ___isspace_l=Module["___isspace_l"]=(a0,a1)=>(___isspace_l=Module["___isspace_l"]=wasmExports["__isspace_l"])(a0,a1);var _isspace_l=Module["_isspace_l"]=(a0,a1)=>(_isspace_l=Module["_isspace_l"]=wasmExports["isspace_l"])(a0,a1);var _isupper=Module["_isupper"]=a0=>(_isupper=Module["_isupper"]=wasmExports["isupper"])(a0);var ___isupper_l=Module["___isupper_l"]=(a0,a1)=>(___isupper_l=Module["___isupper_l"]=wasmExports["__isupper_l"])(a0,a1);var _isupper_l=Module["_isupper_l"]=(a0,a1)=>(_isupper_l=Module["_isupper_l"]=wasmExports["isupper_l"])(a0,a1);var _iswalnum=Module["_iswalnum"]=a0=>(_iswalnum=Module["_iswalnum"]=wasmExports["iswalnum"])(a0);var _iswalpha=Module["_iswalpha"]=a0=>(_iswalpha=Module["_iswalpha"]=wasmExports["iswalpha"])(a0);var ___iswalnum_l=Module["___iswalnum_l"]=(a0,a1)=>(___iswalnum_l=Module["___iswalnum_l"]=wasmExports["__iswalnum_l"])(a0,a1);var _iswalnum_l=Module["_iswalnum_l"]=(a0,a1)=>(_iswalnum_l=Module["_iswalnum_l"]=wasmExports["iswalnum_l"])(a0,a1);var ___iswalpha_l=Module["___iswalpha_l"]=(a0,a1)=>(___iswalpha_l=Module["___iswalpha_l"]=wasmExports["__iswalpha_l"])(a0,a1);var _iswalpha_l=Module["_iswalpha_l"]=(a0,a1)=>(_iswalpha_l=Module["_iswalpha_l"]=wasmExports["iswalpha_l"])(a0,a1);var _iswblank=Module["_iswblank"]=a0=>(_iswblank=Module["_iswblank"]=wasmExports["iswblank"])(a0);var ___iswblank_l=Module["___iswblank_l"]=(a0,a1)=>(___iswblank_l=Module["___iswblank_l"]=wasmExports["__iswblank_l"])(a0,a1);var _iswblank_l=Module["_iswblank_l"]=(a0,a1)=>(_iswblank_l=Module["_iswblank_l"]=wasmExports["iswblank_l"])(a0,a1);var _iswcntrl=Module["_iswcntrl"]=a0=>(_iswcntrl=Module["_iswcntrl"]=wasmExports["iswcntrl"])(a0);var ___iswcntrl_l=Module["___iswcntrl_l"]=(a0,a1)=>(___iswcntrl_l=Module["___iswcntrl_l"]=wasmExports["__iswcntrl_l"])(a0,a1);var _iswcntrl_l=Module["_iswcntrl_l"]=(a0,a1)=>(_iswcntrl_l=Module["_iswcntrl_l"]=wasmExports["iswcntrl_l"])(a0,a1);var _iswgraph=Module["_iswgraph"]=a0=>(_iswgraph=Module["_iswgraph"]=wasmExports["iswgraph"])(a0);var _iswlower=Module["_iswlower"]=a0=>(_iswlower=Module["_iswlower"]=wasmExports["iswlower"])(a0);var _iswprint=Module["_iswprint"]=a0=>(_iswprint=Module["_iswprint"]=wasmExports["iswprint"])(a0);var _iswpunct=Module["_iswpunct"]=a0=>(_iswpunct=Module["_iswpunct"]=wasmExports["iswpunct"])(a0);var _iswspace=Module["_iswspace"]=a0=>(_iswspace=Module["_iswspace"]=wasmExports["iswspace"])(a0);var _iswupper=Module["_iswupper"]=a0=>(_iswupper=Module["_iswupper"]=wasmExports["iswupper"])(a0);var _iswxdigit=Module["_iswxdigit"]=a0=>(_iswxdigit=Module["_iswxdigit"]=wasmExports["iswxdigit"])(a0);var ___iswctype_l=Module["___iswctype_l"]=(a0,a1,a2)=>(___iswctype_l=Module["___iswctype_l"]=wasmExports["__iswctype_l"])(a0,a1,a2);var ___wctype_l=Module["___wctype_l"]=(a0,a1)=>(___wctype_l=Module["___wctype_l"]=wasmExports["__wctype_l"])(a0,a1);var _iswctype_l=Module["_iswctype_l"]=(a0,a1,a2)=>(_iswctype_l=Module["_iswctype_l"]=wasmExports["iswctype_l"])(a0,a1,a2);var _wctype_l=Module["_wctype_l"]=(a0,a1)=>(_wctype_l=Module["_wctype_l"]=wasmExports["wctype_l"])(a0,a1);var _iswdigit=Module["_iswdigit"]=a0=>(_iswdigit=Module["_iswdigit"]=wasmExports["iswdigit"])(a0);var ___iswdigit_l=Module["___iswdigit_l"]=(a0,a1)=>(___iswdigit_l=Module["___iswdigit_l"]=wasmExports["__iswdigit_l"])(a0,a1);var _iswdigit_l=Module["_iswdigit_l"]=(a0,a1)=>(_iswdigit_l=Module["_iswdigit_l"]=wasmExports["iswdigit_l"])(a0,a1);var ___iswgraph_l=Module["___iswgraph_l"]=(a0,a1)=>(___iswgraph_l=Module["___iswgraph_l"]=wasmExports["__iswgraph_l"])(a0,a1);var _iswgraph_l=Module["_iswgraph_l"]=(a0,a1)=>(_iswgraph_l=Module["_iswgraph_l"]=wasmExports["iswgraph_l"])(a0,a1);var ___iswlower_l=Module["___iswlower_l"]=(a0,a1)=>(___iswlower_l=Module["___iswlower_l"]=wasmExports["__iswlower_l"])(a0,a1);var _iswlower_l=Module["_iswlower_l"]=(a0,a1)=>(_iswlower_l=Module["_iswlower_l"]=wasmExports["iswlower_l"])(a0,a1);var ___iswprint_l=Module["___iswprint_l"]=(a0,a1)=>(___iswprint_l=Module["___iswprint_l"]=wasmExports["__iswprint_l"])(a0,a1);var _iswprint_l=Module["_iswprint_l"]=(a0,a1)=>(_iswprint_l=Module["_iswprint_l"]=wasmExports["iswprint_l"])(a0,a1);var ___iswpunct_l=Module["___iswpunct_l"]=(a0,a1)=>(___iswpunct_l=Module["___iswpunct_l"]=wasmExports["__iswpunct_l"])(a0,a1);var _iswpunct_l=Module["_iswpunct_l"]=(a0,a1)=>(_iswpunct_l=Module["_iswpunct_l"]=wasmExports["iswpunct_l"])(a0,a1);var ___iswspace_l=Module["___iswspace_l"]=(a0,a1)=>(___iswspace_l=Module["___iswspace_l"]=wasmExports["__iswspace_l"])(a0,a1);var _iswspace_l=Module["_iswspace_l"]=(a0,a1)=>(_iswspace_l=Module["_iswspace_l"]=wasmExports["iswspace_l"])(a0,a1);var ___iswupper_l=Module["___iswupper_l"]=(a0,a1)=>(___iswupper_l=Module["___iswupper_l"]=wasmExports["__iswupper_l"])(a0,a1);var _iswupper_l=Module["_iswupper_l"]=(a0,a1)=>(_iswupper_l=Module["_iswupper_l"]=wasmExports["iswupper_l"])(a0,a1);var ___iswxdigit_l=Module["___iswxdigit_l"]=(a0,a1)=>(___iswxdigit_l=Module["___iswxdigit_l"]=wasmExports["__iswxdigit_l"])(a0,a1);var _iswxdigit_l=Module["_iswxdigit_l"]=(a0,a1)=>(_iswxdigit_l=Module["_iswxdigit_l"]=wasmExports["iswxdigit_l"])(a0,a1);var ___isxdigit_l=Module["___isxdigit_l"]=(a0,a1)=>(___isxdigit_l=Module["___isxdigit_l"]=wasmExports["__isxdigit_l"])(a0,a1);var _isxdigit_l=Module["_isxdigit_l"]=(a0,a1)=>(_isxdigit_l=Module["_isxdigit_l"]=wasmExports["isxdigit_l"])(a0,a1);var _j0=Module["_j0"]=a0=>(_j0=Module["_j0"]=wasmExports["j0"])(a0);var _y0=Module["_y0"]=a0=>(_y0=Module["_y0"]=wasmExports["y0"])(a0);var _j0f=Module["_j0f"]=a0=>(_j0f=Module["_j0f"]=wasmExports["j0f"])(a0);var _y0f=Module["_y0f"]=a0=>(_y0f=Module["_y0f"]=wasmExports["y0f"])(a0);var _j1=Module["_j1"]=a0=>(_j1=Module["_j1"]=wasmExports["j1"])(a0);var _y1=Module["_y1"]=a0=>(_y1=Module["_y1"]=wasmExports["y1"])(a0);var _j1f=Module["_j1f"]=a0=>(_j1f=Module["_j1f"]=wasmExports["j1f"])(a0);var _y1f=Module["_y1f"]=a0=>(_y1f=Module["_y1f"]=wasmExports["y1f"])(a0);var _jn=Module["_jn"]=(a0,a1)=>(_jn=Module["_jn"]=wasmExports["jn"])(a0,a1);var _yn=Module["_yn"]=(a0,a1)=>(_yn=Module["_yn"]=wasmExports["yn"])(a0,a1);var _jnf=Module["_jnf"]=(a0,a1)=>(_jnf=Module["_jnf"]=wasmExports["jnf"])(a0,a1);var _ynf=Module["_ynf"]=(a0,a1)=>(_ynf=Module["_ynf"]=wasmExports["ynf"])(a0,a1);var _labs=Module["_labs"]=a0=>(_labs=Module["_labs"]=wasmExports["labs"])(a0);var ___nl_langinfo=Module["___nl_langinfo"]=a0=>(___nl_langinfo=Module["___nl_langinfo"]=wasmExports["__nl_langinfo"])(a0);var _nl_langinfo_l=Module["_nl_langinfo_l"]=(a0,a1)=>(_nl_langinfo_l=Module["_nl_langinfo_l"]=wasmExports["nl_langinfo_l"])(a0,a1);var _lchmod=Module["_lchmod"]=(a0,a1)=>(_lchmod=Module["_lchmod"]=wasmExports["lchmod"])(a0,a1);var _lchown=Module["_lchown"]=(a0,a1,a2)=>(_lchown=Module["_lchown"]=wasmExports["lchown"])(a0,a1,a2);var _lcong48=Module["_lcong48"]=a0=>(_lcong48=Module["_lcong48"]=wasmExports["lcong48"])(a0);var _ldexpf=Module["_ldexpf"]=(a0,a1)=>(_ldexpf=Module["_ldexpf"]=wasmExports["ldexpf"])(a0,a1);var _scalbnf=Module["_scalbnf"]=(a0,a1)=>(_scalbnf=Module["_scalbnf"]=wasmExports["scalbnf"])(a0,a1);var _ldexpl=Module["_ldexpl"]=(a0,a1,a2,a3)=>(_ldexpl=Module["_ldexpl"]=wasmExports["ldexpl"])(a0,a1,a2,a3);var _ldiv=Module["_ldiv"]=(a0,a1,a2)=>(_ldiv=Module["_ldiv"]=wasmExports["ldiv"])(a0,a1,a2);var _get_nprocs_conf=Module["_get_nprocs_conf"]=()=>(_get_nprocs_conf=Module["_get_nprocs_conf"]=wasmExports["get_nprocs_conf"])();var _get_nprocs=Module["_get_nprocs"]=()=>(_get_nprocs=Module["_get_nprocs"]=wasmExports["get_nprocs"])();var _get_phys_pages=Module["_get_phys_pages"]=()=>(_get_phys_pages=Module["_get_phys_pages"]=wasmExports["get_phys_pages"])();var _get_avphys_pages=Module["_get_avphys_pages"]=()=>(_get_avphys_pages=Module["_get_avphys_pages"]=wasmExports["get_avphys_pages"])();var _lgamma=Module["_lgamma"]=a0=>(_lgamma=Module["_lgamma"]=wasmExports["lgamma"])(a0);var _lgamma_r=Module["_lgamma_r"]=(a0,a1)=>(_lgamma_r=Module["_lgamma_r"]=wasmExports["lgamma_r"])(a0,a1);var _lgammaf=Module["_lgammaf"]=a0=>(_lgammaf=Module["_lgammaf"]=wasmExports["lgammaf"])(a0);var _lgammaf_r=Module["_lgammaf_r"]=(a0,a1)=>(_lgammaf_r=Module["_lgammaf_r"]=wasmExports["lgammaf_r"])(a0,a1);var ___lgammal_r=Module["___lgammal_r"]=(a0,a1,a2,a3)=>(___lgammal_r=Module["___lgammal_r"]=wasmExports["__lgammal_r"])(a0,a1,a2,a3);var _lgammal=Module["_lgammal"]=(a0,a1,a2)=>(_lgammal=Module["_lgammal"]=wasmExports["lgammal"])(a0,a1,a2);var _lgammal_r=Module["_lgammal_r"]=(a0,a1,a2,a3)=>(_lgammal_r=Module["_lgammal_r"]=wasmExports["lgammal_r"])(a0,a1,a2,a3);var _emscripten_has_threading_support=Module["_emscripten_has_threading_support"]=()=>(_emscripten_has_threading_support=Module["_emscripten_has_threading_support"]=wasmExports["emscripten_has_threading_support"])();var _emscripten_num_logical_cores=Module["_emscripten_num_logical_cores"]=()=>(_emscripten_num_logical_cores=Module["_emscripten_num_logical_cores"]=wasmExports["emscripten_num_logical_cores"])();var _emscripten_force_num_logical_cores=Module["_emscripten_force_num_logical_cores"]=a0=>(_emscripten_force_num_logical_cores=Module["_emscripten_force_num_logical_cores"]=wasmExports["emscripten_force_num_logical_cores"])(a0);var _emscripten_futex_wait=Module["_emscripten_futex_wait"]=(a0,a1,a2)=>(_emscripten_futex_wait=Module["_emscripten_futex_wait"]=wasmExports["emscripten_futex_wait"])(a0,a1,a2);var _emscripten_main_thread_process_queued_calls=Module["_emscripten_main_thread_process_queued_calls"]=()=>(_emscripten_main_thread_process_queued_calls=Module["_emscripten_main_thread_process_queued_calls"]=wasmExports["emscripten_main_thread_process_queued_calls"])();var _emscripten_current_thread_process_queued_calls=Module["_emscripten_current_thread_process_queued_calls"]=()=>(_emscripten_current_thread_process_queued_calls=Module["_emscripten_current_thread_process_queued_calls"]=wasmExports["emscripten_current_thread_process_queued_calls"])();var __emscripten_yield=Module["__emscripten_yield"]=a0=>(__emscripten_yield=Module["__emscripten_yield"]=wasmExports["_emscripten_yield"])(a0);var __emscripten_check_timers=Module["__emscripten_check_timers"]=a0=>(__emscripten_check_timers=Module["__emscripten_check_timers"]=wasmExports["_emscripten_check_timers"])(a0);var _pthread_mutex_consistent=Module["_pthread_mutex_consistent"]=a0=>(_pthread_mutex_consistent=Module["_pthread_mutex_consistent"]=wasmExports["pthread_mutex_consistent"])(a0);var _pthread_barrier_init=Module["_pthread_barrier_init"]=(a0,a1,a2)=>(_pthread_barrier_init=Module["_pthread_barrier_init"]=wasmExports["pthread_barrier_init"])(a0,a1,a2);var _pthread_barrier_destroy=Module["_pthread_barrier_destroy"]=a0=>(_pthread_barrier_destroy=Module["_pthread_barrier_destroy"]=wasmExports["pthread_barrier_destroy"])(a0);var _pthread_barrier_wait=Module["_pthread_barrier_wait"]=a0=>(_pthread_barrier_wait=Module["_pthread_barrier_wait"]=wasmExports["pthread_barrier_wait"])(a0);var _pthread_cond_broadcast=Module["_pthread_cond_broadcast"]=a0=>(_pthread_cond_broadcast=Module["_pthread_cond_broadcast"]=wasmExports["pthread_cond_broadcast"])(a0);var _pthread_atfork=Module["_pthread_atfork"]=(a0,a1,a2)=>(_pthread_atfork=Module["_pthread_atfork"]=wasmExports["pthread_atfork"])(a0,a1,a2);var _pthread_cancel=Module["_pthread_cancel"]=a0=>(_pthread_cancel=Module["_pthread_cancel"]=wasmExports["pthread_cancel"])(a0);var _pthread_testcancel=Module["_pthread_testcancel"]=()=>(_pthread_testcancel=Module["_pthread_testcancel"]=wasmExports["pthread_testcancel"])();var ___pthread_detach=Module["___pthread_detach"]=a0=>(___pthread_detach=Module["___pthread_detach"]=wasmExports["__pthread_detach"])(a0);var _pthread_equal=Module["_pthread_equal"]=(a0,a1)=>(_pthread_equal=Module["_pthread_equal"]=wasmExports["pthread_equal"])(a0,a1);var _pthread_mutexattr_init=Module["_pthread_mutexattr_init"]=a0=>(_pthread_mutexattr_init=Module["_pthread_mutexattr_init"]=wasmExports["pthread_mutexattr_init"])(a0);var _pthread_mutexattr_setprotocol=Module["_pthread_mutexattr_setprotocol"]=(a0,a1)=>(_pthread_mutexattr_setprotocol=Module["_pthread_mutexattr_setprotocol"]=wasmExports["pthread_mutexattr_setprotocol"])(a0,a1);var _pthread_mutexattr_settype=Module["_pthread_mutexattr_settype"]=(a0,a1)=>(_pthread_mutexattr_settype=Module["_pthread_mutexattr_settype"]=wasmExports["pthread_mutexattr_settype"])(a0,a1);var _pthread_mutexattr_destroy=Module["_pthread_mutexattr_destroy"]=a0=>(_pthread_mutexattr_destroy=Module["_pthread_mutexattr_destroy"]=wasmExports["pthread_mutexattr_destroy"])(a0);var _pthread_mutexattr_setpshared=Module["_pthread_mutexattr_setpshared"]=(a0,a1)=>(_pthread_mutexattr_setpshared=Module["_pthread_mutexattr_setpshared"]=wasmExports["pthread_mutexattr_setpshared"])(a0,a1);var _pthread_condattr_destroy=Module["_pthread_condattr_destroy"]=a0=>(_pthread_condattr_destroy=Module["_pthread_condattr_destroy"]=wasmExports["pthread_condattr_destroy"])(a0);var _pthread_condattr_setpshared=Module["_pthread_condattr_setpshared"]=(a0,a1)=>(_pthread_condattr_setpshared=Module["_pthread_condattr_setpshared"]=wasmExports["pthread_condattr_setpshared"])(a0,a1);var _pthread_getattr_np=Module["_pthread_getattr_np"]=(a0,a1)=>(_pthread_getattr_np=Module["_pthread_getattr_np"]=wasmExports["pthread_getattr_np"])(a0,a1);var _pthread_setcanceltype=Module["_pthread_setcanceltype"]=(a0,a1)=>(_pthread_setcanceltype=Module["_pthread_setcanceltype"]=wasmExports["pthread_setcanceltype"])(a0,a1);var _pthread_rwlock_init=Module["_pthread_rwlock_init"]=(a0,a1)=>(_pthread_rwlock_init=Module["_pthread_rwlock_init"]=wasmExports["pthread_rwlock_init"])(a0,a1);var _pthread_rwlock_destroy=Module["_pthread_rwlock_destroy"]=a0=>(_pthread_rwlock_destroy=Module["_pthread_rwlock_destroy"]=wasmExports["pthread_rwlock_destroy"])(a0);var _pthread_rwlock_rdlock=Module["_pthread_rwlock_rdlock"]=a0=>(_pthread_rwlock_rdlock=Module["_pthread_rwlock_rdlock"]=wasmExports["pthread_rwlock_rdlock"])(a0);var _pthread_rwlock_tryrdlock=Module["_pthread_rwlock_tryrdlock"]=a0=>(_pthread_rwlock_tryrdlock=Module["_pthread_rwlock_tryrdlock"]=wasmExports["pthread_rwlock_tryrdlock"])(a0);var _pthread_rwlock_timedrdlock=Module["_pthread_rwlock_timedrdlock"]=(a0,a1)=>(_pthread_rwlock_timedrdlock=Module["_pthread_rwlock_timedrdlock"]=wasmExports["pthread_rwlock_timedrdlock"])(a0,a1);var _pthread_rwlock_wrlock=Module["_pthread_rwlock_wrlock"]=a0=>(_pthread_rwlock_wrlock=Module["_pthread_rwlock_wrlock"]=wasmExports["pthread_rwlock_wrlock"])(a0);var _pthread_rwlock_trywrlock=Module["_pthread_rwlock_trywrlock"]=a0=>(_pthread_rwlock_trywrlock=Module["_pthread_rwlock_trywrlock"]=wasmExports["pthread_rwlock_trywrlock"])(a0);var _pthread_rwlock_timedwrlock=Module["_pthread_rwlock_timedwrlock"]=(a0,a1)=>(_pthread_rwlock_timedwrlock=Module["_pthread_rwlock_timedwrlock"]=wasmExports["pthread_rwlock_timedwrlock"])(a0,a1);var _pthread_rwlock_unlock=Module["_pthread_rwlock_unlock"]=a0=>(_pthread_rwlock_unlock=Module["_pthread_rwlock_unlock"]=wasmExports["pthread_rwlock_unlock"])(a0);var _pthread_rwlockattr_init=Module["_pthread_rwlockattr_init"]=a0=>(_pthread_rwlockattr_init=Module["_pthread_rwlockattr_init"]=wasmExports["pthread_rwlockattr_init"])(a0);var _pthread_rwlockattr_destroy=Module["_pthread_rwlockattr_destroy"]=a0=>(_pthread_rwlockattr_destroy=Module["_pthread_rwlockattr_destroy"]=wasmExports["pthread_rwlockattr_destroy"])(a0);var _pthread_rwlockattr_setpshared=Module["_pthread_rwlockattr_setpshared"]=(a0,a1)=>(_pthread_rwlockattr_setpshared=Module["_pthread_rwlockattr_setpshared"]=wasmExports["pthread_rwlockattr_setpshared"])(a0,a1);var _pthread_spin_init=Module["_pthread_spin_init"]=(a0,a1)=>(_pthread_spin_init=Module["_pthread_spin_init"]=wasmExports["pthread_spin_init"])(a0,a1);var _pthread_spin_destroy=Module["_pthread_spin_destroy"]=a0=>(_pthread_spin_destroy=Module["_pthread_spin_destroy"]=wasmExports["pthread_spin_destroy"])(a0);var _pthread_spin_lock=Module["_pthread_spin_lock"]=a0=>(_pthread_spin_lock=Module["_pthread_spin_lock"]=wasmExports["pthread_spin_lock"])(a0);var _pthread_spin_trylock=Module["_pthread_spin_trylock"]=a0=>(_pthread_spin_trylock=Module["_pthread_spin_trylock"]=wasmExports["pthread_spin_trylock"])(a0);var _pthread_spin_unlock=Module["_pthread_spin_unlock"]=a0=>(_pthread_spin_unlock=Module["_pthread_spin_unlock"]=wasmExports["pthread_spin_unlock"])(a0);var _sem_init=Module["_sem_init"]=(a0,a1,a2)=>(_sem_init=Module["_sem_init"]=wasmExports["sem_init"])(a0,a1,a2);var _sem_post=Module["_sem_post"]=a0=>(_sem_post=Module["_sem_post"]=wasmExports["sem_post"])(a0);var _sem_wait=Module["_sem_wait"]=a0=>(_sem_wait=Module["_sem_wait"]=wasmExports["sem_wait"])(a0);var _sem_trywait=Module["_sem_trywait"]=a0=>(_sem_trywait=Module["_sem_trywait"]=wasmExports["sem_trywait"])(a0);var _sem_destroy=Module["_sem_destroy"]=a0=>(_sem_destroy=Module["_sem_destroy"]=wasmExports["sem_destroy"])(a0);var _pthread_mutex_timedlock=Module["_pthread_mutex_timedlock"]=(a0,a1)=>(_pthread_mutex_timedlock=Module["_pthread_mutex_timedlock"]=wasmExports["pthread_mutex_timedlock"])(a0,a1);var _emscripten_builtin_pthread_create=Module["_emscripten_builtin_pthread_create"]=(a0,a1,a2,a3)=>(_emscripten_builtin_pthread_create=Module["_emscripten_builtin_pthread_create"]=wasmExports["emscripten_builtin_pthread_create"])(a0,a1,a2,a3);var _emscripten_builtin_pthread_join=Module["_emscripten_builtin_pthread_join"]=(a0,a1)=>(_emscripten_builtin_pthread_join=Module["_emscripten_builtin_pthread_join"]=wasmExports["emscripten_builtin_pthread_join"])(a0,a1);var _pthread_join=Module["_pthread_join"]=(a0,a1)=>(_pthread_join=Module["_pthread_join"]=wasmExports["pthread_join"])(a0,a1);var _pthread_once=Module["_pthread_once"]=(a0,a1)=>(_pthread_once=Module["_pthread_once"]=wasmExports["pthread_once"])(a0,a1);var _emscripten_builtin_pthread_exit=Module["_emscripten_builtin_pthread_exit"]=a0=>(_emscripten_builtin_pthread_exit=Module["_emscripten_builtin_pthread_exit"]=wasmExports["emscripten_builtin_pthread_exit"])(a0);var _emscripten_builtin_pthread_detach=Module["_emscripten_builtin_pthread_detach"]=a0=>(_emscripten_builtin_pthread_detach=Module["_emscripten_builtin_pthread_detach"]=wasmExports["emscripten_builtin_pthread_detach"])(a0);var _thrd_detach=Module["_thrd_detach"]=a0=>(_thrd_detach=Module["_thrd_detach"]=wasmExports["thrd_detach"])(a0);var _link=Module["_link"]=(a0,a1)=>(_link=Module["_link"]=wasmExports["link"])(a0,a1);var _linkat=Module["_linkat"]=(a0,a1,a2,a3,a4)=>(_linkat=Module["_linkat"]=wasmExports["linkat"])(a0,a1,a2,a3,a4);var _llabs=Module["_llabs"]=a0=>(_llabs=Module["_llabs"]=wasmExports["llabs"])(a0);var _lldiv=Module["_lldiv"]=(a0,a1,a2)=>(_lldiv=Module["_lldiv"]=wasmExports["lldiv"])(a0,a1,a2);var _llrint=Module["_llrint"]=a0=>(_llrint=Module["_llrint"]=wasmExports["llrint"])(a0);var _rint=Module["_rint"]=a0=>(_rint=Module["_rint"]=wasmExports["rint"])(a0);var _llrintf=Module["_llrintf"]=a0=>(_llrintf=Module["_llrintf"]=wasmExports["llrintf"])(a0);var _rintf=Module["_rintf"]=a0=>(_rintf=Module["_rintf"]=wasmExports["rintf"])(a0);var _llrintl=Module["_llrintl"]=(a0,a1)=>(_llrintl=Module["_llrintl"]=wasmExports["llrintl"])(a0,a1);var _rintl=Module["_rintl"]=(a0,a1,a2)=>(_rintl=Module["_rintl"]=wasmExports["rintl"])(a0,a1,a2);var _llround=Module["_llround"]=a0=>(_llround=Module["_llround"]=wasmExports["llround"])(a0);var _llroundf=Module["_llroundf"]=a0=>(_llroundf=Module["_llroundf"]=wasmExports["llroundf"])(a0);var _roundf=Module["_roundf"]=a0=>(_roundf=Module["_roundf"]=wasmExports["roundf"])(a0);var _llroundl=Module["_llroundl"]=(a0,a1)=>(_llroundl=Module["_llroundl"]=wasmExports["llroundl"])(a0,a1);var _roundl=Module["_roundl"]=(a0,a1,a2)=>(_roundl=Module["_roundl"]=wasmExports["roundl"])(a0,a1,a2);var _log10f=Module["_log10f"]=a0=>(_log10f=Module["_log10f"]=wasmExports["log10f"])(a0);var _log10l=Module["_log10l"]=(a0,a1,a2)=>(_log10l=Module["_log10l"]=wasmExports["log10l"])(a0,a1,a2);var _log2f=Module["_log2f"]=a0=>(_log2f=Module["_log2f"]=wasmExports["log2f"])(a0);var _log2l=Module["_log2l"]=(a0,a1,a2)=>(_log2l=Module["_log2l"]=wasmExports["log2l"])(a0,a1,a2);var _logb=Module["_logb"]=a0=>(_logb=Module["_logb"]=wasmExports["logb"])(a0);var _logbf=Module["_logbf"]=a0=>(_logbf=Module["_logbf"]=wasmExports["logbf"])(a0);var _logbl=Module["_logbl"]=(a0,a1,a2)=>(_logbl=Module["_logbl"]=wasmExports["logbl"])(a0,a1,a2);var _strtoull=Module["_strtoull"]=(a0,a1,a2)=>(_strtoull=Module["_strtoull"]=wasmExports["strtoull"])(a0,a1,a2);var _nrand48=Module["_nrand48"]=a0=>(_nrand48=Module["_nrand48"]=wasmExports["nrand48"])(a0);var _lrand48=Module["_lrand48"]=()=>(_lrand48=Module["_lrand48"]=wasmExports["lrand48"])();var _lrint=Module["_lrint"]=a0=>(_lrint=Module["_lrint"]=wasmExports["lrint"])(a0);var _lrintf=Module["_lrintf"]=a0=>(_lrintf=Module["_lrintf"]=wasmExports["lrintf"])(a0);var _lrintl=Module["_lrintl"]=(a0,a1)=>(_lrintl=Module["_lrintl"]=wasmExports["lrintl"])(a0,a1);var _lround=Module["_lround"]=a0=>(_lround=Module["_lround"]=wasmExports["lround"])(a0);var _lroundf=Module["_lroundf"]=a0=>(_lroundf=Module["_lroundf"]=wasmExports["lroundf"])(a0);var _lroundl=Module["_lroundl"]=(a0,a1)=>(_lroundl=Module["_lroundl"]=wasmExports["lroundl"])(a0,a1);var _lsearch=Module["_lsearch"]=(a0,a1,a2,a3,a4)=>(_lsearch=Module["_lsearch"]=wasmExports["lsearch"])(a0,a1,a2,a3,a4);var _lfind=Module["_lfind"]=(a0,a1,a2,a3,a4)=>(_lfind=Module["_lfind"]=wasmExports["lfind"])(a0,a1,a2,a3,a4);var _mbrlen=Module["_mbrlen"]=(a0,a1,a2)=>(_mbrlen=Module["_mbrlen"]=wasmExports["mbrlen"])(a0,a1,a2);var _mbrtoc16=Module["_mbrtoc16"]=(a0,a1,a2,a3)=>(_mbrtoc16=Module["_mbrtoc16"]=wasmExports["mbrtoc16"])(a0,a1,a2,a3);var _mbrtoc32=Module["_mbrtoc32"]=(a0,a1,a2,a3)=>(_mbrtoc32=Module["_mbrtoc32"]=wasmExports["mbrtoc32"])(a0,a1,a2,a3);var _mbsinit=Module["_mbsinit"]=a0=>(_mbsinit=Module["_mbsinit"]=wasmExports["mbsinit"])(a0);var _mbsnrtowcs=Module["_mbsnrtowcs"]=(a0,a1,a2,a3,a4)=>(_mbsnrtowcs=Module["_mbsnrtowcs"]=wasmExports["mbsnrtowcs"])(a0,a1,a2,a3,a4);var _mbsrtowcs=Module["_mbsrtowcs"]=(a0,a1,a2,a3)=>(_mbsrtowcs=Module["_mbsrtowcs"]=wasmExports["mbsrtowcs"])(a0,a1,a2,a3);var _memccpy=Module["_memccpy"]=(a0,a1,a2,a3)=>(_memccpy=Module["_memccpy"]=wasmExports["memccpy"])(a0,a1,a2,a3);var _memmem=Module["_memmem"]=(a0,a1,a2,a3)=>(_memmem=Module["_memmem"]=wasmExports["memmem"])(a0,a1,a2,a3);var _mempcpy=Module["_mempcpy"]=(a0,a1,a2)=>(_mempcpy=Module["_mempcpy"]=wasmExports["mempcpy"])(a0,a1,a2);var _mincore=Module["_mincore"]=(a0,a1,a2)=>(_mincore=Module["_mincore"]=wasmExports["mincore"])(a0,a1,a2);var _mkdtemp=Module["_mkdtemp"]=a0=>(_mkdtemp=Module["_mkdtemp"]=wasmExports["mkdtemp"])(a0);var _mkfifo=Module["_mkfifo"]=(a0,a1)=>(_mkfifo=Module["_mkfifo"]=wasmExports["mkfifo"])(a0,a1);var _mkfifoat=Module["_mkfifoat"]=(a0,a1,a2)=>(_mkfifoat=Module["_mkfifoat"]=wasmExports["mkfifoat"])(a0,a1,a2);var _mkostemp=Module["_mkostemp"]=(a0,a1)=>(_mkostemp=Module["_mkostemp"]=wasmExports["mkostemp"])(a0,a1);var _mkostemps=Module["_mkostemps"]=(a0,a1,a2)=>(_mkostemps=Module["_mkostemps"]=wasmExports["mkostemps"])(a0,a1,a2);var _mkstemp=Module["_mkstemp"]=a0=>(_mkstemp=Module["_mkstemp"]=wasmExports["mkstemp"])(a0);var _mkstemps=Module["_mkstemps"]=(a0,a1)=>(_mkstemps=Module["_mkstemps"]=wasmExports["mkstemps"])(a0,a1);var _mktemp=Module["_mktemp"]=a0=>(_mktemp=Module["_mktemp"]=wasmExports["mktemp"])(a0);var _timegm=Module["_timegm"]=a0=>(_timegm=Module["_timegm"]=wasmExports["timegm"])(a0);var _tzset=Module["_tzset"]=()=>(_tzset=Module["_tzset"]=wasmExports["tzset"])();var _mlock=Module["_mlock"]=(a0,a1)=>(_mlock=Module["_mlock"]=wasmExports["mlock"])(a0,a1);var _mlockall=Module["_mlockall"]=a0=>(_mlockall=Module["_mlockall"]=wasmExports["mlockall"])(a0);var _emscripten_builtin_mmap=Module["_emscripten_builtin_mmap"]=(a0,a1,a2,a3,a4,a5)=>(_emscripten_builtin_mmap=Module["_emscripten_builtin_mmap"]=wasmExports["emscripten_builtin_mmap"])(a0,a1,a2,a3,a4,a5);var _setmntent=Module["_setmntent"]=(a0,a1)=>(_setmntent=Module["_setmntent"]=wasmExports["setmntent"])(a0,a1);var _endmntent=Module["_endmntent"]=a0=>(_endmntent=Module["_endmntent"]=wasmExports["endmntent"])(a0);var _getmntent_r=Module["_getmntent_r"]=(a0,a1,a2,a3)=>(_getmntent_r=Module["_getmntent_r"]=wasmExports["getmntent_r"])(a0,a1,a2,a3);var _sscanf=Module["_sscanf"]=(a0,a1,a2)=>(_sscanf=Module["_sscanf"]=wasmExports["sscanf"])(a0,a1,a2);var _getmntent=Module["_getmntent"]=a0=>(_getmntent=Module["_getmntent"]=wasmExports["getmntent"])(a0);var _addmntent=Module["_addmntent"]=(a0,a1)=>(_addmntent=Module["_addmntent"]=wasmExports["addmntent"])(a0,a1);var _hasmntopt=Module["_hasmntopt"]=(a0,a1)=>(_hasmntopt=Module["_hasmntopt"]=wasmExports["hasmntopt"])(a0,a1);var _mprotect=Module["_mprotect"]=(a0,a1,a2)=>(_mprotect=Module["_mprotect"]=wasmExports["mprotect"])(a0,a1,a2);var _jrand48=Module["_jrand48"]=a0=>(_jrand48=Module["_jrand48"]=wasmExports["jrand48"])(a0);var _mrand48=Module["_mrand48"]=()=>(_mrand48=Module["_mrand48"]=wasmExports["mrand48"])();var _mtx_destroy=Module["_mtx_destroy"]=a0=>(_mtx_destroy=Module["_mtx_destroy"]=wasmExports["mtx_destroy"])(a0);var _mtx_init=Module["_mtx_init"]=(a0,a1)=>(_mtx_init=Module["_mtx_init"]=wasmExports["mtx_init"])(a0,a1);var _mtx_lock=Module["_mtx_lock"]=a0=>(_mtx_lock=Module["_mtx_lock"]=wasmExports["mtx_lock"])(a0);var _mtx_timedlock=Module["_mtx_timedlock"]=(a0,a1)=>(_mtx_timedlock=Module["_mtx_timedlock"]=wasmExports["mtx_timedlock"])(a0,a1);var _mtx_trylock=Module["_mtx_trylock"]=a0=>(_mtx_trylock=Module["_mtx_trylock"]=wasmExports["mtx_trylock"])(a0);var _mtx_unlock=Module["_mtx_unlock"]=a0=>(_mtx_unlock=Module["_mtx_unlock"]=wasmExports["mtx_unlock"])(a0);var _munlock=Module["_munlock"]=(a0,a1)=>(_munlock=Module["_munlock"]=wasmExports["munlock"])(a0,a1);var _munlockall=Module["_munlockall"]=()=>(_munlockall=Module["_munlockall"]=wasmExports["munlockall"])();var _emscripten_builtin_munmap=Module["_emscripten_builtin_munmap"]=(a0,a1)=>(_emscripten_builtin_munmap=Module["_emscripten_builtin_munmap"]=wasmExports["emscripten_builtin_munmap"])(a0,a1);var _nan=Module["_nan"]=a0=>(_nan=Module["_nan"]=wasmExports["nan"])(a0);var _nanf=Module["_nanf"]=a0=>(_nanf=Module["_nanf"]=wasmExports["nanf"])(a0);var _nanl=Module["_nanl"]=(a0,a1)=>(_nanl=Module["_nanl"]=wasmExports["nanl"])(a0,a1);var _nanosleep=Module["_nanosleep"]=(a0,a1)=>(_nanosleep=Module["_nanosleep"]=wasmExports["nanosleep"])(a0,a1);var _nearbyint=Module["_nearbyint"]=a0=>(_nearbyint=Module["_nearbyint"]=wasmExports["nearbyint"])(a0);var _nearbyintf=Module["_nearbyintf"]=a0=>(_nearbyintf=Module["_nearbyintf"]=wasmExports["nearbyintf"])(a0);var _nearbyintl=Module["_nearbyintl"]=(a0,a1,a2)=>(_nearbyintl=Module["_nearbyintl"]=wasmExports["nearbyintl"])(a0,a1,a2);var _getnetbyaddr=Module["_getnetbyaddr"]=(a0,a1)=>(_getnetbyaddr=Module["_getnetbyaddr"]=wasmExports["getnetbyaddr"])(a0,a1);var _getnetbyname=Module["_getnetbyname"]=a0=>(_getnetbyname=Module["_getnetbyname"]=wasmExports["getnetbyname"])(a0);var ___newlocale=Module["___newlocale"]=(a0,a1,a2)=>(___newlocale=Module["___newlocale"]=wasmExports["__newlocale"])(a0,a1,a2);var _newlocale=Module["_newlocale"]=(a0,a1,a2)=>(_newlocale=Module["_newlocale"]=wasmExports["newlocale"])(a0,a1,a2);var _nextafterf=Module["_nextafterf"]=(a0,a1)=>(_nextafterf=Module["_nextafterf"]=wasmExports["nextafterf"])(a0,a1);var _nexttoward=Module["_nexttoward"]=(a0,a1,a2)=>(_nexttoward=Module["_nexttoward"]=wasmExports["nexttoward"])(a0,a1,a2);var _nexttowardf=Module["_nexttowardf"]=(a0,a1,a2)=>(_nexttowardf=Module["_nexttowardf"]=wasmExports["nexttowardf"])(a0,a1,a2);var _nexttowardl=Module["_nexttowardl"]=(a0,a1,a2,a3,a4)=>(_nexttowardl=Module["_nexttowardl"]=wasmExports["nexttowardl"])(a0,a1,a2,a3,a4);var _nftw=Module["_nftw"]=(a0,a1,a2,a3)=>(_nftw=Module["_nftw"]=wasmExports["nftw"])(a0,a1,a2,a3);var _nice=Module["_nice"]=a0=>(_nice=Module["_nice"]=wasmExports["nice"])(a0);var _setpriority=Module["_setpriority"]=(a0,a1,a2)=>(_setpriority=Module["_setpriority"]=wasmExports["setpriority"])(a0,a1,a2);var _ns_get16=Module["_ns_get16"]=a0=>(_ns_get16=Module["_ns_get16"]=wasmExports["ns_get16"])(a0);var _ns_get32=Module["_ns_get32"]=a0=>(_ns_get32=Module["_ns_get32"]=wasmExports["ns_get32"])(a0);var _ns_put16=Module["_ns_put16"]=(a0,a1)=>(_ns_put16=Module["_ns_put16"]=wasmExports["ns_put16"])(a0,a1);var _ns_put32=Module["_ns_put32"]=(a0,a1)=>(_ns_put32=Module["_ns_put32"]=wasmExports["ns_put32"])(a0,a1);var _ns_skiprr=Module["_ns_skiprr"]=(a0,a1,a2,a3)=>(_ns_skiprr=Module["_ns_skiprr"]=wasmExports["ns_skiprr"])(a0,a1,a2,a3);var _ns_initparse=Module["_ns_initparse"]=(a0,a1,a2)=>(_ns_initparse=Module["_ns_initparse"]=wasmExports["ns_initparse"])(a0,a1,a2);var _ns_name_uncompress=Module["_ns_name_uncompress"]=(a0,a1,a2,a3,a4)=>(_ns_name_uncompress=Module["_ns_name_uncompress"]=wasmExports["ns_name_uncompress"])(a0,a1,a2,a3,a4);var _ns_parserr=Module["_ns_parserr"]=(a0,a1,a2,a3)=>(_ns_parserr=Module["_ns_parserr"]=wasmExports["ns_parserr"])(a0,a1,a2,a3);var _open_memstream=Module["_open_memstream"]=(a0,a1)=>(_open_memstream=Module["_open_memstream"]=wasmExports["open_memstream"])(a0,a1);var _open_wmemstream=Module["_open_wmemstream"]=(a0,a1)=>(_open_wmemstream=Module["_open_wmemstream"]=wasmExports["open_wmemstream"])(a0,a1);var _tcsetattr=Module["_tcsetattr"]=(a0,a1,a2)=>(_tcsetattr=Module["_tcsetattr"]=wasmExports["tcsetattr"])(a0,a1,a2);var _posix_close=Module["_posix_close"]=(a0,a1)=>(_posix_close=Module["_posix_close"]=wasmExports["posix_close"])(a0,a1);var _posix_fallocate=Module["_posix_fallocate"]=(a0,a1,a2)=>(_posix_fallocate=Module["_posix_fallocate"]=wasmExports["posix_fallocate"])(a0,a1,a2);var _posix_madvise=Module["_posix_madvise"]=(a0,a1,a2)=>(_posix_madvise=Module["_posix_madvise"]=wasmExports["posix_madvise"])(a0,a1,a2);var _posix_spawn_file_actions_addchdir_np=Module["_posix_spawn_file_actions_addchdir_np"]=(a0,a1)=>(_posix_spawn_file_actions_addchdir_np=Module["_posix_spawn_file_actions_addchdir_np"]=wasmExports["posix_spawn_file_actions_addchdir_np"])(a0,a1);var _posix_spawn_file_actions_addclose=Module["_posix_spawn_file_actions_addclose"]=(a0,a1)=>(_posix_spawn_file_actions_addclose=Module["_posix_spawn_file_actions_addclose"]=wasmExports["posix_spawn_file_actions_addclose"])(a0,a1);var _posix_spawn_file_actions_adddup2=Module["_posix_spawn_file_actions_adddup2"]=(a0,a1,a2)=>(_posix_spawn_file_actions_adddup2=Module["_posix_spawn_file_actions_adddup2"]=wasmExports["posix_spawn_file_actions_adddup2"])(a0,a1,a2);var _posix_spawn_file_actions_addfchdir_np=Module["_posix_spawn_file_actions_addfchdir_np"]=(a0,a1)=>(_posix_spawn_file_actions_addfchdir_np=Module["_posix_spawn_file_actions_addfchdir_np"]=wasmExports["posix_spawn_file_actions_addfchdir_np"])(a0,a1);var _posix_spawn_file_actions_addopen=Module["_posix_spawn_file_actions_addopen"]=(a0,a1,a2,a3,a4)=>(_posix_spawn_file_actions_addopen=Module["_posix_spawn_file_actions_addopen"]=wasmExports["posix_spawn_file_actions_addopen"])(a0,a1,a2,a3,a4);var _posix_spawn_file_actions_destroy=Module["_posix_spawn_file_actions_destroy"]=a0=>(_posix_spawn_file_actions_destroy=Module["_posix_spawn_file_actions_destroy"]=wasmExports["posix_spawn_file_actions_destroy"])(a0);var _posix_spawn_file_actions_init=Module["_posix_spawn_file_actions_init"]=a0=>(_posix_spawn_file_actions_init=Module["_posix_spawn_file_actions_init"]=wasmExports["posix_spawn_file_actions_init"])(a0);var _posix_spawnattr_destroy=Module["_posix_spawnattr_destroy"]=a0=>(_posix_spawnattr_destroy=Module["_posix_spawnattr_destroy"]=wasmExports["posix_spawnattr_destroy"])(a0);var _posix_spawnattr_getflags=Module["_posix_spawnattr_getflags"]=(a0,a1)=>(_posix_spawnattr_getflags=Module["_posix_spawnattr_getflags"]=wasmExports["posix_spawnattr_getflags"])(a0,a1);var _posix_spawnattr_getpgroup=Module["_posix_spawnattr_getpgroup"]=(a0,a1)=>(_posix_spawnattr_getpgroup=Module["_posix_spawnattr_getpgroup"]=wasmExports["posix_spawnattr_getpgroup"])(a0,a1);var _posix_spawnattr_getsigdefault=Module["_posix_spawnattr_getsigdefault"]=(a0,a1)=>(_posix_spawnattr_getsigdefault=Module["_posix_spawnattr_getsigdefault"]=wasmExports["posix_spawnattr_getsigdefault"])(a0,a1);var _posix_spawnattr_getsigmask=Module["_posix_spawnattr_getsigmask"]=(a0,a1)=>(_posix_spawnattr_getsigmask=Module["_posix_spawnattr_getsigmask"]=wasmExports["posix_spawnattr_getsigmask"])(a0,a1);var _posix_spawnattr_init=Module["_posix_spawnattr_init"]=a0=>(_posix_spawnattr_init=Module["_posix_spawnattr_init"]=wasmExports["posix_spawnattr_init"])(a0);var _posix_spawnattr_getschedparam=Module["_posix_spawnattr_getschedparam"]=(a0,a1)=>(_posix_spawnattr_getschedparam=Module["_posix_spawnattr_getschedparam"]=wasmExports["posix_spawnattr_getschedparam"])(a0,a1);var _posix_spawnattr_setschedparam=Module["_posix_spawnattr_setschedparam"]=(a0,a1)=>(_posix_spawnattr_setschedparam=Module["_posix_spawnattr_setschedparam"]=wasmExports["posix_spawnattr_setschedparam"])(a0,a1);var _posix_spawnattr_getschedpolicy=Module["_posix_spawnattr_getschedpolicy"]=(a0,a1)=>(_posix_spawnattr_getschedpolicy=Module["_posix_spawnattr_getschedpolicy"]=wasmExports["posix_spawnattr_getschedpolicy"])(a0,a1);var _posix_spawnattr_setschedpolicy=Module["_posix_spawnattr_setschedpolicy"]=(a0,a1)=>(_posix_spawnattr_setschedpolicy=Module["_posix_spawnattr_setschedpolicy"]=wasmExports["posix_spawnattr_setschedpolicy"])(a0,a1);var _posix_spawnattr_setflags=Module["_posix_spawnattr_setflags"]=(a0,a1)=>(_posix_spawnattr_setflags=Module["_posix_spawnattr_setflags"]=wasmExports["posix_spawnattr_setflags"])(a0,a1);var _posix_spawnattr_setpgroup=Module["_posix_spawnattr_setpgroup"]=(a0,a1)=>(_posix_spawnattr_setpgroup=Module["_posix_spawnattr_setpgroup"]=wasmExports["posix_spawnattr_setpgroup"])(a0,a1);var _posix_spawnattr_setsigdefault=Module["_posix_spawnattr_setsigdefault"]=(a0,a1)=>(_posix_spawnattr_setsigdefault=Module["_posix_spawnattr_setsigdefault"]=wasmExports["posix_spawnattr_setsigdefault"])(a0,a1);var _posix_spawnattr_setsigmask=Module["_posix_spawnattr_setsigmask"]=(a0,a1)=>(_posix_spawnattr_setsigmask=Module["_posix_spawnattr_setsigmask"]=wasmExports["posix_spawnattr_setsigmask"])(a0,a1);var _powf=Module["_powf"]=(a0,a1)=>(_powf=Module["_powf"]=wasmExports["powf"])(a0,a1);var _preadv=Module["_preadv"]=(a0,a1,a2,a3)=>(_preadv=Module["_preadv"]=wasmExports["preadv"])(a0,a1,a2,a3);var _printf=Module["_printf"]=(a0,a1)=>(_printf=Module["_printf"]=wasmExports["printf"])(a0,a1);var ___small_printf=Module["___small_printf"]=(a0,a1)=>(___small_printf=Module["___small_printf"]=wasmExports["__small_printf"])(a0,a1);var _em_proxying_queue_create=Module["_em_proxying_queue_create"]=()=>(_em_proxying_queue_create=Module["_em_proxying_queue_create"]=wasmExports["em_proxying_queue_create"])();var _em_proxying_queue_destroy=Module["_em_proxying_queue_destroy"]=a0=>(_em_proxying_queue_destroy=Module["_em_proxying_queue_destroy"]=wasmExports["em_proxying_queue_destroy"])(a0);var _emscripten_proxy_get_system_queue=Module["_emscripten_proxy_get_system_queue"]=()=>(_emscripten_proxy_get_system_queue=Module["_emscripten_proxy_get_system_queue"]=wasmExports["emscripten_proxy_get_system_queue"])();var _emscripten_proxy_execute_queue=Module["_emscripten_proxy_execute_queue"]=a0=>(_emscripten_proxy_execute_queue=Module["_emscripten_proxy_execute_queue"]=wasmExports["emscripten_proxy_execute_queue"])(a0);var _emscripten_proxy_finish=Module["_emscripten_proxy_finish"]=a0=>(_emscripten_proxy_finish=Module["_emscripten_proxy_finish"]=wasmExports["emscripten_proxy_finish"])(a0);var _emscripten_proxy_async=Module["_emscripten_proxy_async"]=(a0,a1,a2,a3)=>(_emscripten_proxy_async=Module["_emscripten_proxy_async"]=wasmExports["emscripten_proxy_async"])(a0,a1,a2,a3);var _emscripten_proxy_sync=Module["_emscripten_proxy_sync"]=(a0,a1,a2,a3)=>(_emscripten_proxy_sync=Module["_emscripten_proxy_sync"]=wasmExports["emscripten_proxy_sync"])(a0,a1,a2,a3);var _emscripten_proxy_sync_with_ctx=Module["_emscripten_proxy_sync_with_ctx"]=(a0,a1,a2,a3)=>(_emscripten_proxy_sync_with_ctx=Module["_emscripten_proxy_sync_with_ctx"]=wasmExports["emscripten_proxy_sync_with_ctx"])(a0,a1,a2,a3);var _pselect=Module["_pselect"]=(a0,a1,a2,a3,a4,a5)=>(_pselect=Module["_pselect"]=wasmExports["pselect"])(a0,a1,a2,a3,a4,a5);var _pthread_attr_getdetachstate=Module["_pthread_attr_getdetachstate"]=(a0,a1)=>(_pthread_attr_getdetachstate=Module["_pthread_attr_getdetachstate"]=wasmExports["pthread_attr_getdetachstate"])(a0,a1);var _pthread_attr_getguardsize=Module["_pthread_attr_getguardsize"]=(a0,a1)=>(_pthread_attr_getguardsize=Module["_pthread_attr_getguardsize"]=wasmExports["pthread_attr_getguardsize"])(a0,a1);var _pthread_attr_getinheritsched=Module["_pthread_attr_getinheritsched"]=(a0,a1)=>(_pthread_attr_getinheritsched=Module["_pthread_attr_getinheritsched"]=wasmExports["pthread_attr_getinheritsched"])(a0,a1);var _pthread_attr_getschedparam=Module["_pthread_attr_getschedparam"]=(a0,a1)=>(_pthread_attr_getschedparam=Module["_pthread_attr_getschedparam"]=wasmExports["pthread_attr_getschedparam"])(a0,a1);var _pthread_attr_getschedpolicy=Module["_pthread_attr_getschedpolicy"]=(a0,a1)=>(_pthread_attr_getschedpolicy=Module["_pthread_attr_getschedpolicy"]=wasmExports["pthread_attr_getschedpolicy"])(a0,a1);var _pthread_attr_getscope=Module["_pthread_attr_getscope"]=(a0,a1)=>(_pthread_attr_getscope=Module["_pthread_attr_getscope"]=wasmExports["pthread_attr_getscope"])(a0,a1);var _pthread_attr_getstack=Module["_pthread_attr_getstack"]=(a0,a1,a2)=>(_pthread_attr_getstack=Module["_pthread_attr_getstack"]=wasmExports["pthread_attr_getstack"])(a0,a1,a2);var _pthread_attr_getstacksize=Module["_pthread_attr_getstacksize"]=(a0,a1)=>(_pthread_attr_getstacksize=Module["_pthread_attr_getstacksize"]=wasmExports["pthread_attr_getstacksize"])(a0,a1);var _pthread_barrierattr_getpshared=Module["_pthread_barrierattr_getpshared"]=(a0,a1)=>(_pthread_barrierattr_getpshared=Module["_pthread_barrierattr_getpshared"]=wasmExports["pthread_barrierattr_getpshared"])(a0,a1);var _pthread_condattr_getclock=Module["_pthread_condattr_getclock"]=(a0,a1)=>(_pthread_condattr_getclock=Module["_pthread_condattr_getclock"]=wasmExports["pthread_condattr_getclock"])(a0,a1);var _pthread_condattr_getpshared=Module["_pthread_condattr_getpshared"]=(a0,a1)=>(_pthread_condattr_getpshared=Module["_pthread_condattr_getpshared"]=wasmExports["pthread_condattr_getpshared"])(a0,a1);var _pthread_mutexattr_getprotocol=Module["_pthread_mutexattr_getprotocol"]=(a0,a1)=>(_pthread_mutexattr_getprotocol=Module["_pthread_mutexattr_getprotocol"]=wasmExports["pthread_mutexattr_getprotocol"])(a0,a1);var _pthread_mutexattr_getpshared=Module["_pthread_mutexattr_getpshared"]=(a0,a1)=>(_pthread_mutexattr_getpshared=Module["_pthread_mutexattr_getpshared"]=wasmExports["pthread_mutexattr_getpshared"])(a0,a1);var _pthread_mutexattr_getrobust=Module["_pthread_mutexattr_getrobust"]=(a0,a1)=>(_pthread_mutexattr_getrobust=Module["_pthread_mutexattr_getrobust"]=wasmExports["pthread_mutexattr_getrobust"])(a0,a1);var _pthread_mutexattr_gettype=Module["_pthread_mutexattr_gettype"]=(a0,a1)=>(_pthread_mutexattr_gettype=Module["_pthread_mutexattr_gettype"]=wasmExports["pthread_mutexattr_gettype"])(a0,a1);var _pthread_rwlockattr_getpshared=Module["_pthread_rwlockattr_getpshared"]=(a0,a1)=>(_pthread_rwlockattr_getpshared=Module["_pthread_rwlockattr_getpshared"]=wasmExports["pthread_rwlockattr_getpshared"])(a0,a1);var _pthread_attr_setdetachstate=Module["_pthread_attr_setdetachstate"]=(a0,a1)=>(_pthread_attr_setdetachstate=Module["_pthread_attr_setdetachstate"]=wasmExports["pthread_attr_setdetachstate"])(a0,a1);var _pthread_attr_setguardsize=Module["_pthread_attr_setguardsize"]=(a0,a1)=>(_pthread_attr_setguardsize=Module["_pthread_attr_setguardsize"]=wasmExports["pthread_attr_setguardsize"])(a0,a1);var _pthread_attr_setinheritsched=Module["_pthread_attr_setinheritsched"]=(a0,a1)=>(_pthread_attr_setinheritsched=Module["_pthread_attr_setinheritsched"]=wasmExports["pthread_attr_setinheritsched"])(a0,a1);var _pthread_attr_setschedparam=Module["_pthread_attr_setschedparam"]=(a0,a1)=>(_pthread_attr_setschedparam=Module["_pthread_attr_setschedparam"]=wasmExports["pthread_attr_setschedparam"])(a0,a1);var _pthread_attr_setschedpolicy=Module["_pthread_attr_setschedpolicy"]=(a0,a1)=>(_pthread_attr_setschedpolicy=Module["_pthread_attr_setschedpolicy"]=wasmExports["pthread_attr_setschedpolicy"])(a0,a1);var _pthread_attr_setscope=Module["_pthread_attr_setscope"]=(a0,a1)=>(_pthread_attr_setscope=Module["_pthread_attr_setscope"]=wasmExports["pthread_attr_setscope"])(a0,a1);var _pthread_attr_setstack=Module["_pthread_attr_setstack"]=(a0,a1,a2)=>(_pthread_attr_setstack=Module["_pthread_attr_setstack"]=wasmExports["pthread_attr_setstack"])(a0,a1,a2);var __pthread_cleanup_push=Module["__pthread_cleanup_push"]=(a0,a1,a2)=>(__pthread_cleanup_push=Module["__pthread_cleanup_push"]=wasmExports["_pthread_cleanup_push"])(a0,a1,a2);var __pthread_cleanup_pop=Module["__pthread_cleanup_pop"]=(a0,a1)=>(__pthread_cleanup_pop=Module["__pthread_cleanup_pop"]=wasmExports["_pthread_cleanup_pop"])(a0,a1);var _pthread_getconcurrency=Module["_pthread_getconcurrency"]=()=>(_pthread_getconcurrency=Module["_pthread_getconcurrency"]=wasmExports["pthread_getconcurrency"])();var _pthread_getschedparam=Module["_pthread_getschedparam"]=(a0,a1,a2)=>(_pthread_getschedparam=Module["_pthread_getschedparam"]=wasmExports["pthread_getschedparam"])(a0,a1,a2);var _thrd_current=Module["_thrd_current"]=()=>(_thrd_current=Module["_thrd_current"]=wasmExports["thrd_current"])();var _emscripten_main_runtime_thread_id=Module["_emscripten_main_runtime_thread_id"]=()=>(_emscripten_main_runtime_thread_id=Module["_emscripten_main_runtime_thread_id"]=wasmExports["emscripten_main_runtime_thread_id"])();var _pthread_setconcurrency=Module["_pthread_setconcurrency"]=a0=>(_pthread_setconcurrency=Module["_pthread_setconcurrency"]=wasmExports["pthread_setconcurrency"])(a0);var _pthread_setschedprio=Module["_pthread_setschedprio"]=(a0,a1)=>(_pthread_setschedprio=Module["_pthread_setschedprio"]=wasmExports["pthread_setschedprio"])(a0,a1);var ___sig_is_blocked=Module["___sig_is_blocked"]=a0=>(___sig_is_blocked=Module["___sig_is_blocked"]=wasmExports["__sig_is_blocked"])(a0);var _sigorset=Module["_sigorset"]=(a0,a1,a2)=>(_sigorset=Module["_sigorset"]=wasmExports["sigorset"])(a0,a1,a2);var _sigandset=Module["_sigandset"]=(a0,a1,a2)=>(_sigandset=Module["_sigandset"]=wasmExports["sigandset"])(a0,a1,a2);var _sigdelset=Module["_sigdelset"]=(a0,a1)=>(_sigdelset=Module["_sigdelset"]=wasmExports["sigdelset"])(a0,a1);var _ptsname=Module["_ptsname"]=a0=>(_ptsname=Module["_ptsname"]=wasmExports["ptsname"])(a0);var _posix_openpt=Module["_posix_openpt"]=a0=>(_posix_openpt=Module["_posix_openpt"]=wasmExports["posix_openpt"])(a0);var _grantpt=Module["_grantpt"]=a0=>(_grantpt=Module["_grantpt"]=wasmExports["grantpt"])(a0);var _unlockpt=Module["_unlockpt"]=a0=>(_unlockpt=Module["_unlockpt"]=wasmExports["unlockpt"])(a0);var _ptsname_r=Module["_ptsname_r"]=(a0,a1,a2)=>(_ptsname_r=Module["_ptsname_r"]=wasmExports["ptsname_r"])(a0,a1,a2);var __IO_putc=Module["__IO_putc"]=(a0,a1)=>(__IO_putc=Module["__IO_putc"]=wasmExports["_IO_putc"])(a0,a1);var _putc_unlocked=Module["_putc_unlocked"]=(a0,a1)=>(_putc_unlocked=Module["_putc_unlocked"]=wasmExports["putc_unlocked"])(a0,a1);var _fputc_unlocked=Module["_fputc_unlocked"]=(a0,a1)=>(_fputc_unlocked=Module["_fputc_unlocked"]=wasmExports["fputc_unlocked"])(a0,a1);var __IO_putc_unlocked=Module["__IO_putc_unlocked"]=(a0,a1)=>(__IO_putc_unlocked=Module["__IO_putc_unlocked"]=wasmExports["_IO_putc_unlocked"])(a0,a1);var _putchar_unlocked=Module["_putchar_unlocked"]=a0=>(_putchar_unlocked=Module["_putchar_unlocked"]=wasmExports["putchar_unlocked"])(a0);var _putenv=Module["_putenv"]=a0=>(_putenv=Module["_putenv"]=wasmExports["putenv"])(a0);var _putw=Module["_putw"]=(a0,a1)=>(_putw=Module["_putw"]=wasmExports["putw"])(a0,a1);var _putwc=Module["_putwc"]=(a0,a1)=>(_putwc=Module["_putwc"]=wasmExports["putwc"])(a0,a1);var _putwchar=Module["_putwchar"]=a0=>(_putwchar=Module["_putwchar"]=wasmExports["putwchar"])(a0);var _putwchar_unlocked=Module["_putwchar_unlocked"]=a0=>(_putwchar_unlocked=Module["_putwchar_unlocked"]=wasmExports["putwchar_unlocked"])(a0);var _pwritev=Module["_pwritev"]=(a0,a1,a2,a3)=>(_pwritev=Module["_pwritev"]=wasmExports["pwritev"])(a0,a1,a2,a3);var _qsort_r=Module["_qsort_r"]=(a0,a1,a2,a3,a4)=>(_qsort_r=Module["_qsort_r"]=wasmExports["qsort_r"])(a0,a1,a2,a3,a4);var _quick_exit=Module["_quick_exit"]=a0=>(_quick_exit=Module["_quick_exit"]=wasmExports["quick_exit"])(a0);var _action_abort=Module["_action_abort"]=a0=>(_action_abort=Module["_action_abort"]=wasmExports["action_abort"])(a0);var _action_terminate=Module["_action_terminate"]=a0=>(_action_terminate=Module["_action_terminate"]=wasmExports["action_terminate"])(a0);var _srand=Module["_srand"]=a0=>(_srand=Module["_srand"]=wasmExports["srand"])(a0);var _rand=Module["_rand"]=()=>(_rand=Module["_rand"]=wasmExports["rand"])();var _rand_r=Module["_rand_r"]=a0=>(_rand_r=Module["_rand_r"]=wasmExports["rand_r"])(a0);var _srandom=Module["_srandom"]=a0=>(_srandom=Module["_srandom"]=wasmExports["srandom"])(a0);var _initstate=Module["_initstate"]=(a0,a1,a2)=>(_initstate=Module["_initstate"]=wasmExports["initstate"])(a0,a1,a2);var _setstate=Module["_setstate"]=a0=>(_setstate=Module["_setstate"]=wasmExports["setstate"])(a0);var _random=Module["_random"]=()=>(_random=Module["_random"]=wasmExports["random"])();var _readdir_r=Module["_readdir_r"]=(a0,a1,a2)=>(_readdir_r=Module["_readdir_r"]=wasmExports["readdir_r"])(a0,a1,a2);var _recvmmsg=Module["_recvmmsg"]=(a0,a1,a2,a3,a4)=>(_recvmmsg=Module["_recvmmsg"]=wasmExports["recvmmsg"])(a0,a1,a2,a3,a4);var _regcomp=Module["_regcomp"]=(a0,a1,a2)=>(_regcomp=Module["_regcomp"]=wasmExports["regcomp"])(a0,a1,a2);var _regfree=Module["_regfree"]=a0=>(_regfree=Module["_regfree"]=wasmExports["regfree"])(a0);var _regerror=Module["_regerror"]=(a0,a1,a2,a3)=>(_regerror=Module["_regerror"]=wasmExports["regerror"])(a0,a1,a2,a3);var _regexec=Module["_regexec"]=(a0,a1,a2,a3,a4)=>(_regexec=Module["_regexec"]=wasmExports["regexec"])(a0,a1,a2,a3,a4);var _remainder=Module["_remainder"]=(a0,a1)=>(_remainder=Module["_remainder"]=wasmExports["remainder"])(a0,a1);var _remquo=Module["_remquo"]=(a0,a1,a2)=>(_remquo=Module["_remquo"]=wasmExports["remquo"])(a0,a1,a2);var _drem=Module["_drem"]=(a0,a1)=>(_drem=Module["_drem"]=wasmExports["drem"])(a0,a1);var _remainderf=Module["_remainderf"]=(a0,a1)=>(_remainderf=Module["_remainderf"]=wasmExports["remainderf"])(a0,a1);var _remquof=Module["_remquof"]=(a0,a1,a2)=>(_remquof=Module["_remquof"]=wasmExports["remquof"])(a0,a1,a2);var _dremf=Module["_dremf"]=(a0,a1)=>(_dremf=Module["_dremf"]=wasmExports["dremf"])(a0,a1);var _remainderl=Module["_remainderl"]=(a0,a1,a2,a3,a4)=>(_remainderl=Module["_remainderl"]=wasmExports["remainderl"])(a0,a1,a2,a3,a4);var _remquol=Module["_remquol"]=(a0,a1,a2,a3,a4,a5)=>(_remquol=Module["_remquol"]=wasmExports["remquol"])(a0,a1,a2,a3,a4,a5);var _remove=Module["_remove"]=a0=>(_remove=Module["_remove"]=wasmExports["remove"])(a0);var _res_init=Module["_res_init"]=()=>(_res_init=Module["_res_init"]=wasmExports["res_init"])();var _res_mkquery=Module["_res_mkquery"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(_res_mkquery=Module["_res_mkquery"]=wasmExports["res_mkquery"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var ___res_msend=Module["___res_msend"]=(a0,a1,a2,a3,a4,a5)=>(___res_msend=Module["___res_msend"]=wasmExports["__res_msend"])(a0,a1,a2,a3,a4,a5);var _res_send=Module["_res_send"]=(a0,a1,a2,a3)=>(_res_send=Module["_res_send"]=wasmExports["res_send"])(a0,a1,a2,a3);var ___res_state=Module["___res_state"]=()=>(___res_state=Module["___res_state"]=wasmExports["__res_state"])();var _rindex=Module["_rindex"]=(a0,a1)=>(_rindex=Module["_rindex"]=wasmExports["rindex"])(a0,a1);var _emscripten_get_sbrk_ptr=Module["_emscripten_get_sbrk_ptr"]=()=>(_emscripten_get_sbrk_ptr=Module["_emscripten_get_sbrk_ptr"]=wasmExports["emscripten_get_sbrk_ptr"])();var _sbrk=Module["_sbrk"]=a0=>(_sbrk=Module["_sbrk"]=wasmExports["sbrk"])(a0);var _brk=Module["_brk"]=a0=>(_brk=Module["_brk"]=wasmExports["brk"])(a0);var _scalb=Module["_scalb"]=(a0,a1)=>(_scalb=Module["_scalb"]=wasmExports["scalb"])(a0,a1);var _scalbf=Module["_scalbf"]=(a0,a1)=>(_scalbf=Module["_scalbf"]=wasmExports["scalbf"])(a0,a1);var _scalbln=Module["_scalbln"]=(a0,a1)=>(_scalbln=Module["_scalbln"]=wasmExports["scalbln"])(a0,a1);var _scalblnf=Module["_scalblnf"]=(a0,a1)=>(_scalblnf=Module["_scalblnf"]=wasmExports["scalblnf"])(a0,a1);var _scalblnl=Module["_scalblnl"]=(a0,a1,a2,a3)=>(_scalblnl=Module["_scalblnl"]=wasmExports["scalblnl"])(a0,a1,a2,a3);var _scandir=Module["_scandir"]=(a0,a1,a2,a3)=>(_scandir=Module["_scandir"]=wasmExports["scandir"])(a0,a1,a2,a3);var _scanf=Module["_scanf"]=(a0,a1)=>(_scanf=Module["_scanf"]=wasmExports["scanf"])(a0,a1);var _vscanf=Module["_vscanf"]=(a0,a1)=>(_vscanf=Module["_vscanf"]=wasmExports["vscanf"])(a0,a1);var ___isoc99_scanf=Module["___isoc99_scanf"]=(a0,a1)=>(___isoc99_scanf=Module["___isoc99_scanf"]=wasmExports["__isoc99_scanf"])(a0,a1);var _secure_getenv=Module["_secure_getenv"]=a0=>(_secure_getenv=Module["_secure_getenv"]=wasmExports["secure_getenv"])(a0);var _seed48=Module["_seed48"]=a0=>(_seed48=Module["_seed48"]=wasmExports["seed48"])(a0);var _seekdir=Module["_seekdir"]=(a0,a1)=>(_seekdir=Module["_seekdir"]=wasmExports["seekdir"])(a0,a1);var _sendmmsg=Module["_sendmmsg"]=(a0,a1,a2,a3)=>(_sendmmsg=Module["_sendmmsg"]=wasmExports["sendmmsg"])(a0,a1,a2,a3);var _endservent=Module["_endservent"]=()=>(_endservent=Module["_endservent"]=wasmExports["endservent"])();var _setservent=Module["_setservent"]=a0=>(_setservent=Module["_setservent"]=wasmExports["setservent"])(a0);var _getservent=Module["_getservent"]=()=>(_getservent=Module["_getservent"]=wasmExports["getservent"])();var _setbuf=Module["_setbuf"]=(a0,a1)=>(_setbuf=Module["_setbuf"]=wasmExports["setbuf"])(a0,a1);var _setbuffer=Module["_setbuffer"]=(a0,a1,a2)=>(_setbuffer=Module["_setbuffer"]=wasmExports["setbuffer"])(a0,a1,a2);var _setdomainname=Module["_setdomainname"]=(a0,a1)=>(_setdomainname=Module["_setdomainname"]=wasmExports["setdomainname"])(a0,a1);var _setegid=Module["_setegid"]=a0=>(_setegid=Module["_setegid"]=wasmExports["setegid"])(a0);var _seteuid=Module["_seteuid"]=a0=>(_seteuid=Module["_seteuid"]=wasmExports["seteuid"])(a0);var __emscripten_timeout=(a0,a1)=>(__emscripten_timeout=wasmExports["_emscripten_timeout"])(a0,a1);var _setlinebuf=Module["_setlinebuf"]=a0=>(_setlinebuf=Module["_setlinebuf"]=wasmExports["setlinebuf"])(a0);var _setresgid=Module["_setresgid"]=(a0,a1,a2)=>(_setresgid=Module["_setresgid"]=wasmExports["setresgid"])(a0,a1,a2);var _setresuid=Module["_setresuid"]=(a0,a1,a2)=>(_setresuid=Module["_setresuid"]=wasmExports["setresuid"])(a0,a1,a2);var _shm_open=Module["_shm_open"]=(a0,a1,a2)=>(_shm_open=Module["_shm_open"]=wasmExports["shm_open"])(a0,a1,a2);var _shm_unlink=Module["_shm_unlink"]=a0=>(_shm_unlink=Module["_shm_unlink"]=wasmExports["shm_unlink"])(a0);var _sigaction=Module["_sigaction"]=(a0,a1,a2)=>(_sigaction=Module["_sigaction"]=wasmExports["sigaction"])(a0,a1,a2);var _sigisemptyset=Module["_sigisemptyset"]=a0=>(_sigisemptyset=Module["_sigisemptyset"]=wasmExports["sigisemptyset"])(a0);var _bsd_signal=Module["_bsd_signal"]=(a0,a1)=>(_bsd_signal=Module["_bsd_signal"]=wasmExports["bsd_signal"])(a0,a1);var ___sysv_signal=Module["___sysv_signal"]=(a0,a1)=>(___sysv_signal=Module["___sysv_signal"]=wasmExports["__sysv_signal"])(a0,a1);var _significand=Module["_significand"]=a0=>(_significand=Module["_significand"]=wasmExports["significand"])(a0);var _significandf=Module["_significandf"]=a0=>(_significandf=Module["_significandf"]=wasmExports["significandf"])(a0);var _sigprocmask=Module["_sigprocmask"]=(a0,a1,a2)=>(_sigprocmask=Module["_sigprocmask"]=wasmExports["sigprocmask"])(a0,a1,a2);var _sincos=Module["_sincos"]=(a0,a1,a2)=>(_sincos=Module["_sincos"]=wasmExports["sincos"])(a0,a1,a2);var _sincosf=Module["_sincosf"]=(a0,a1,a2)=>(_sincosf=Module["_sincosf"]=wasmExports["sincosf"])(a0,a1,a2);var _sincosl=Module["_sincosl"]=(a0,a1,a2,a3)=>(_sincosl=Module["_sincosl"]=wasmExports["sincosl"])(a0,a1,a2,a3);var _sinhl=Module["_sinhl"]=(a0,a1,a2)=>(_sinhl=Module["_sinhl"]=wasmExports["sinhl"])(a0,a1,a2);var _sinl=Module["_sinl"]=(a0,a1,a2)=>(_sinl=Module["_sinl"]=wasmExports["sinl"])(a0,a1,a2);var _sleep=Module["_sleep"]=a0=>(_sleep=Module["_sleep"]=wasmExports["sleep"])(a0);var _sockatmark=Module["_sockatmark"]=a0=>(_sockatmark=Module["_sockatmark"]=wasmExports["sockatmark"])(a0);var _vsprintf=Module["_vsprintf"]=(a0,a1,a2)=>(_vsprintf=Module["_vsprintf"]=wasmExports["vsprintf"])(a0,a1,a2);var _vsiprintf=Module["_vsiprintf"]=(a0,a1,a2)=>(_vsiprintf=Module["_vsiprintf"]=wasmExports["vsiprintf"])(a0,a1,a2);var ___small_sprintf=Module["___small_sprintf"]=(a0,a1,a2)=>(___small_sprintf=Module["___small_sprintf"]=wasmExports["__small_sprintf"])(a0,a1,a2);var ___small_vsprintf=Module["___small_vsprintf"]=(a0,a1,a2)=>(___small_vsprintf=Module["___small_vsprintf"]=wasmExports["__small_vsprintf"])(a0,a1,a2);var _srand48=Module["_srand48"]=a0=>(_srand48=Module["_srand48"]=wasmExports["srand48"])(a0);var _vsscanf=Module["_vsscanf"]=(a0,a1,a2)=>(_vsscanf=Module["_vsscanf"]=wasmExports["vsscanf"])(a0,a1,a2);var ___isoc99_sscanf=Module["___isoc99_sscanf"]=(a0,a1,a2)=>(___isoc99_sscanf=Module["___isoc99_sscanf"]=wasmExports["__isoc99_sscanf"])(a0,a1,a2);var _statfs=Module["_statfs"]=(a0,a1)=>(_statfs=Module["_statfs"]=wasmExports["statfs"])(a0,a1);var _fstatfs=Module["_fstatfs"]=(a0,a1)=>(_fstatfs=Module["_fstatfs"]=wasmExports["fstatfs"])(a0,a1);var _statx=Module["_statx"]=(a0,a1,a2,a3,a4)=>(_statx=Module["_statx"]=wasmExports["statx"])(a0,a1,a2,a3,a4);var _stpcpy=Module["_stpcpy"]=(a0,a1)=>(_stpcpy=Module["_stpcpy"]=wasmExports["stpcpy"])(a0,a1);var _stpncpy=Module["_stpncpy"]=(a0,a1,a2)=>(_stpncpy=Module["_stpncpy"]=wasmExports["stpncpy"])(a0,a1,a2);var ___strcasecmp_l=Module["___strcasecmp_l"]=(a0,a1,a2)=>(___strcasecmp_l=Module["___strcasecmp_l"]=wasmExports["__strcasecmp_l"])(a0,a1,a2);var _strcasecmp_l=Module["_strcasecmp_l"]=(a0,a1,a2)=>(_strcasecmp_l=Module["_strcasecmp_l"]=wasmExports["strcasecmp_l"])(a0,a1,a2);var _strcasestr=Module["_strcasestr"]=(a0,a1)=>(_strcasestr=Module["_strcasestr"]=wasmExports["strcasestr"])(a0,a1);var _strncasecmp=Module["_strncasecmp"]=(a0,a1,a2)=>(_strncasecmp=Module["_strncasecmp"]=wasmExports["strncasecmp"])(a0,a1,a2);var _strchrnul=Module["_strchrnul"]=(a0,a1)=>(_strchrnul=Module["_strchrnul"]=wasmExports["strchrnul"])(a0,a1);var ___strcoll_l=Module["___strcoll_l"]=(a0,a1,a2)=>(___strcoll_l=Module["___strcoll_l"]=wasmExports["__strcoll_l"])(a0,a1,a2);var _strcoll_l=Module["_strcoll_l"]=(a0,a1,a2)=>(_strcoll_l=Module["_strcoll_l"]=wasmExports["strcoll_l"])(a0,a1,a2);var ___strerror_l=Module["___strerror_l"]=(a0,a1)=>(___strerror_l=Module["___strerror_l"]=wasmExports["__strerror_l"])(a0,a1);var _strerror_l=Module["_strerror_l"]=(a0,a1)=>(_strerror_l=Module["_strerror_l"]=wasmExports["strerror_l"])(a0,a1);var _strerror_r=Module["_strerror_r"]=(a0,a1,a2)=>(_strerror_r=Module["_strerror_r"]=wasmExports["strerror_r"])(a0,a1,a2);var ___xpg_strerror_r=Module["___xpg_strerror_r"]=(a0,a1,a2)=>(___xpg_strerror_r=Module["___xpg_strerror_r"]=wasmExports["__xpg_strerror_r"])(a0,a1,a2);var _strfmon_l=Module["_strfmon_l"]=(a0,a1,a2,a3,a4)=>(_strfmon_l=Module["_strfmon_l"]=wasmExports["strfmon_l"])(a0,a1,a2,a3,a4);var _strfmon=Module["_strfmon"]=(a0,a1,a2,a3)=>(_strfmon=Module["_strfmon"]=wasmExports["strfmon"])(a0,a1,a2,a3);var _strlcat=Module["_strlcat"]=(a0,a1,a2)=>(_strlcat=Module["_strlcat"]=wasmExports["strlcat"])(a0,a1,a2);var _strlcpy=Module["_strlcpy"]=(a0,a1,a2)=>(_strlcpy=Module["_strlcpy"]=wasmExports["strlcpy"])(a0,a1,a2);var _strlwr=Module["_strlwr"]=a0=>(_strlwr=Module["_strlwr"]=wasmExports["strlwr"])(a0);var ___strncasecmp_l=Module["___strncasecmp_l"]=(a0,a1,a2,a3)=>(___strncasecmp_l=Module["___strncasecmp_l"]=wasmExports["__strncasecmp_l"])(a0,a1,a2,a3);var _strncasecmp_l=Module["_strncasecmp_l"]=(a0,a1,a2,a3)=>(_strncasecmp_l=Module["_strncasecmp_l"]=wasmExports["strncasecmp_l"])(a0,a1,a2,a3);var _strndup=Module["_strndup"]=(a0,a1)=>(_strndup=Module["_strndup"]=wasmExports["strndup"])(a0,a1);var _strsep=Module["_strsep"]=(a0,a1)=>(_strsep=Module["_strsep"]=wasmExports["strsep"])(a0,a1);var _strtof=Module["_strtof"]=(a0,a1)=>(_strtof=Module["_strtof"]=wasmExports["strtof"])(a0,a1);var _strtold=Module["_strtold"]=(a0,a1,a2)=>(_strtold=Module["_strtold"]=wasmExports["strtold"])(a0,a1,a2);var _strtof_l=Module["_strtof_l"]=(a0,a1,a2)=>(_strtof_l=Module["_strtof_l"]=wasmExports["strtof_l"])(a0,a1,a2);var _strtod_l=Module["_strtod_l"]=(a0,a1,a2)=>(_strtod_l=Module["_strtod_l"]=wasmExports["strtod_l"])(a0,a1,a2);var _strtold_l=Module["_strtold_l"]=(a0,a1,a2,a3)=>(_strtold_l=Module["_strtold_l"]=wasmExports["strtold_l"])(a0,a1,a2,a3);var ___strtof_l=Module["___strtof_l"]=(a0,a1,a2)=>(___strtof_l=Module["___strtof_l"]=wasmExports["__strtof_l"])(a0,a1,a2);var ___strtod_l=Module["___strtod_l"]=(a0,a1,a2)=>(___strtod_l=Module["___strtod_l"]=wasmExports["__strtod_l"])(a0,a1,a2);var ___strtold_l=Module["___strtold_l"]=(a0,a1,a2,a3)=>(___strtold_l=Module["___strtold_l"]=wasmExports["__strtold_l"])(a0,a1,a2,a3);var _strtok=Module["_strtok"]=(a0,a1)=>(_strtok=Module["_strtok"]=wasmExports["strtok"])(a0,a1);var _strtok_r=Module["_strtok_r"]=(a0,a1,a2)=>(_strtok_r=Module["_strtok_r"]=wasmExports["strtok_r"])(a0,a1,a2);var _strtoll=Module["_strtoll"]=(a0,a1,a2)=>(_strtoll=Module["_strtoll"]=wasmExports["strtoll"])(a0,a1,a2);var _strtoimax=Module["_strtoimax"]=(a0,a1,a2)=>(_strtoimax=Module["_strtoimax"]=wasmExports["strtoimax"])(a0,a1,a2);var _strtoumax=Module["_strtoumax"]=(a0,a1,a2)=>(_strtoumax=Module["_strtoumax"]=wasmExports["strtoumax"])(a0,a1,a2);var ___strtol_internal=Module["___strtol_internal"]=(a0,a1,a2)=>(___strtol_internal=Module["___strtol_internal"]=wasmExports["__strtol_internal"])(a0,a1,a2);var ___strtoul_internal=Module["___strtoul_internal"]=(a0,a1,a2)=>(___strtoul_internal=Module["___strtoul_internal"]=wasmExports["__strtoul_internal"])(a0,a1,a2);var ___strtoll_internal=Module["___strtoll_internal"]=(a0,a1,a2)=>(___strtoll_internal=Module["___strtoll_internal"]=wasmExports["__strtoll_internal"])(a0,a1,a2);var ___strtoull_internal=Module["___strtoull_internal"]=(a0,a1,a2)=>(___strtoull_internal=Module["___strtoull_internal"]=wasmExports["__strtoull_internal"])(a0,a1,a2);var ___strtoimax_internal=Module["___strtoimax_internal"]=(a0,a1,a2)=>(___strtoimax_internal=Module["___strtoimax_internal"]=wasmExports["__strtoimax_internal"])(a0,a1,a2);var ___strtoumax_internal=Module["___strtoumax_internal"]=(a0,a1,a2)=>(___strtoumax_internal=Module["___strtoumax_internal"]=wasmExports["__strtoumax_internal"])(a0,a1,a2);var _strtoull_l=Module["_strtoull_l"]=(a0,a1,a2,a3)=>(_strtoull_l=Module["_strtoull_l"]=wasmExports["strtoull_l"])(a0,a1,a2,a3);var _strtoll_l=Module["_strtoll_l"]=(a0,a1,a2,a3)=>(_strtoll_l=Module["_strtoll_l"]=wasmExports["strtoll_l"])(a0,a1,a2,a3);var _strtoul_l=Module["_strtoul_l"]=(a0,a1,a2,a3)=>(_strtoul_l=Module["_strtoul_l"]=wasmExports["strtoul_l"])(a0,a1,a2,a3);var _strtol_l=Module["_strtol_l"]=(a0,a1,a2,a3)=>(_strtol_l=Module["_strtol_l"]=wasmExports["strtol_l"])(a0,a1,a2,a3);var _strupr=Module["_strupr"]=a0=>(_strupr=Module["_strupr"]=wasmExports["strupr"])(a0);var _strverscmp=Module["_strverscmp"]=(a0,a1)=>(_strverscmp=Module["_strverscmp"]=wasmExports["strverscmp"])(a0,a1);var ___strxfrm_l=Module["___strxfrm_l"]=(a0,a1,a2,a3)=>(___strxfrm_l=Module["___strxfrm_l"]=wasmExports["__strxfrm_l"])(a0,a1,a2,a3);var _strxfrm=Module["_strxfrm"]=(a0,a1,a2)=>(_strxfrm=Module["_strxfrm"]=wasmExports["strxfrm"])(a0,a1,a2);var _strxfrm_l=Module["_strxfrm_l"]=(a0,a1,a2,a3)=>(_strxfrm_l=Module["_strxfrm_l"]=wasmExports["strxfrm_l"])(a0,a1,a2,a3);var _swab=Module["_swab"]=(a0,a1,a2)=>(_swab=Module["_swab"]=wasmExports["swab"])(a0,a1,a2);var _swprintf=Module["_swprintf"]=(a0,a1,a2,a3)=>(_swprintf=Module["_swprintf"]=wasmExports["swprintf"])(a0,a1,a2,a3);var _vswprintf=Module["_vswprintf"]=(a0,a1,a2,a3)=>(_vswprintf=Module["_vswprintf"]=wasmExports["vswprintf"])(a0,a1,a2,a3);var _swscanf=Module["_swscanf"]=(a0,a1,a2)=>(_swscanf=Module["_swscanf"]=wasmExports["swscanf"])(a0,a1,a2);var _vswscanf=Module["_vswscanf"]=(a0,a1,a2)=>(_vswscanf=Module["_vswscanf"]=wasmExports["vswscanf"])(a0,a1,a2);var ___isoc99_swscanf=Module["___isoc99_swscanf"]=(a0,a1,a2)=>(___isoc99_swscanf=Module["___isoc99_swscanf"]=wasmExports["__isoc99_swscanf"])(a0,a1,a2);var _symlinkat=Module["_symlinkat"]=(a0,a1,a2)=>(_symlinkat=Module["_symlinkat"]=wasmExports["symlinkat"])(a0,a1,a2);var _setlogmask=Module["_setlogmask"]=a0=>(_setlogmask=Module["_setlogmask"]=wasmExports["setlogmask"])(a0);var _closelog=Module["_closelog"]=()=>(_closelog=Module["_closelog"]=wasmExports["closelog"])();var _openlog=Module["_openlog"]=(a0,a1,a2)=>(_openlog=Module["_openlog"]=wasmExports["openlog"])(a0,a1,a2);var _syslog=Module["_syslog"]=(a0,a1,a2)=>(_syslog=Module["_syslog"]=wasmExports["syslog"])(a0,a1,a2);var _vsyslog=Module["_vsyslog"]=(a0,a1,a2)=>(_vsyslog=Module["_vsyslog"]=wasmExports["vsyslog"])(a0,a1,a2);var _tanhf=Module["_tanhf"]=a0=>(_tanhf=Module["_tanhf"]=wasmExports["tanhf"])(a0);var _tanhl=Module["_tanhl"]=(a0,a1,a2)=>(_tanhl=Module["_tanhl"]=wasmExports["tanhl"])(a0,a1,a2);var _tanl=Module["_tanl"]=(a0,a1,a2)=>(_tanl=Module["_tanl"]=wasmExports["tanl"])(a0,a1,a2);var _tcdrain=Module["_tcdrain"]=a0=>(_tcdrain=Module["_tcdrain"]=wasmExports["tcdrain"])(a0);var _tcflow=Module["_tcflow"]=(a0,a1)=>(_tcflow=Module["_tcflow"]=wasmExports["tcflow"])(a0,a1);var _tcflush=Module["_tcflush"]=(a0,a1)=>(_tcflush=Module["_tcflush"]=wasmExports["tcflush"])(a0,a1);var _tcgetattr=Module["_tcgetattr"]=(a0,a1)=>(_tcgetattr=Module["_tcgetattr"]=wasmExports["tcgetattr"])(a0,a1);var _tcgetsid=Module["_tcgetsid"]=a0=>(_tcgetsid=Module["_tcgetsid"]=wasmExports["tcgetsid"])(a0);var _tcgetwinsize=Module["_tcgetwinsize"]=(a0,a1)=>(_tcgetwinsize=Module["_tcgetwinsize"]=wasmExports["tcgetwinsize"])(a0,a1);var _tcsendbreak=Module["_tcsendbreak"]=(a0,a1)=>(_tcsendbreak=Module["_tcsendbreak"]=wasmExports["tcsendbreak"])(a0,a1);var _tcsetwinsize=Module["_tcsetwinsize"]=(a0,a1)=>(_tcsetwinsize=Module["_tcsetwinsize"]=wasmExports["tcsetwinsize"])(a0,a1);var _tdelete=Module["_tdelete"]=(a0,a1,a2)=>(_tdelete=Module["_tdelete"]=wasmExports["tdelete"])(a0,a1,a2);var _tdestroy=Module["_tdestroy"]=(a0,a1)=>(_tdestroy=Module["_tdestroy"]=wasmExports["tdestroy"])(a0,a1);var _telldir=Module["_telldir"]=a0=>(_telldir=Module["_telldir"]=wasmExports["telldir"])(a0);var _tempnam=Module["_tempnam"]=(a0,a1)=>(_tempnam=Module["_tempnam"]=wasmExports["tempnam"])(a0,a1);var _ngettext=Module["_ngettext"]=(a0,a1,a2)=>(_ngettext=Module["_ngettext"]=wasmExports["ngettext"])(a0,a1,a2);var _tfind=Module["_tfind"]=(a0,a1,a2)=>(_tfind=Module["_tfind"]=wasmExports["tfind"])(a0,a1,a2);var _tgamma=Module["_tgamma"]=a0=>(_tgamma=Module["_tgamma"]=wasmExports["tgamma"])(a0);var _tgammaf=Module["_tgammaf"]=a0=>(_tgammaf=Module["_tgammaf"]=wasmExports["tgammaf"])(a0);var _tgammal=Module["_tgammal"]=(a0,a1,a2)=>(_tgammal=Module["_tgammal"]=wasmExports["tgammal"])(a0,a1,a2);var _thrd_create=Module["_thrd_create"]=(a0,a1,a2)=>(_thrd_create=Module["_thrd_create"]=wasmExports["thrd_create"])(a0,a1,a2);var _thrd_exit=Module["_thrd_exit"]=a0=>(_thrd_exit=Module["_thrd_exit"]=wasmExports["thrd_exit"])(a0);var _thrd_join=Module["_thrd_join"]=(a0,a1)=>(_thrd_join=Module["_thrd_join"]=wasmExports["thrd_join"])(a0,a1);var _thrd_sleep=Module["_thrd_sleep"]=(a0,a1)=>(_thrd_sleep=Module["_thrd_sleep"]=wasmExports["thrd_sleep"])(a0,a1);var _thrd_yield=Module["_thrd_yield"]=()=>(_thrd_yield=Module["_thrd_yield"]=wasmExports["thrd_yield"])();var _emscripten_set_thread_name=Module["_emscripten_set_thread_name"]=(a0,a1)=>(_emscripten_set_thread_name=Module["_emscripten_set_thread_name"]=wasmExports["emscripten_set_thread_name"])(a0,a1);var _timespec_get=Module["_timespec_get"]=(a0,a1)=>(_timespec_get=Module["_timespec_get"]=wasmExports["timespec_get"])(a0,a1);var _tmpfile=Module["_tmpfile"]=()=>(_tmpfile=Module["_tmpfile"]=wasmExports["tmpfile"])();var _tmpnam=Module["_tmpnam"]=a0=>(_tmpnam=Module["_tmpnam"]=wasmExports["tmpnam"])(a0);var _toascii=Module["_toascii"]=a0=>(_toascii=Module["_toascii"]=wasmExports["toascii"])(a0);var ___tolower_l=Module["___tolower_l"]=(a0,a1)=>(___tolower_l=Module["___tolower_l"]=wasmExports["__tolower_l"])(a0,a1);var _tolower_l=Module["_tolower_l"]=(a0,a1)=>(_tolower_l=Module["_tolower_l"]=wasmExports["tolower_l"])(a0,a1);var ___toupper_l=Module["___toupper_l"]=(a0,a1)=>(___toupper_l=Module["___toupper_l"]=wasmExports["__toupper_l"])(a0,a1);var _toupper_l=Module["_toupper_l"]=(a0,a1)=>(_toupper_l=Module["_toupper_l"]=wasmExports["toupper_l"])(a0,a1);var ___towupper_l=Module["___towupper_l"]=(a0,a1)=>(___towupper_l=Module["___towupper_l"]=wasmExports["__towupper_l"])(a0,a1);var ___towlower_l=Module["___towlower_l"]=(a0,a1)=>(___towlower_l=Module["___towlower_l"]=wasmExports["__towlower_l"])(a0,a1);var _towupper_l=Module["_towupper_l"]=(a0,a1)=>(_towupper_l=Module["_towupper_l"]=wasmExports["towupper_l"])(a0,a1);var _towlower_l=Module["_towlower_l"]=(a0,a1)=>(_towlower_l=Module["_towlower_l"]=wasmExports["towlower_l"])(a0,a1);var _trunc=Module["_trunc"]=a0=>(_trunc=Module["_trunc"]=wasmExports["trunc"])(a0);var _truncf=Module["_truncf"]=a0=>(_truncf=Module["_truncf"]=wasmExports["truncf"])(a0);var _truncl=Module["_truncl"]=(a0,a1,a2)=>(_truncl=Module["_truncl"]=wasmExports["truncl"])(a0,a1,a2);var _tsearch=Module["_tsearch"]=(a0,a1,a2)=>(_tsearch=Module["_tsearch"]=wasmExports["tsearch"])(a0,a1,a2);var _tss_create=Module["_tss_create"]=(a0,a1)=>(_tss_create=Module["_tss_create"]=wasmExports["tss_create"])(a0,a1);var _tss_delete=Module["_tss_delete"]=a0=>(_tss_delete=Module["_tss_delete"]=wasmExports["tss_delete"])(a0);var _tss_set=Module["_tss_set"]=(a0,a1)=>(_tss_set=Module["_tss_set"]=wasmExports["tss_set"])(a0,a1);var _ttyname=Module["_ttyname"]=a0=>(_ttyname=Module["_ttyname"]=wasmExports["ttyname"])(a0);var _twalk=Module["_twalk"]=(a0,a1)=>(_twalk=Module["_twalk"]=wasmExports["twalk"])(a0,a1);var _ualarm=Module["_ualarm"]=(a0,a1)=>(_ualarm=Module["_ualarm"]=wasmExports["ualarm"])(a0,a1);var _ungetwc=Module["_ungetwc"]=(a0,a1)=>(_ungetwc=Module["_ungetwc"]=wasmExports["ungetwc"])(a0,a1);var ___uselocale=Module["___uselocale"]=a0=>(___uselocale=Module["___uselocale"]=wasmExports["__uselocale"])(a0);var _uselocale=Module["_uselocale"]=a0=>(_uselocale=Module["_uselocale"]=wasmExports["uselocale"])(a0);var _usleep=Module["_usleep"]=a0=>(_usleep=Module["_usleep"]=wasmExports["usleep"])(a0);var _utime=Module["_utime"]=(a0,a1)=>(_utime=Module["_utime"]=wasmExports["utime"])(a0,a1);var _versionsort=Module["_versionsort"]=(a0,a1)=>(_versionsort=Module["_versionsort"]=wasmExports["versionsort"])(a0,a1);var ___vfprintf_internal=Module["___vfprintf_internal"]=(a0,a1,a2,a3,a4)=>(___vfprintf_internal=Module["___vfprintf_internal"]=wasmExports["__vfprintf_internal"])(a0,a1,a2,a3,a4);var ___isoc99_vfscanf=Module["___isoc99_vfscanf"]=(a0,a1,a2)=>(___isoc99_vfscanf=Module["___isoc99_vfscanf"]=wasmExports["__isoc99_vfscanf"])(a0,a1,a2);var _wcsnlen=Module["_wcsnlen"]=(a0,a1)=>(_wcsnlen=Module["_wcsnlen"]=wasmExports["wcsnlen"])(a0,a1);var ___isoc99_vfwscanf=Module["___isoc99_vfwscanf"]=(a0,a1,a2)=>(___isoc99_vfwscanf=Module["___isoc99_vfwscanf"]=wasmExports["__isoc99_vfwscanf"])(a0,a1,a2);var _vprintf=Module["_vprintf"]=(a0,a1)=>(_vprintf=Module["_vprintf"]=wasmExports["vprintf"])(a0,a1);var ___isoc99_vscanf=Module["___isoc99_vscanf"]=(a0,a1)=>(___isoc99_vscanf=Module["___isoc99_vscanf"]=wasmExports["__isoc99_vscanf"])(a0,a1);var _vsniprintf=Module["_vsniprintf"]=(a0,a1,a2,a3)=>(_vsniprintf=Module["_vsniprintf"]=wasmExports["vsniprintf"])(a0,a1,a2,a3);var ___small_vsnprintf=Module["___small_vsnprintf"]=(a0,a1,a2,a3)=>(___small_vsnprintf=Module["___small_vsnprintf"]=wasmExports["__small_vsnprintf"])(a0,a1,a2,a3);var ___isoc99_vsscanf=Module["___isoc99_vsscanf"]=(a0,a1,a2)=>(___isoc99_vsscanf=Module["___isoc99_vsscanf"]=wasmExports["__isoc99_vsscanf"])(a0,a1,a2);var ___isoc99_vswscanf=Module["___isoc99_vswscanf"]=(a0,a1,a2)=>(___isoc99_vswscanf=Module["___isoc99_vswscanf"]=wasmExports["__isoc99_vswscanf"])(a0,a1,a2);var _vwprintf=Module["_vwprintf"]=(a0,a1)=>(_vwprintf=Module["_vwprintf"]=wasmExports["vwprintf"])(a0,a1);var _vwscanf=Module["_vwscanf"]=(a0,a1)=>(_vwscanf=Module["_vwscanf"]=wasmExports["vwscanf"])(a0,a1);var ___isoc99_vwscanf=Module["___isoc99_vwscanf"]=(a0,a1)=>(___isoc99_vwscanf=Module["___isoc99_vwscanf"]=wasmExports["__isoc99_vwscanf"])(a0,a1);var _wcpcpy=Module["_wcpcpy"]=(a0,a1)=>(_wcpcpy=Module["_wcpcpy"]=wasmExports["wcpcpy"])(a0,a1);var _wcpncpy=Module["_wcpncpy"]=(a0,a1,a2)=>(_wcpncpy=Module["_wcpncpy"]=wasmExports["wcpncpy"])(a0,a1,a2);var _wcscasecmp=Module["_wcscasecmp"]=(a0,a1)=>(_wcscasecmp=Module["_wcscasecmp"]=wasmExports["wcscasecmp"])(a0,a1);var _wcsncasecmp=Module["_wcsncasecmp"]=(a0,a1,a2)=>(_wcsncasecmp=Module["_wcsncasecmp"]=wasmExports["wcsncasecmp"])(a0,a1,a2);var _wcscasecmp_l=Module["_wcscasecmp_l"]=(a0,a1,a2)=>(_wcscasecmp_l=Module["_wcscasecmp_l"]=wasmExports["wcscasecmp_l"])(a0,a1,a2);var _wcscat=Module["_wcscat"]=(a0,a1)=>(_wcscat=Module["_wcscat"]=wasmExports["wcscat"])(a0,a1);var ___wcscoll_l=Module["___wcscoll_l"]=(a0,a1,a2)=>(___wcscoll_l=Module["___wcscoll_l"]=wasmExports["__wcscoll_l"])(a0,a1,a2);var _wcscoll_l=Module["_wcscoll_l"]=(a0,a1,a2)=>(_wcscoll_l=Module["_wcscoll_l"]=wasmExports["wcscoll_l"])(a0,a1,a2);var _wcscspn=Module["_wcscspn"]=(a0,a1)=>(_wcscspn=Module["_wcscspn"]=wasmExports["wcscspn"])(a0,a1);var _wcsdup=Module["_wcsdup"]=a0=>(_wcsdup=Module["_wcsdup"]=wasmExports["wcsdup"])(a0);var _wmemcpy=Module["_wmemcpy"]=(a0,a1,a2)=>(_wmemcpy=Module["_wmemcpy"]=wasmExports["wmemcpy"])(a0,a1,a2);var _wcsncasecmp_l=Module["_wcsncasecmp_l"]=(a0,a1,a2,a3)=>(_wcsncasecmp_l=Module["_wcsncasecmp_l"]=wasmExports["wcsncasecmp_l"])(a0,a1,a2,a3);var _wcsncat=Module["_wcsncat"]=(a0,a1,a2)=>(_wcsncat=Module["_wcsncat"]=wasmExports["wcsncat"])(a0,a1,a2);var _wmemset=Module["_wmemset"]=(a0,a1,a2)=>(_wmemset=Module["_wmemset"]=wasmExports["wmemset"])(a0,a1,a2);var _wcsnrtombs=Module["_wcsnrtombs"]=(a0,a1,a2,a3,a4)=>(_wcsnrtombs=Module["_wcsnrtombs"]=wasmExports["wcsnrtombs"])(a0,a1,a2,a3,a4);var _wcspbrk=Module["_wcspbrk"]=(a0,a1)=>(_wcspbrk=Module["_wcspbrk"]=wasmExports["wcspbrk"])(a0,a1);var _wcsspn=Module["_wcsspn"]=(a0,a1)=>(_wcsspn=Module["_wcsspn"]=wasmExports["wcsspn"])(a0,a1);var _wcsstr=Module["_wcsstr"]=(a0,a1)=>(_wcsstr=Module["_wcsstr"]=wasmExports["wcsstr"])(a0,a1);var _wcstof=Module["_wcstof"]=(a0,a1)=>(_wcstof=Module["_wcstof"]=wasmExports["wcstof"])(a0,a1);var _wcstod=Module["_wcstod"]=(a0,a1)=>(_wcstod=Module["_wcstod"]=wasmExports["wcstod"])(a0,a1);var _wcstold=Module["_wcstold"]=(a0,a1,a2)=>(_wcstold=Module["_wcstold"]=wasmExports["wcstold"])(a0,a1,a2);var _wcstoull=Module["_wcstoull"]=(a0,a1,a2)=>(_wcstoull=Module["_wcstoull"]=wasmExports["wcstoull"])(a0,a1,a2);var _wcstoll=Module["_wcstoll"]=(a0,a1,a2)=>(_wcstoll=Module["_wcstoll"]=wasmExports["wcstoll"])(a0,a1,a2);var _wcstoul=Module["_wcstoul"]=(a0,a1,a2)=>(_wcstoul=Module["_wcstoul"]=wasmExports["wcstoul"])(a0,a1,a2);var _wcstoimax=Module["_wcstoimax"]=(a0,a1,a2)=>(_wcstoimax=Module["_wcstoimax"]=wasmExports["wcstoimax"])(a0,a1,a2);var _wcstoumax=Module["_wcstoumax"]=(a0,a1,a2)=>(_wcstoumax=Module["_wcstoumax"]=wasmExports["wcstoumax"])(a0,a1,a2);var _wcswcs=Module["_wcswcs"]=(a0,a1)=>(_wcswcs=Module["_wcswcs"]=wasmExports["wcswcs"])(a0,a1);var _wcswidth=Module["_wcswidth"]=(a0,a1)=>(_wcswidth=Module["_wcswidth"]=wasmExports["wcswidth"])(a0,a1);var _wcwidth=Module["_wcwidth"]=a0=>(_wcwidth=Module["_wcwidth"]=wasmExports["wcwidth"])(a0);var ___wcsxfrm_l=Module["___wcsxfrm_l"]=(a0,a1,a2,a3)=>(___wcsxfrm_l=Module["___wcsxfrm_l"]=wasmExports["__wcsxfrm_l"])(a0,a1,a2,a3);var _wcsxfrm_l=Module["_wcsxfrm_l"]=(a0,a1,a2,a3)=>(_wcsxfrm_l=Module["_wcsxfrm_l"]=wasmExports["wcsxfrm_l"])(a0,a1,a2,a3);var _wctob=Module["_wctob"]=a0=>(_wctob=Module["_wctob"]=wasmExports["wctob"])(a0);var _wctrans=Module["_wctrans"]=a0=>(_wctrans=Module["_wctrans"]=wasmExports["wctrans"])(a0);var _towctrans=Module["_towctrans"]=(a0,a1)=>(_towctrans=Module["_towctrans"]=wasmExports["towctrans"])(a0,a1);var ___wctrans_l=Module["___wctrans_l"]=(a0,a1)=>(___wctrans_l=Module["___wctrans_l"]=wasmExports["__wctrans_l"])(a0,a1);var ___towctrans_l=Module["___towctrans_l"]=(a0,a1,a2)=>(___towctrans_l=Module["___towctrans_l"]=wasmExports["__towctrans_l"])(a0,a1,a2);var _wctrans_l=Module["_wctrans_l"]=(a0,a1)=>(_wctrans_l=Module["_wctrans_l"]=wasmExports["wctrans_l"])(a0,a1);var _towctrans_l=Module["_towctrans_l"]=(a0,a1,a2)=>(_towctrans_l=Module["_towctrans_l"]=wasmExports["towctrans_l"])(a0,a1,a2);var _wmemmove=Module["_wmemmove"]=(a0,a1,a2)=>(_wmemmove=Module["_wmemmove"]=wasmExports["wmemmove"])(a0,a1,a2);var _wprintf=Module["_wprintf"]=(a0,a1)=>(_wprintf=Module["_wprintf"]=wasmExports["wprintf"])(a0,a1);var _wscanf=Module["_wscanf"]=(a0,a1)=>(_wscanf=Module["_wscanf"]=wasmExports["wscanf"])(a0,a1);var ___isoc99_wscanf=Module["___isoc99_wscanf"]=(a0,a1)=>(___isoc99_wscanf=Module["___isoc99_wscanf"]=wasmExports["__isoc99_wscanf"])(a0,a1);var ___libc_realloc=Module["___libc_realloc"]=(a0,a1)=>(___libc_realloc=Module["___libc_realloc"]=wasmExports["__libc_realloc"])(a0,a1);var _realloc_in_place=Module["_realloc_in_place"]=(a0,a1)=>(_realloc_in_place=Module["_realloc_in_place"]=wasmExports["realloc_in_place"])(a0,a1);var _memalign=Module["_memalign"]=(a0,a1)=>(_memalign=Module["_memalign"]=wasmExports["memalign"])(a0,a1);var _valloc=Module["_valloc"]=a0=>(_valloc=Module["_valloc"]=wasmExports["valloc"])(a0);var _pvalloc=Module["_pvalloc"]=a0=>(_pvalloc=Module["_pvalloc"]=wasmExports["pvalloc"])(a0);var _mallinfo=Module["_mallinfo"]=a0=>(_mallinfo=Module["_mallinfo"]=wasmExports["mallinfo"])(a0);var _mallopt=Module["_mallopt"]=(a0,a1)=>(_mallopt=Module["_mallopt"]=wasmExports["mallopt"])(a0,a1);var _malloc_trim=Module["_malloc_trim"]=a0=>(_malloc_trim=Module["_malloc_trim"]=wasmExports["malloc_trim"])(a0);var _malloc_usable_size=Module["_malloc_usable_size"]=a0=>(_malloc_usable_size=Module["_malloc_usable_size"]=wasmExports["malloc_usable_size"])(a0);var _malloc_footprint=Module["_malloc_footprint"]=()=>(_malloc_footprint=Module["_malloc_footprint"]=wasmExports["malloc_footprint"])();var _malloc_max_footprint=Module["_malloc_max_footprint"]=()=>(_malloc_max_footprint=Module["_malloc_max_footprint"]=wasmExports["malloc_max_footprint"])();var _malloc_footprint_limit=Module["_malloc_footprint_limit"]=()=>(_malloc_footprint_limit=Module["_malloc_footprint_limit"]=wasmExports["malloc_footprint_limit"])();var _malloc_set_footprint_limit=Module["_malloc_set_footprint_limit"]=a0=>(_malloc_set_footprint_limit=Module["_malloc_set_footprint_limit"]=wasmExports["malloc_set_footprint_limit"])(a0);var _independent_calloc=Module["_independent_calloc"]=(a0,a1,a2)=>(_independent_calloc=Module["_independent_calloc"]=wasmExports["independent_calloc"])(a0,a1,a2);var _independent_comalloc=Module["_independent_comalloc"]=(a0,a1,a2)=>(_independent_comalloc=Module["_independent_comalloc"]=wasmExports["independent_comalloc"])(a0,a1,a2);var _bulk_free=Module["_bulk_free"]=(a0,a1)=>(_bulk_free=Module["_bulk_free"]=wasmExports["bulk_free"])(a0,a1);var ___trap=Module["___trap"]=()=>(___trap=Module["___trap"]=wasmExports["__trap"])();var ___absvdi2=Module["___absvdi2"]=a0=>(___absvdi2=Module["___absvdi2"]=wasmExports["__absvdi2"])(a0);var ___absvsi2=Module["___absvsi2"]=a0=>(___absvsi2=Module["___absvsi2"]=wasmExports["__absvsi2"])(a0);var ___absvti2=Module["___absvti2"]=(a0,a1,a2)=>(___absvti2=Module["___absvti2"]=wasmExports["__absvti2"])(a0,a1,a2);var ___adddf3=Module["___adddf3"]=(a0,a1)=>(___adddf3=Module["___adddf3"]=wasmExports["__adddf3"])(a0,a1);var ___fe_getround=Module["___fe_getround"]=()=>(___fe_getround=Module["___fe_getround"]=wasmExports["__fe_getround"])();var ___fe_raise_inexact=Module["___fe_raise_inexact"]=()=>(___fe_raise_inexact=Module["___fe_raise_inexact"]=wasmExports["__fe_raise_inexact"])();var ___addsf3=Module["___addsf3"]=(a0,a1)=>(___addsf3=Module["___addsf3"]=wasmExports["__addsf3"])(a0,a1);var ___ashlti3=Module["___ashlti3"]=(a0,a1,a2,a3)=>(___ashlti3=Module["___ashlti3"]=wasmExports["__ashlti3"])(a0,a1,a2,a3);var ___lshrti3=Module["___lshrti3"]=(a0,a1,a2,a3)=>(___lshrti3=Module["___lshrti3"]=wasmExports["__lshrti3"])(a0,a1,a2,a3);var ___addvdi3=Module["___addvdi3"]=(a0,a1)=>(___addvdi3=Module["___addvdi3"]=wasmExports["__addvdi3"])(a0,a1);var ___addvsi3=Module["___addvsi3"]=(a0,a1)=>(___addvsi3=Module["___addvsi3"]=wasmExports["__addvsi3"])(a0,a1);var ___addvti3=Module["___addvti3"]=(a0,a1,a2,a3,a4)=>(___addvti3=Module["___addvti3"]=wasmExports["__addvti3"])(a0,a1,a2,a3,a4);var ___ashldi3=Module["___ashldi3"]=(a0,a1)=>(___ashldi3=Module["___ashldi3"]=wasmExports["__ashldi3"])(a0,a1);var ___ashrdi3=Module["___ashrdi3"]=(a0,a1)=>(___ashrdi3=Module["___ashrdi3"]=wasmExports["__ashrdi3"])(a0,a1);var ___ashrti3=Module["___ashrti3"]=(a0,a1,a2,a3)=>(___ashrti3=Module["___ashrti3"]=wasmExports["__ashrti3"])(a0,a1,a2,a3);var ___atomic_is_lock_free=Module["___atomic_is_lock_free"]=(a0,a1)=>(___atomic_is_lock_free=Module["___atomic_is_lock_free"]=wasmExports["__atomic_is_lock_free"])(a0,a1);var ___atomic_load=Module["___atomic_load"]=(a0,a1,a2,a3)=>(___atomic_load=Module["___atomic_load"]=wasmExports["__atomic_load"])(a0,a1,a2,a3);var ___atomic_store=Module["___atomic_store"]=(a0,a1,a2,a3)=>(___atomic_store=Module["___atomic_store"]=wasmExports["__atomic_store"])(a0,a1,a2,a3);var ___atomic_compare_exchange=Module["___atomic_compare_exchange"]=(a0,a1,a2,a3,a4,a5)=>(___atomic_compare_exchange=Module["___atomic_compare_exchange"]=wasmExports["__atomic_compare_exchange"])(a0,a1,a2,a3,a4,a5);var ___atomic_exchange=Module["___atomic_exchange"]=(a0,a1,a2,a3,a4)=>(___atomic_exchange=Module["___atomic_exchange"]=wasmExports["__atomic_exchange"])(a0,a1,a2,a3,a4);var ___atomic_load_1=Module["___atomic_load_1"]=(a0,a1)=>(___atomic_load_1=Module["___atomic_load_1"]=wasmExports["__atomic_load_1"])(a0,a1);var ___atomic_load_2=Module["___atomic_load_2"]=(a0,a1)=>(___atomic_load_2=Module["___atomic_load_2"]=wasmExports["__atomic_load_2"])(a0,a1);var ___atomic_load_4=Module["___atomic_load_4"]=(a0,a1)=>(___atomic_load_4=Module["___atomic_load_4"]=wasmExports["__atomic_load_4"])(a0,a1);var ___atomic_load_8=Module["___atomic_load_8"]=(a0,a1)=>(___atomic_load_8=Module["___atomic_load_8"]=wasmExports["__atomic_load_8"])(a0,a1);var ___atomic_load_16=Module["___atomic_load_16"]=(a0,a1,a2)=>(___atomic_load_16=Module["___atomic_load_16"]=wasmExports["__atomic_load_16"])(a0,a1,a2);var ___atomic_store_1=Module["___atomic_store_1"]=(a0,a1,a2)=>(___atomic_store_1=Module["___atomic_store_1"]=wasmExports["__atomic_store_1"])(a0,a1,a2);var ___atomic_store_2=Module["___atomic_store_2"]=(a0,a1,a2)=>(___atomic_store_2=Module["___atomic_store_2"]=wasmExports["__atomic_store_2"])(a0,a1,a2);var ___atomic_store_4=Module["___atomic_store_4"]=(a0,a1,a2)=>(___atomic_store_4=Module["___atomic_store_4"]=wasmExports["__atomic_store_4"])(a0,a1,a2);var ___atomic_store_8=Module["___atomic_store_8"]=(a0,a1,a2)=>(___atomic_store_8=Module["___atomic_store_8"]=wasmExports["__atomic_store_8"])(a0,a1,a2);var ___atomic_store_16=Module["___atomic_store_16"]=(a0,a1,a2,a3)=>(___atomic_store_16=Module["___atomic_store_16"]=wasmExports["__atomic_store_16"])(a0,a1,a2,a3);var ___atomic_exchange_1=Module["___atomic_exchange_1"]=(a0,a1,a2)=>(___atomic_exchange_1=Module["___atomic_exchange_1"]=wasmExports["__atomic_exchange_1"])(a0,a1,a2);var ___atomic_exchange_2=Module["___atomic_exchange_2"]=(a0,a1,a2)=>(___atomic_exchange_2=Module["___atomic_exchange_2"]=wasmExports["__atomic_exchange_2"])(a0,a1,a2);var ___atomic_exchange_4=Module["___atomic_exchange_4"]=(a0,a1,a2)=>(___atomic_exchange_4=Module["___atomic_exchange_4"]=wasmExports["__atomic_exchange_4"])(a0,a1,a2);var ___atomic_exchange_8=Module["___atomic_exchange_8"]=(a0,a1,a2)=>(___atomic_exchange_8=Module["___atomic_exchange_8"]=wasmExports["__atomic_exchange_8"])(a0,a1,a2);var ___atomic_exchange_16=Module["___atomic_exchange_16"]=(a0,a1,a2,a3,a4)=>(___atomic_exchange_16=Module["___atomic_exchange_16"]=wasmExports["__atomic_exchange_16"])(a0,a1,a2,a3,a4);var ___atomic_compare_exchange_1=Module["___atomic_compare_exchange_1"]=(a0,a1,a2,a3,a4)=>(___atomic_compare_exchange_1=Module["___atomic_compare_exchange_1"]=wasmExports["__atomic_compare_exchange_1"])(a0,a1,a2,a3,a4);var ___atomic_compare_exchange_2=Module["___atomic_compare_exchange_2"]=(a0,a1,a2,a3,a4)=>(___atomic_compare_exchange_2=Module["___atomic_compare_exchange_2"]=wasmExports["__atomic_compare_exchange_2"])(a0,a1,a2,a3,a4);var ___atomic_compare_exchange_4=Module["___atomic_compare_exchange_4"]=(a0,a1,a2,a3,a4)=>(___atomic_compare_exchange_4=Module["___atomic_compare_exchange_4"]=wasmExports["__atomic_compare_exchange_4"])(a0,a1,a2,a3,a4);var ___atomic_compare_exchange_8=Module["___atomic_compare_exchange_8"]=(a0,a1,a2,a3,a4)=>(___atomic_compare_exchange_8=Module["___atomic_compare_exchange_8"]=wasmExports["__atomic_compare_exchange_8"])(a0,a1,a2,a3,a4);var ___atomic_compare_exchange_16=Module["___atomic_compare_exchange_16"]=(a0,a1,a2,a3,a4,a5)=>(___atomic_compare_exchange_16=Module["___atomic_compare_exchange_16"]=wasmExports["__atomic_compare_exchange_16"])(a0,a1,a2,a3,a4,a5);var ___atomic_fetch_add_1=Module["___atomic_fetch_add_1"]=(a0,a1,a2)=>(___atomic_fetch_add_1=Module["___atomic_fetch_add_1"]=wasmExports["__atomic_fetch_add_1"])(a0,a1,a2);var ___atomic_fetch_add_2=Module["___atomic_fetch_add_2"]=(a0,a1,a2)=>(___atomic_fetch_add_2=Module["___atomic_fetch_add_2"]=wasmExports["__atomic_fetch_add_2"])(a0,a1,a2);var ___atomic_fetch_add_4=Module["___atomic_fetch_add_4"]=(a0,a1,a2)=>(___atomic_fetch_add_4=Module["___atomic_fetch_add_4"]=wasmExports["__atomic_fetch_add_4"])(a0,a1,a2);var ___atomic_fetch_add_8=Module["___atomic_fetch_add_8"]=(a0,a1,a2)=>(___atomic_fetch_add_8=Module["___atomic_fetch_add_8"]=wasmExports["__atomic_fetch_add_8"])(a0,a1,a2);var ___atomic_fetch_add_16=Module["___atomic_fetch_add_16"]=(a0,a1,a2,a3,a4)=>(___atomic_fetch_add_16=Module["___atomic_fetch_add_16"]=wasmExports["__atomic_fetch_add_16"])(a0,a1,a2,a3,a4);var ___atomic_fetch_sub_1=Module["___atomic_fetch_sub_1"]=(a0,a1,a2)=>(___atomic_fetch_sub_1=Module["___atomic_fetch_sub_1"]=wasmExports["__atomic_fetch_sub_1"])(a0,a1,a2);var ___atomic_fetch_sub_2=Module["___atomic_fetch_sub_2"]=(a0,a1,a2)=>(___atomic_fetch_sub_2=Module["___atomic_fetch_sub_2"]=wasmExports["__atomic_fetch_sub_2"])(a0,a1,a2);var ___atomic_fetch_sub_4=Module["___atomic_fetch_sub_4"]=(a0,a1,a2)=>(___atomic_fetch_sub_4=Module["___atomic_fetch_sub_4"]=wasmExports["__atomic_fetch_sub_4"])(a0,a1,a2);var ___atomic_fetch_sub_8=Module["___atomic_fetch_sub_8"]=(a0,a1,a2)=>(___atomic_fetch_sub_8=Module["___atomic_fetch_sub_8"]=wasmExports["__atomic_fetch_sub_8"])(a0,a1,a2);var ___atomic_fetch_sub_16=Module["___atomic_fetch_sub_16"]=(a0,a1,a2,a3,a4)=>(___atomic_fetch_sub_16=Module["___atomic_fetch_sub_16"]=wasmExports["__atomic_fetch_sub_16"])(a0,a1,a2,a3,a4);var ___atomic_fetch_and_1=Module["___atomic_fetch_and_1"]=(a0,a1,a2)=>(___atomic_fetch_and_1=Module["___atomic_fetch_and_1"]=wasmExports["__atomic_fetch_and_1"])(a0,a1,a2);var ___atomic_fetch_and_2=Module["___atomic_fetch_and_2"]=(a0,a1,a2)=>(___atomic_fetch_and_2=Module["___atomic_fetch_and_2"]=wasmExports["__atomic_fetch_and_2"])(a0,a1,a2);var ___atomic_fetch_and_4=Module["___atomic_fetch_and_4"]=(a0,a1,a2)=>(___atomic_fetch_and_4=Module["___atomic_fetch_and_4"]=wasmExports["__atomic_fetch_and_4"])(a0,a1,a2);var ___atomic_fetch_and_8=Module["___atomic_fetch_and_8"]=(a0,a1,a2)=>(___atomic_fetch_and_8=Module["___atomic_fetch_and_8"]=wasmExports["__atomic_fetch_and_8"])(a0,a1,a2);var ___atomic_fetch_and_16=Module["___atomic_fetch_and_16"]=(a0,a1,a2,a3,a4)=>(___atomic_fetch_and_16=Module["___atomic_fetch_and_16"]=wasmExports["__atomic_fetch_and_16"])(a0,a1,a2,a3,a4);var ___atomic_fetch_or_1=Module["___atomic_fetch_or_1"]=(a0,a1,a2)=>(___atomic_fetch_or_1=Module["___atomic_fetch_or_1"]=wasmExports["__atomic_fetch_or_1"])(a0,a1,a2);var ___atomic_fetch_or_2=Module["___atomic_fetch_or_2"]=(a0,a1,a2)=>(___atomic_fetch_or_2=Module["___atomic_fetch_or_2"]=wasmExports["__atomic_fetch_or_2"])(a0,a1,a2);var ___atomic_fetch_or_4=Module["___atomic_fetch_or_4"]=(a0,a1,a2)=>(___atomic_fetch_or_4=Module["___atomic_fetch_or_4"]=wasmExports["__atomic_fetch_or_4"])(a0,a1,a2);var ___atomic_fetch_or_8=Module["___atomic_fetch_or_8"]=(a0,a1,a2)=>(___atomic_fetch_or_8=Module["___atomic_fetch_or_8"]=wasmExports["__atomic_fetch_or_8"])(a0,a1,a2);var ___atomic_fetch_or_16=Module["___atomic_fetch_or_16"]=(a0,a1,a2,a3,a4)=>(___atomic_fetch_or_16=Module["___atomic_fetch_or_16"]=wasmExports["__atomic_fetch_or_16"])(a0,a1,a2,a3,a4);var ___atomic_fetch_xor_1=Module["___atomic_fetch_xor_1"]=(a0,a1,a2)=>(___atomic_fetch_xor_1=Module["___atomic_fetch_xor_1"]=wasmExports["__atomic_fetch_xor_1"])(a0,a1,a2);var ___atomic_fetch_xor_2=Module["___atomic_fetch_xor_2"]=(a0,a1,a2)=>(___atomic_fetch_xor_2=Module["___atomic_fetch_xor_2"]=wasmExports["__atomic_fetch_xor_2"])(a0,a1,a2);var ___atomic_fetch_xor_4=Module["___atomic_fetch_xor_4"]=(a0,a1,a2)=>(___atomic_fetch_xor_4=Module["___atomic_fetch_xor_4"]=wasmExports["__atomic_fetch_xor_4"])(a0,a1,a2);var ___atomic_fetch_xor_8=Module["___atomic_fetch_xor_8"]=(a0,a1,a2)=>(___atomic_fetch_xor_8=Module["___atomic_fetch_xor_8"]=wasmExports["__atomic_fetch_xor_8"])(a0,a1,a2);var ___atomic_fetch_xor_16=Module["___atomic_fetch_xor_16"]=(a0,a1,a2,a3,a4)=>(___atomic_fetch_xor_16=Module["___atomic_fetch_xor_16"]=wasmExports["__atomic_fetch_xor_16"])(a0,a1,a2,a3,a4);var ___atomic_fetch_nand_1=Module["___atomic_fetch_nand_1"]=(a0,a1,a2)=>(___atomic_fetch_nand_1=Module["___atomic_fetch_nand_1"]=wasmExports["__atomic_fetch_nand_1"])(a0,a1,a2);var ___atomic_fetch_nand_2=Module["___atomic_fetch_nand_2"]=(a0,a1,a2)=>(___atomic_fetch_nand_2=Module["___atomic_fetch_nand_2"]=wasmExports["__atomic_fetch_nand_2"])(a0,a1,a2);var ___atomic_fetch_nand_4=Module["___atomic_fetch_nand_4"]=(a0,a1,a2)=>(___atomic_fetch_nand_4=Module["___atomic_fetch_nand_4"]=wasmExports["__atomic_fetch_nand_4"])(a0,a1,a2);var ___atomic_fetch_nand_8=Module["___atomic_fetch_nand_8"]=(a0,a1,a2)=>(___atomic_fetch_nand_8=Module["___atomic_fetch_nand_8"]=wasmExports["__atomic_fetch_nand_8"])(a0,a1,a2);var ___atomic_fetch_nand_16=Module["___atomic_fetch_nand_16"]=(a0,a1,a2,a3,a4)=>(___atomic_fetch_nand_16=Module["___atomic_fetch_nand_16"]=wasmExports["__atomic_fetch_nand_16"])(a0,a1,a2,a3,a4);var _atomic_flag_clear=Module["_atomic_flag_clear"]=a0=>(_atomic_flag_clear=Module["_atomic_flag_clear"]=wasmExports["atomic_flag_clear"])(a0);var _atomic_flag_clear_explicit=Module["_atomic_flag_clear_explicit"]=(a0,a1)=>(_atomic_flag_clear_explicit=Module["_atomic_flag_clear_explicit"]=wasmExports["atomic_flag_clear_explicit"])(a0,a1);var _atomic_flag_test_and_set=Module["_atomic_flag_test_and_set"]=a0=>(_atomic_flag_test_and_set=Module["_atomic_flag_test_and_set"]=wasmExports["atomic_flag_test_and_set"])(a0);var _atomic_flag_test_and_set_explicit=Module["_atomic_flag_test_and_set_explicit"]=(a0,a1)=>(_atomic_flag_test_and_set_explicit=Module["_atomic_flag_test_and_set_explicit"]=wasmExports["atomic_flag_test_and_set_explicit"])(a0,a1);var _atomic_signal_fence=Module["_atomic_signal_fence"]=a0=>(_atomic_signal_fence=Module["_atomic_signal_fence"]=wasmExports["atomic_signal_fence"])(a0);var _atomic_thread_fence=Module["_atomic_thread_fence"]=a0=>(_atomic_thread_fence=Module["_atomic_thread_fence"]=wasmExports["atomic_thread_fence"])(a0);var ___bswapdi2=Module["___bswapdi2"]=a0=>(___bswapdi2=Module["___bswapdi2"]=wasmExports["__bswapdi2"])(a0);var ___bswapsi2=Module["___bswapsi2"]=a0=>(___bswapsi2=Module["___bswapsi2"]=wasmExports["__bswapsi2"])(a0);var ___clear_cache=Module["___clear_cache"]=(a0,a1)=>(___clear_cache=Module["___clear_cache"]=wasmExports["__clear_cache"])(a0,a1);var ___clzdi2=Module["___clzdi2"]=a0=>(___clzdi2=Module["___clzdi2"]=wasmExports["__clzdi2"])(a0);var ___clzsi2=Module["___clzsi2"]=a0=>(___clzsi2=Module["___clzsi2"]=wasmExports["__clzsi2"])(a0);var ___clzti2=Module["___clzti2"]=(a0,a1)=>(___clzti2=Module["___clzti2"]=wasmExports["__clzti2"])(a0,a1);var ___cmpdi2=Module["___cmpdi2"]=(a0,a1)=>(___cmpdi2=Module["___cmpdi2"]=wasmExports["__cmpdi2"])(a0,a1);var ___cmpti2=Module["___cmpti2"]=(a0,a1,a2,a3)=>(___cmpti2=Module["___cmpti2"]=wasmExports["__cmpti2"])(a0,a1,a2,a3);var ___ledf2=Module["___ledf2"]=(a0,a1)=>(___ledf2=Module["___ledf2"]=wasmExports["__ledf2"])(a0,a1);var ___gedf2=Module["___gedf2"]=(a0,a1)=>(___gedf2=Module["___gedf2"]=wasmExports["__gedf2"])(a0,a1);var ___unorddf2=Module["___unorddf2"]=(a0,a1)=>(___unorddf2=Module["___unorddf2"]=wasmExports["__unorddf2"])(a0,a1);var ___eqdf2=Module["___eqdf2"]=(a0,a1)=>(___eqdf2=Module["___eqdf2"]=wasmExports["__eqdf2"])(a0,a1);var ___ltdf2=Module["___ltdf2"]=(a0,a1)=>(___ltdf2=Module["___ltdf2"]=wasmExports["__ltdf2"])(a0,a1);var ___nedf2=Module["___nedf2"]=(a0,a1)=>(___nedf2=Module["___nedf2"]=wasmExports["__nedf2"])(a0,a1);var ___gtdf2=Module["___gtdf2"]=(a0,a1)=>(___gtdf2=Module["___gtdf2"]=wasmExports["__gtdf2"])(a0,a1);var ___lesf2=Module["___lesf2"]=(a0,a1)=>(___lesf2=Module["___lesf2"]=wasmExports["__lesf2"])(a0,a1);var ___gesf2=Module["___gesf2"]=(a0,a1)=>(___gesf2=Module["___gesf2"]=wasmExports["__gesf2"])(a0,a1);var ___unordsf2=Module["___unordsf2"]=(a0,a1)=>(___unordsf2=Module["___unordsf2"]=wasmExports["__unordsf2"])(a0,a1);var ___eqsf2=Module["___eqsf2"]=(a0,a1)=>(___eqsf2=Module["___eqsf2"]=wasmExports["__eqsf2"])(a0,a1);var ___ltsf2=Module["___ltsf2"]=(a0,a1)=>(___ltsf2=Module["___ltsf2"]=wasmExports["__ltsf2"])(a0,a1);var ___nesf2=Module["___nesf2"]=(a0,a1)=>(___nesf2=Module["___nesf2"]=wasmExports["__nesf2"])(a0,a1);var ___gtsf2=Module["___gtsf2"]=(a0,a1)=>(___gtsf2=Module["___gtsf2"]=wasmExports["__gtsf2"])(a0,a1);var ___ctzdi2=Module["___ctzdi2"]=a0=>(___ctzdi2=Module["___ctzdi2"]=wasmExports["__ctzdi2"])(a0);var ___ctzsi2=Module["___ctzsi2"]=a0=>(___ctzsi2=Module["___ctzsi2"]=wasmExports["__ctzsi2"])(a0);var ___ctzti2=Module["___ctzti2"]=(a0,a1)=>(___ctzti2=Module["___ctzti2"]=wasmExports["__ctzti2"])(a0,a1);var ___divdc3=Module["___divdc3"]=(a0,a1,a2,a3,a4)=>(___divdc3=Module["___divdc3"]=wasmExports["__divdc3"])(a0,a1,a2,a3,a4);var ___divdf3=Module["___divdf3"]=(a0,a1)=>(___divdf3=Module["___divdf3"]=wasmExports["__divdf3"])(a0,a1);var ___divdi3=Module["___divdi3"]=(a0,a1)=>(___divdi3=Module["___divdi3"]=wasmExports["__divdi3"])(a0,a1);var ___udivmoddi4=Module["___udivmoddi4"]=(a0,a1,a2)=>(___udivmoddi4=Module["___udivmoddi4"]=wasmExports["__udivmoddi4"])(a0,a1,a2);var ___divmoddi4=Module["___divmoddi4"]=(a0,a1,a2)=>(___divmoddi4=Module["___divmoddi4"]=wasmExports["__divmoddi4"])(a0,a1,a2);var ___divmodsi4=Module["___divmodsi4"]=(a0,a1,a2)=>(___divmodsi4=Module["___divmodsi4"]=wasmExports["__divmodsi4"])(a0,a1,a2);var ___udivmodsi4=Module["___udivmodsi4"]=(a0,a1,a2)=>(___udivmodsi4=Module["___udivmodsi4"]=wasmExports["__udivmodsi4"])(a0,a1,a2);var ___divmodti4=Module["___divmodti4"]=(a0,a1,a2,a3,a4,a5)=>(___divmodti4=Module["___divmodti4"]=wasmExports["__divmodti4"])(a0,a1,a2,a3,a4,a5);var ___udivmodti4=Module["___udivmodti4"]=(a0,a1,a2,a3,a4,a5)=>(___udivmodti4=Module["___udivmodti4"]=wasmExports["__udivmodti4"])(a0,a1,a2,a3,a4,a5);var ___divsc3=Module["___divsc3"]=(a0,a1,a2,a3,a4)=>(___divsc3=Module["___divsc3"]=wasmExports["__divsc3"])(a0,a1,a2,a3,a4);var ___divsf3=Module["___divsf3"]=(a0,a1)=>(___divsf3=Module["___divsf3"]=wasmExports["__divsf3"])(a0,a1);var ___divsi3=Module["___divsi3"]=(a0,a1)=>(___divsi3=Module["___divsi3"]=wasmExports["__divsi3"])(a0,a1);var ___divtc3=Module["___divtc3"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(___divtc3=Module["___divtc3"]=wasmExports["__divtc3"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var ___divti3=Module["___divti3"]=(a0,a1,a2,a3,a4)=>(___divti3=Module["___divti3"]=wasmExports["__divti3"])(a0,a1,a2,a3,a4);var _setThrew=(a0,a1)=>(_setThrew=wasmExports["setThrew"])(a0,a1);var ___wasm_setjmp=Module["___wasm_setjmp"]=(a0,a1,a2)=>(___wasm_setjmp=Module["___wasm_setjmp"]=wasmExports["__wasm_setjmp"])(a0,a1,a2);var ___wasm_setjmp_test=Module["___wasm_setjmp_test"]=(a0,a1)=>(___wasm_setjmp_test=Module["___wasm_setjmp_test"]=wasmExports["__wasm_setjmp_test"])(a0,a1);var _emscripten_longjmp=Module["_emscripten_longjmp"]=(a0,a1)=>(_emscripten_longjmp=Module["_emscripten_longjmp"]=wasmExports["emscripten_longjmp"])(a0,a1);var __emscripten_tempret_set=a0=>(__emscripten_tempret_set=wasmExports["_emscripten_tempret_set"])(a0);var __emscripten_tempret_get=()=>(__emscripten_tempret_get=wasmExports["_emscripten_tempret_get"])();var ___get_temp_ret=Module["___get_temp_ret"]=()=>(___get_temp_ret=Module["___get_temp_ret"]=wasmExports["__get_temp_ret"])();var ___set_temp_ret=Module["___set_temp_ret"]=a0=>(___set_temp_ret=Module["___set_temp_ret"]=wasmExports["__set_temp_ret"])(a0);var _getTempRet0=Module["_getTempRet0"]=()=>(_getTempRet0=Module["_getTempRet0"]=wasmExports["getTempRet0"])();var _setTempRet0=Module["_setTempRet0"]=a0=>(_setTempRet0=Module["_setTempRet0"]=wasmExports["setTempRet0"])(a0);var ___emutls_get_address=Module["___emutls_get_address"]=a0=>(___emutls_get_address=Module["___emutls_get_address"]=wasmExports["__emutls_get_address"])(a0);var ___enable_execute_stack=Module["___enable_execute_stack"]=a0=>(___enable_execute_stack=Module["___enable_execute_stack"]=wasmExports["__enable_execute_stack"])(a0);var ___extendhfsf2=Module["___extendhfsf2"]=a0=>(___extendhfsf2=Module["___extendhfsf2"]=wasmExports["__extendhfsf2"])(a0);var ___gnu_h2f_ieee=Module["___gnu_h2f_ieee"]=a0=>(___gnu_h2f_ieee=Module["___gnu_h2f_ieee"]=wasmExports["__gnu_h2f_ieee"])(a0);var ___extendsfdf2=Module["___extendsfdf2"]=a0=>(___extendsfdf2=Module["___extendsfdf2"]=wasmExports["__extendsfdf2"])(a0);var ___ffsdi2=Module["___ffsdi2"]=a0=>(___ffsdi2=Module["___ffsdi2"]=wasmExports["__ffsdi2"])(a0);var ___ffssi2=Module["___ffssi2"]=a0=>(___ffssi2=Module["___ffssi2"]=wasmExports["__ffssi2"])(a0);var ___ffsti2=Module["___ffsti2"]=(a0,a1)=>(___ffsti2=Module["___ffsti2"]=wasmExports["__ffsti2"])(a0,a1);var ___fixdfdi=Module["___fixdfdi"]=a0=>(___fixdfdi=Module["___fixdfdi"]=wasmExports["__fixdfdi"])(a0);var ___fixunsdfdi=Module["___fixunsdfdi"]=a0=>(___fixunsdfdi=Module["___fixunsdfdi"]=wasmExports["__fixunsdfdi"])(a0);var ___fixdfsi=Module["___fixdfsi"]=a0=>(___fixdfsi=Module["___fixdfsi"]=wasmExports["__fixdfsi"])(a0);var ___fixdfti=Module["___fixdfti"]=(a0,a1)=>(___fixdfti=Module["___fixdfti"]=wasmExports["__fixdfti"])(a0,a1);var ___fixsfdi=Module["___fixsfdi"]=a0=>(___fixsfdi=Module["___fixsfdi"]=wasmExports["__fixsfdi"])(a0);var ___fixunssfdi=Module["___fixunssfdi"]=a0=>(___fixunssfdi=Module["___fixunssfdi"]=wasmExports["__fixunssfdi"])(a0);var ___fixsfsi=Module["___fixsfsi"]=a0=>(___fixsfsi=Module["___fixsfsi"]=wasmExports["__fixsfsi"])(a0);var ___fixsfti=Module["___fixsfti"]=(a0,a1)=>(___fixsfti=Module["___fixsfti"]=wasmExports["__fixsfti"])(a0,a1);var ___fixtfti=Module["___fixtfti"]=(a0,a1,a2)=>(___fixtfti=Module["___fixtfti"]=wasmExports["__fixtfti"])(a0,a1,a2);var ___fixunsdfsi=Module["___fixunsdfsi"]=a0=>(___fixunsdfsi=Module["___fixunsdfsi"]=wasmExports["__fixunsdfsi"])(a0);var ___fixunsdfti=Module["___fixunsdfti"]=(a0,a1)=>(___fixunsdfti=Module["___fixunsdfti"]=wasmExports["__fixunsdfti"])(a0,a1);var ___fixunssfsi=Module["___fixunssfsi"]=a0=>(___fixunssfsi=Module["___fixunssfsi"]=wasmExports["__fixunssfsi"])(a0);var ___fixunssfti=Module["___fixunssfti"]=(a0,a1)=>(___fixunssfti=Module["___fixunssfti"]=wasmExports["__fixunssfti"])(a0,a1);var ___fixunstfdi=Module["___fixunstfdi"]=(a0,a1)=>(___fixunstfdi=Module["___fixunstfdi"]=wasmExports["__fixunstfdi"])(a0,a1);var ___fixunstfsi=Module["___fixunstfsi"]=(a0,a1)=>(___fixunstfsi=Module["___fixunstfsi"]=wasmExports["__fixunstfsi"])(a0,a1);var ___fixunstfti=Module["___fixunstfti"]=(a0,a1,a2)=>(___fixunstfti=Module["___fixunstfti"]=wasmExports["__fixunstfti"])(a0,a1,a2);var ___floatdidf=Module["___floatdidf"]=a0=>(___floatdidf=Module["___floatdidf"]=wasmExports["__floatdidf"])(a0);var ___floatdisf=Module["___floatdisf"]=a0=>(___floatdisf=Module["___floatdisf"]=wasmExports["__floatdisf"])(a0);var ___floatditf=Module["___floatditf"]=(a0,a1)=>(___floatditf=Module["___floatditf"]=wasmExports["__floatditf"])(a0,a1);var ___floatsidf=Module["___floatsidf"]=a0=>(___floatsidf=Module["___floatsidf"]=wasmExports["__floatsidf"])(a0);var ___floatsisf=Module["___floatsisf"]=a0=>(___floatsisf=Module["___floatsisf"]=wasmExports["__floatsisf"])(a0);var ___floattidf=Module["___floattidf"]=(a0,a1)=>(___floattidf=Module["___floattidf"]=wasmExports["__floattidf"])(a0,a1);var ___floattisf=Module["___floattisf"]=(a0,a1)=>(___floattisf=Module["___floattisf"]=wasmExports["__floattisf"])(a0,a1);var ___floattitf=Module["___floattitf"]=(a0,a1,a2)=>(___floattitf=Module["___floattitf"]=wasmExports["__floattitf"])(a0,a1,a2);var ___floatundidf=Module["___floatundidf"]=a0=>(___floatundidf=Module["___floatundidf"]=wasmExports["__floatundidf"])(a0);var ___floatundisf=Module["___floatundisf"]=a0=>(___floatundisf=Module["___floatundisf"]=wasmExports["__floatundisf"])(a0);var ___floatunditf=Module["___floatunditf"]=(a0,a1)=>(___floatunditf=Module["___floatunditf"]=wasmExports["__floatunditf"])(a0,a1);var ___floatunsidf=Module["___floatunsidf"]=a0=>(___floatunsidf=Module["___floatunsidf"]=wasmExports["__floatunsidf"])(a0);var ___floatunsisf=Module["___floatunsisf"]=a0=>(___floatunsisf=Module["___floatunsisf"]=wasmExports["__floatunsisf"])(a0);var ___floatuntidf=Module["___floatuntidf"]=(a0,a1)=>(___floatuntidf=Module["___floatuntidf"]=wasmExports["__floatuntidf"])(a0,a1);var ___floatuntisf=Module["___floatuntisf"]=(a0,a1)=>(___floatuntisf=Module["___floatuntisf"]=wasmExports["__floatuntisf"])(a0,a1);var ___floatuntitf=Module["___floatuntitf"]=(a0,a1,a2)=>(___floatuntitf=Module["___floatuntitf"]=wasmExports["__floatuntitf"])(a0,a1,a2);var ___lshrdi3=Module["___lshrdi3"]=(a0,a1)=>(___lshrdi3=Module["___lshrdi3"]=wasmExports["__lshrdi3"])(a0,a1);var ___moddi3=Module["___moddi3"]=(a0,a1)=>(___moddi3=Module["___moddi3"]=wasmExports["__moddi3"])(a0,a1);var ___modsi3=Module["___modsi3"]=(a0,a1)=>(___modsi3=Module["___modsi3"]=wasmExports["__modsi3"])(a0,a1);var ___modti3=Module["___modti3"]=(a0,a1,a2,a3,a4)=>(___modti3=Module["___modti3"]=wasmExports["__modti3"])(a0,a1,a2,a3,a4);var ___muldf3=Module["___muldf3"]=(a0,a1)=>(___muldf3=Module["___muldf3"]=wasmExports["__muldf3"])(a0,a1);var ___muldi3=Module["___muldi3"]=(a0,a1)=>(___muldi3=Module["___muldi3"]=wasmExports["__muldi3"])(a0,a1);var ___mulodi4=Module["___mulodi4"]=(a0,a1,a2)=>(___mulodi4=Module["___mulodi4"]=wasmExports["__mulodi4"])(a0,a1,a2);var ___mulosi4=Module["___mulosi4"]=(a0,a1,a2)=>(___mulosi4=Module["___mulosi4"]=wasmExports["__mulosi4"])(a0,a1,a2);var ___muloti4=Module["___muloti4"]=(a0,a1,a2,a3,a4,a5)=>(___muloti4=Module["___muloti4"]=wasmExports["__muloti4"])(a0,a1,a2,a3,a4,a5);var ___udivti3=Module["___udivti3"]=(a0,a1,a2,a3,a4)=>(___udivti3=Module["___udivti3"]=wasmExports["__udivti3"])(a0,a1,a2,a3,a4);var ___mulsf3=Module["___mulsf3"]=(a0,a1)=>(___mulsf3=Module["___mulsf3"]=wasmExports["__mulsf3"])(a0,a1);var ___mulvdi3=Module["___mulvdi3"]=(a0,a1)=>(___mulvdi3=Module["___mulvdi3"]=wasmExports["__mulvdi3"])(a0,a1);var ___mulvsi3=Module["___mulvsi3"]=(a0,a1)=>(___mulvsi3=Module["___mulvsi3"]=wasmExports["__mulvsi3"])(a0,a1);var ___mulvti3=Module["___mulvti3"]=(a0,a1,a2,a3,a4)=>(___mulvti3=Module["___mulvti3"]=wasmExports["__mulvti3"])(a0,a1,a2,a3,a4);var ___negdf2=Module["___negdf2"]=a0=>(___negdf2=Module["___negdf2"]=wasmExports["__negdf2"])(a0);var ___negdi2=Module["___negdi2"]=a0=>(___negdi2=Module["___negdi2"]=wasmExports["__negdi2"])(a0);var ___negsf2=Module["___negsf2"]=a0=>(___negsf2=Module["___negsf2"]=wasmExports["__negsf2"])(a0);var ___negti2=Module["___negti2"]=(a0,a1,a2)=>(___negti2=Module["___negti2"]=wasmExports["__negti2"])(a0,a1,a2);var ___negvdi2=Module["___negvdi2"]=a0=>(___negvdi2=Module["___negvdi2"]=wasmExports["__negvdi2"])(a0);var ___negvsi2=Module["___negvsi2"]=a0=>(___negvsi2=Module["___negvsi2"]=wasmExports["__negvsi2"])(a0);var ___negvti2=Module["___negvti2"]=(a0,a1,a2)=>(___negvti2=Module["___negvti2"]=wasmExports["__negvti2"])(a0,a1,a2);var ___paritydi2=Module["___paritydi2"]=a0=>(___paritydi2=Module["___paritydi2"]=wasmExports["__paritydi2"])(a0);var ___paritysi2=Module["___paritysi2"]=a0=>(___paritysi2=Module["___paritysi2"]=wasmExports["__paritysi2"])(a0);var ___parityti2=Module["___parityti2"]=(a0,a1)=>(___parityti2=Module["___parityti2"]=wasmExports["__parityti2"])(a0,a1);var ___popcountdi2=Module["___popcountdi2"]=a0=>(___popcountdi2=Module["___popcountdi2"]=wasmExports["__popcountdi2"])(a0);var ___popcountsi2=Module["___popcountsi2"]=a0=>(___popcountsi2=Module["___popcountsi2"]=wasmExports["__popcountsi2"])(a0);var ___popcountti2=Module["___popcountti2"]=(a0,a1)=>(___popcountti2=Module["___popcountti2"]=wasmExports["__popcountti2"])(a0,a1);var ___powidf2=Module["___powidf2"]=(a0,a1)=>(___powidf2=Module["___powidf2"]=wasmExports["__powidf2"])(a0,a1);var ___powisf2=Module["___powisf2"]=(a0,a1)=>(___powisf2=Module["___powisf2"]=wasmExports["__powisf2"])(a0,a1);var ___powitf2=Module["___powitf2"]=(a0,a1,a2,a3)=>(___powitf2=Module["___powitf2"]=wasmExports["__powitf2"])(a0,a1,a2,a3);var _emscripten_stack_init=Module["_emscripten_stack_init"]=()=>(_emscripten_stack_init=Module["_emscripten_stack_init"]=wasmExports["emscripten_stack_init"])();var _emscripten_stack_set_limits=Module["_emscripten_stack_set_limits"]=(a0,a1)=>(_emscripten_stack_set_limits=Module["_emscripten_stack_set_limits"]=wasmExports["emscripten_stack_set_limits"])(a0,a1);var _emscripten_stack_get_free=Module["_emscripten_stack_get_free"]=()=>(_emscripten_stack_get_free=Module["_emscripten_stack_get_free"]=wasmExports["emscripten_stack_get_free"])();var __emscripten_stack_restore=a0=>(__emscripten_stack_restore=wasmExports["_emscripten_stack_restore"])(a0);var __emscripten_stack_alloc=a0=>(__emscripten_stack_alloc=wasmExports["_emscripten_stack_alloc"])(a0);var ___subdf3=Module["___subdf3"]=(a0,a1)=>(___subdf3=Module["___subdf3"]=wasmExports["__subdf3"])(a0,a1);var ___subsf3=Module["___subsf3"]=(a0,a1)=>(___subsf3=Module["___subsf3"]=wasmExports["__subsf3"])(a0,a1);var ___subvdi3=Module["___subvdi3"]=(a0,a1)=>(___subvdi3=Module["___subvdi3"]=wasmExports["__subvdi3"])(a0,a1);var ___subvsi3=Module["___subvsi3"]=(a0,a1)=>(___subvsi3=Module["___subvsi3"]=wasmExports["__subvsi3"])(a0,a1);var ___subvti3=Module["___subvti3"]=(a0,a1,a2,a3,a4)=>(___subvti3=Module["___subvti3"]=wasmExports["__subvti3"])(a0,a1,a2,a3,a4);var ___truncdfhf2=Module["___truncdfhf2"]=a0=>(___truncdfhf2=Module["___truncdfhf2"]=wasmExports["__truncdfhf2"])(a0);var ___truncdfsf2=Module["___truncdfsf2"]=a0=>(___truncdfsf2=Module["___truncdfsf2"]=wasmExports["__truncdfsf2"])(a0);var ___truncsfhf2=Module["___truncsfhf2"]=a0=>(___truncsfhf2=Module["___truncsfhf2"]=wasmExports["__truncsfhf2"])(a0);var ___gnu_f2h_ieee=Module["___gnu_f2h_ieee"]=a0=>(___gnu_f2h_ieee=Module["___gnu_f2h_ieee"]=wasmExports["__gnu_f2h_ieee"])(a0);var ___ucmpdi2=Module["___ucmpdi2"]=(a0,a1)=>(___ucmpdi2=Module["___ucmpdi2"]=wasmExports["__ucmpdi2"])(a0,a1);var ___ucmpti2=Module["___ucmpti2"]=(a0,a1,a2,a3)=>(___ucmpti2=Module["___ucmpti2"]=wasmExports["__ucmpti2"])(a0,a1,a2,a3);var ___udivdi3=Module["___udivdi3"]=(a0,a1)=>(___udivdi3=Module["___udivdi3"]=wasmExports["__udivdi3"])(a0,a1);var ___udivsi3=Module["___udivsi3"]=(a0,a1)=>(___udivsi3=Module["___udivsi3"]=wasmExports["__udivsi3"])(a0,a1);var ___umoddi3=Module["___umoddi3"]=(a0,a1)=>(___umoddi3=Module["___umoddi3"]=wasmExports["__umoddi3"])(a0,a1);var ___umodsi3=Module["___umodsi3"]=(a0,a1)=>(___umodsi3=Module["___umodsi3"]=wasmExports["__umodsi3"])(a0,a1);var ___umodti3=Module["___umodti3"]=(a0,a1,a2,a3,a4)=>(___umodti3=Module["___umodti3"]=wasmExports["__umodti3"])(a0,a1,a2,a3,a4);var ___cxa_allocate_exception=Module["___cxa_allocate_exception"]=a0=>(___cxa_allocate_exception=Module["___cxa_allocate_exception"]=wasmExports["__cxa_allocate_exception"])(a0);var ___cxa_free_exception=a0=>(___cxa_free_exception=wasmExports["__cxa_free_exception"])(a0);var ___cxa_pure_virtual=Module["___cxa_pure_virtual"]=()=>(___cxa_pure_virtual=Module["___cxa_pure_virtual"]=wasmExports["__cxa_pure_virtual"])();var ___cxa_decrement_exception_refcount=a0=>(___cxa_decrement_exception_refcount=wasmExports["__cxa_decrement_exception_refcount"])(a0);var ___cxa_increment_exception_refcount=a0=>(___cxa_increment_exception_refcount=wasmExports["__cxa_increment_exception_refcount"])(a0);var ___cxa_init_primary_exception=Module["___cxa_init_primary_exception"]=(a0,a1,a2)=>(___cxa_init_primary_exception=Module["___cxa_init_primary_exception"]=wasmExports["__cxa_init_primary_exception"])(a0,a1,a2);var ___dynamic_cast=Module["___dynamic_cast"]=(a0,a1,a2,a3)=>(___dynamic_cast=Module["___dynamic_cast"]=wasmExports["__dynamic_cast"])(a0,a1,a2,a3);var ___cxa_bad_cast=Module["___cxa_bad_cast"]=()=>(___cxa_bad_cast=Module["___cxa_bad_cast"]=wasmExports["__cxa_bad_cast"])();var ___cxa_bad_typeid=Module["___cxa_bad_typeid"]=()=>(___cxa_bad_typeid=Module["___cxa_bad_typeid"]=wasmExports["__cxa_bad_typeid"])();var ___cxa_throw_bad_array_new_length=Module["___cxa_throw_bad_array_new_length"]=()=>(___cxa_throw_bad_array_new_length=Module["___cxa_throw_bad_array_new_length"]=wasmExports["__cxa_throw_bad_array_new_length"])();var ___cxa_demangle=(a0,a1,a2,a3)=>(___cxa_demangle=wasmExports["__cxa_demangle"])(a0,a1,a2,a3);var ___gxx_personality_v0=Module["___gxx_personality_v0"]=(a0,a1,a2,a3,a4)=>(___gxx_personality_v0=Module["___gxx_personality_v0"]=wasmExports["__gxx_personality_v0"])(a0,a1,a2,a3,a4);var ___thrown_object_from_unwind_exception=Module["___thrown_object_from_unwind_exception"]=a0=>(___thrown_object_from_unwind_exception=Module["___thrown_object_from_unwind_exception"]=wasmExports["__thrown_object_from_unwind_exception"])(a0);var ___get_exception_message=(a0,a1,a2)=>(___get_exception_message=wasmExports["__get_exception_message"])(a0,a1,a2);var ___get_exception_terminate_message=Module["___get_exception_terminate_message"]=a0=>(___get_exception_terminate_message=Module["___get_exception_terminate_message"]=wasmExports["__get_exception_terminate_message"])(a0);var ___cxa_guard_acquire=Module["___cxa_guard_acquire"]=a0=>(___cxa_guard_acquire=Module["___cxa_guard_acquire"]=wasmExports["__cxa_guard_acquire"])(a0);var ___cxa_guard_release=Module["___cxa_guard_release"]=a0=>(___cxa_guard_release=Module["___cxa_guard_release"]=wasmExports["__cxa_guard_release"])(a0);var ___cxa_guard_abort=Module["___cxa_guard_abort"]=a0=>(___cxa_guard_abort=Module["___cxa_guard_abort"]=wasmExports["__cxa_guard_abort"])(a0);var ___cxa_thread_atexit=Module["___cxa_thread_atexit"]=(a0,a1,a2)=>(___cxa_thread_atexit=Module["___cxa_thread_atexit"]=wasmExports["__cxa_thread_atexit"])(a0,a1,a2);var ___cxa_deleted_virtual=Module["___cxa_deleted_virtual"]=()=>(___cxa_deleted_virtual=Module["___cxa_deleted_virtual"]=wasmExports["__cxa_deleted_virtual"])();var ___cxa_can_catch=(a0,a1,a2)=>(___cxa_can_catch=wasmExports["__cxa_can_catch"])(a0,a1,a2);var ___cxa_is_pointer_type=a0=>(___cxa_is_pointer_type=wasmExports["__cxa_is_pointer_type"])(a0);var _gethostbyaddr_r=Module["_gethostbyaddr_r"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(_gethostbyaddr_r=Module["_gethostbyaddr_r"]=wasmExports["gethostbyaddr_r"])(a0,a1,a2,a3,a4,a5,a6,a7);var _gethostbyname2=Module["_gethostbyname2"]=(a0,a1)=>(_gethostbyname2=Module["_gethostbyname2"]=wasmExports["gethostbyname2"])(a0,a1);var _gethostbyname2_r=Module["_gethostbyname2_r"]=(a0,a1,a2,a3,a4,a5,a6)=>(_gethostbyname2_r=Module["_gethostbyname2_r"]=wasmExports["gethostbyname2_r"])(a0,a1,a2,a3,a4,a5,a6);var _gethostbyname_r=Module["_gethostbyname_r"]=(a0,a1,a2,a3,a4,a5)=>(_gethostbyname_r=Module["_gethostbyname_r"]=wasmExports["gethostbyname_r"])(a0,a1,a2,a3,a4,a5);var _shutdown=Module["_shutdown"]=(a0,a1)=>(_shutdown=Module["_shutdown"]=wasmExports["shutdown"])(a0,a1);var _socketpair=Module["_socketpair"]=(a0,a1,a2,a3)=>(_socketpair=Module["_socketpair"]=wasmExports["socketpair"])(a0,a1,a2,a3);var _py_docstring_mod=Module["_py_docstring_mod"]=4582144;var _PyExc_AttributeError=Module["_PyExc_AttributeError"]=3194744;var _stdout=Module["_stdout"]=4429296;var _PyExc_ModuleNotFoundError=Module["_PyExc_ModuleNotFoundError"]=3189868;var __Py_NoneStruct=Module["__Py_NoneStruct"]=3221576;var _internal_error=Module["_internal_error"]=4582152;var _conversion_error=Module["_conversion_error"]=4582156;var _PyExc_ImportError=Module["_PyExc_ImportError"]=3189656;var _pyodide_export_=Module["_pyodide_export_"]=3171504;var _py_version_major_=Module["_py_version_major_"]=3171508;var _set_new_cframe_=Module["_set_new_cframe_"]=3171512;var __Py_TrueStruct=Module["__Py_TrueStruct"]=3176132;var __Py_FalseStruct=Module["__Py_FalseStruct"]=3176148;var _jsbind=Module["_jsbind"]=4582212;var _PyExc_TypeError=Module["_PyExc_TypeError"]=3188168;var _Jsr_undefined=Module["_Jsr_undefined"]=255324;var _PyExc_StopIteration=Module["_PyExc_StopIteration"]=3188592;var _PyTraceBack_Type=Module["_PyTraceBack_Type"]=3723036;var _PyExc_GeneratorExit=Module["_PyExc_GeneratorExit"]=3188804;var _PyExc_StopAsyncIteration=Module["_PyExc_StopAsyncIteration"]=3188380;var _PyExc_RuntimeError=Module["_PyExc_RuntimeError"]=3193684;var _PyExc_IndexError=Module["_PyExc_IndexError"]=3195804;var _PyExc_Exception=Module["_PyExc_Exception"]=3187956;var _PyExc_BaseException=Module["_PyExc_BaseException"]=3187744;var _methods=Module["_methods"]=3172752;var _PyExc_SystemError=Module["_PyExc_SystemError"]=3198344;var _PyExc_KeyError=Module["_PyExc_KeyError"]=3196016;var _PySlice_Type=Module["_PySlice_Type"]=3226480;var _PyLong_Type=Module["_PyLong_Type"]=3212144;var _PyBool_Type=Module["_PyBool_Type"]=3176308;var _PyExc_ValueError=Module["_PyExc_ValueError"]=3189024;var _PyExc_NotImplementedError=Module["_PyExc_NotImplementedError"]=3194108;var _PyBaseObject_Type=Module["_PyBaseObject_Type"]=3228504;var _PyExc_OverflowError=Module["_PyExc_OverflowError"]=3197920;var _PyList_Type=Module["_PyList_Type"]=3210992;var _PyTuple_Type=Module["_PyTuple_Type"]=3226832;var __Py_NotImplementedStruct=Module["__Py_NotImplementedStruct"]=3222352;var _default_signature=Module["_default_signature"]=4582220;var _no_default=Module["_no_default"]=4582216;var _PyCoro_Type=Module["_PyCoro_Type"]=3204976;var _PyGen_Type=Module["_PyGen_Type"]=3204768;var _PyDict_Type=Module["_PyDict_Type"]=3213432;var _compat_to_string_repr=Module["_compat_to_string_repr"]=4582236;var _PyMethod_Type=Module["_PyMethod_Type"]=3181240;var _PyFunction_Type=Module["_PyFunction_Type"]=3208492;var _py_buffer_len_offset=Module["_py_buffer_len_offset"]=3174856;var _py_buffer_shape_offset=Module["_py_buffer_shape_offset"]=3174860;var _Jsr_true=Module["_Jsr_true"]=255328;var _Jsr_false=Module["_Jsr_false"]=255332;var _Jsr_novalue=Module["_Jsr_novalue"]=255336;var _PySet_Type=Module["_PySet_Type"]=3225104;var _PyFloat_Type=Module["_PyFloat_Type"]=3207232;var _threadstate_freelist_len=Module["_threadstate_freelist_len"]=4582312;var _threadstate_freelist=Module["_threadstate_freelist"]=4582272;var _size_of_cframe=Module["_size_of_cframe"]=3175424;var _stderr=Module["_stderr"]=4428992;var __PyParser_TokenNames=Module["__PyParser_TokenNames"]=3175440;var _PyExc_SyntaxError=Module["_PyExc_SyntaxError"]=3194956;var _PyExc_LookupError=Module["_PyExc_LookupError"]=3195592;var _PyExc_UnicodeDecodeError=Module["_PyExc_UnicodeDecodeError"]=3196860;var _PyExc_IndentationError=Module["_PyExc_IndentationError"]=3195168;var _PyExc_KeyboardInterrupt=Module["_PyExc_KeyboardInterrupt"]=3189444;var _PyExc_TabError=Module["_PyExc_TabError"]=3195380;var _PyExc_UnicodeError=Module["_PyExc_UnicodeError"]=3196436;var _stdin=Module["_stdin"]=4429144;var _PyExc_MemoryError=Module["_PyExc_MemoryError"]=3198560;var __PyRuntime=Module["__PyRuntime"]=3248552;var _PyComplex_Type=Module["_PyComplex_Type"]=3183356;var _PyBytes_Type=Module["_PyBytes_Type"]=3178712;var _PyUnicode_Type=Module["_PyUnicode_Type"]=3235072;var __Py_EllipsisObject=Module["__Py_EllipsisObject"]=3226336;var __Py_ctype_table=Module["__Py_ctype_table"]=456752;var _PyExc_DeprecationWarning=Module["_PyExc_DeprecationWarning"]=3199616;var _PyExc_SyntaxWarning=Module["_PyExc_SyntaxWarning"]=3200040;var __PyOS_ReadlineTState=Module["__PyOS_ReadlineTState"]=4582372;var _PyOS_InputHook=Module["_PyOS_InputHook"]=4582376;var _PyOS_ReadlineFunctionPointer=Module["_PyOS_ReadlineFunctionPointer"]=4582380;var _PyExc_OSError=Module["_PyExc_OSError"]=3190080;var _PyType_Type=Module["_PyType_Type"]=3227456;var _PyExc_BufferError=Module["_PyExc_BufferError"]=3198980;var _PyCFunction_Type=Module["_PyCFunction_Type"]=3220244;var _PyByteArray_Type=Module["_PyByteArray_Type"]=3176516;var __PyByteArray_empty_string=Module["__PyByteArray_empty_string"]=4582388;var __Py_ctype_tolower=Module["__Py_ctype_tolower"]=457776;var __Py_ctype_toupper=Module["__Py_ctype_toupper"]=458032;var _Py_hexdigits=Module["_Py_hexdigits"]=3244072;var _PyExc_BytesWarning=Module["_PyExc_BytesWarning"]=3201100;var _PyByteArrayIter_Type=Module["_PyByteArrayIter_Type"]=3177872;var __PyLong_DigitValue=Module["__PyLong_DigitValue"]=3212352;var _PyBytesIter_Type=Module["_PyBytesIter_Type"]=3179920;var _PyModule_Type=Module["_PyModule_Type"]=3220872;var _PyCapsule_Type=Module["_PyCapsule_Type"]=3180784;var _PyCell_Type=Module["_PyCell_Type"]=3180992;var _PyInstanceMethod_Type=Module["_PyInstanceMethod_Type"]=3181592;var _PyCode_Type=Module["_PyCode_Type"]=3181896;var _PyFrozenSet_Type=Module["_PyFrozenSet_Type"]=3225664;var _PyExc_ZeroDivisionError=Module["_PyExc_ZeroDivisionError"]=3198132;var __PyMethodWrapper_Type=Module["__PyMethodWrapper_Type"]=3185768;var _PyMethodDescr_Type=Module["_PyMethodDescr_Type"]=3184112;var _PyClassMethodDescr_Type=Module["_PyClassMethodDescr_Type"]=3184320;var _PyMemberDescr_Type=Module["_PyMemberDescr_Type"]=3184588;var _PyGetSetDescr_Type=Module["_PyGetSetDescr_Type"]=3184860;var _PyWrapperDescr_Type=Module["_PyWrapperDescr_Type"]=3185152;var _PyDictProxy_Type=Module["_PyDictProxy_Type"]=3185360;var _PyProperty_Type=Module["_PyProperty_Type"]=3186536;var _PyReversed_Type=Module["_PyReversed_Type"]=3187248;var _PyEnum_Type=Module["_PyEnum_Type"]=3186976;var _PyExc_BaseExceptionGroup=Module["_PyExc_BaseExceptionGroup"]=3189020;var _PyExc_UnicodeTranslateError=Module["_PyExc_UnicodeTranslateError"]=3197072;var _PyExc_BlockingIOError=Module["_PyExc_BlockingIOError"]=3190292;var _PyExc_BrokenPipeError=Module["_PyExc_BrokenPipeError"]=3190928;var _PyExc_ChildProcessError=Module["_PyExc_ChildProcessError"]=3190716;var _PyExc_ConnectionAbortedError=Module["_PyExc_ConnectionAbortedError"]=3191140;var _PyExc_ConnectionRefusedError=Module["_PyExc_ConnectionRefusedError"]=3191352;var _PyExc_ConnectionResetError=Module["_PyExc_ConnectionResetError"]=3191564;var _PyExc_FileExistsError=Module["_PyExc_FileExistsError"]=3191776;var _PyExc_FileNotFoundError=Module["_PyExc_FileNotFoundError"]=3191988;var _PyExc_IsADirectoryError=Module["_PyExc_IsADirectoryError"]=3192200;var _PyExc_NotADirectoryError=Module["_PyExc_NotADirectoryError"]=3192412;var _PyExc_InterruptedError=Module["_PyExc_InterruptedError"]=3192624;var _PyExc_PermissionError=Module["_PyExc_PermissionError"]=3192836;var _PyExc_ProcessLookupError=Module["_PyExc_ProcessLookupError"]=3193048;var _PyExc_TimeoutError=Module["_PyExc_TimeoutError"]=3193260;var _PyExc_EnvironmentError=Module["_PyExc_EnvironmentError"]=4582392;var _PyExc_IOError=Module["_PyExc_IOError"]=4582396;var _PyExc_SystemExit=Module["_PyExc_SystemExit"]=3189016;var _PyExc_ConnectionError=Module["_PyExc_ConnectionError"]=3190504;var _PyExc_EOFError=Module["_PyExc_EOFError"]=3193472;var _PyExc_RecursionError=Module["_PyExc_RecursionError"]=3193896;var _PyExc_NameError=Module["_PyExc_NameError"]=3194320;var _PyExc_UnboundLocalError=Module["_PyExc_UnboundLocalError"]=3194532;var _PyExc_UnicodeEncodeError=Module["_PyExc_UnicodeEncodeError"]=3196648;var _PyExc_AssertionError=Module["_PyExc_AssertionError"]=3197284;var _PyExc_ArithmeticError=Module["_PyExc_ArithmeticError"]=3197496;var _PyExc_FloatingPointError=Module["_PyExc_FloatingPointError"]=3197708;var _PyExc_ReferenceError=Module["_PyExc_ReferenceError"]=3198556;var _PyExc_Warning=Module["_PyExc_Warning"]=3199192;var _PyExc_UserWarning=Module["_PyExc_UserWarning"]=3199404;var _PyExc_PendingDeprecationWarning=Module["_PyExc_PendingDeprecationWarning"]=3199828;var _PyExc_RuntimeWarning=Module["_PyExc_RuntimeWarning"]=3200252;var _PyExc_FutureWarning=Module["_PyExc_FutureWarning"]=3200464;var _PyExc_ImportWarning=Module["_PyExc_ImportWarning"]=3200676;var _PyExc_UnicodeWarning=Module["_PyExc_UnicodeWarning"]=3200888;var _PyExc_EncodingWarning=Module["_PyExc_EncodingWarning"]=3201312;var _PyExc_ResourceWarning=Module["_PyExc_ResourceWarning"]=3201524;var _Py_GenericAliasType=Module["_Py_GenericAliasType"]=3204044;var _PyAsyncGen_Type=Module["_PyAsyncGen_Type"]=3204304;var __PyAsyncGenWrappedValue_Type=Module["__PyAsyncGenWrappedValue_Type"]=3206352;var __PyCoroWrapper_Type=Module["__PyCoroWrapper_Type"]=3205552;var __PyAsyncGenASend_Type=Module["__PyAsyncGenASend_Type"]=3206144;var __PyAsyncGenAThrow_Type=Module["__PyAsyncGenAThrow_Type"]=3206640;var _PyStdPrinter_Type=Module["_PyStdPrinter_Type"]=3206848;var __Py_SwappedOp=Module["__Py_SwappedOp"]=3221584;var _PyFrame_Type=Module["_PyFrame_Type"]=3208264;var _PyClassMethod_Type=Module["_PyClassMethod_Type"]=3209148;var _PyStaticMethod_Type=Module["_PyStaticMethod_Type"]=3209484;var __PyInterpreterID_Type=Module["__PyInterpreterID_Type"]=3209972;var _PySeqIter_Type=Module["_PySeqIter_Type"]=3210192;var _PyCallIter_Type=Module["_PyCallIter_Type"]=3210464;var _PyListIter_Type=Module["_PyListIter_Type"]=3211584;var _PyListRevIter_Type=Module["_PyListRevIter_Type"]=3211856;var _PyDictIterKey_Type=Module["_PyDictIterKey_Type"]=3214160;var _PyDictRevIterKey_Type=Module["_PyDictRevIterKey_Type"]=3214784;var _PyDictRevIterValue_Type=Module["_PyDictRevIterValue_Type"]=3215200;var _PyDictKeys_Type=Module["_PyDictKeys_Type"]=3215408;var _PyDictItems_Type=Module["_PyDictItems_Type"]=3215616;var _PyDictIterItem_Type=Module["_PyDictIterItem_Type"]=3214576;var _PyDictIterValue_Type=Module["_PyDictIterValue_Type"]=3214368;var _PyDictRevIterItem_Type=Module["_PyDictRevIterItem_Type"]=3214992;var _PyDictValues_Type=Module["_PyDictValues_Type"]=3216272;var _PyODict_Type=Module["_PyODict_Type"]=3216968;var _PyODictIter_Type=Module["_PyODictIter_Type"]=3217216;var _PyODictKeys_Type=Module["_PyODictKeys_Type"]=3217456;var _PyODictValues_Type=Module["_PyODictValues_Type"]=3217936;var _PyODictItems_Type=Module["_PyODictItems_Type"]=3217696;var __PyManagedBuffer_Type=Module["__PyManagedBuffer_Type"]=3218536;var _PyMemoryView_Type=Module["_PyMemoryView_Type"]=3219444;var _PyCMethod_Type=Module["_PyCMethod_Type"]=3220036;var _PyModuleDef_Type=Module["_PyModuleDef_Type"]=3220664;var __PyNamespace_Type=Module["__PyNamespace_Type"]=3221368;var __PyNone_Type=Module["__PyNone_Type"]=3221752;var __PyNotImplemented_Type=Module["__PyNotImplemented_Type"]=3222144;var _PyContextToken_Type=Module["_PyContextToken_Type"]=3244656;var _PyContextVar_Type=Module["_PyContextVar_Type"]=3244448;var _PyContext_Type=Module["_PyContext_Type"]=3244240;var _PyEllipsis_Type=Module["_PyEllipsis_Type"]=3226128;var _PyFilter_Type=Module["_PyFilter_Type"]=3241792;var _PyLongRangeIter_Type=Module["_PyLongRangeIter_Type"]=3224096;var _PyMap_Type=Module["_PyMap_Type"]=3242032;var _PyPickleBuffer_Type=Module["_PyPickleBuffer_Type"]=3222920;var _PyRangeIter_Type=Module["_PyRangeIter_Type"]=3223824;var _PyRange_Type=Module["_PyRange_Type"]=3223552;var _PySetIter_Type=Module["_PySetIter_Type"]=3224352;var _PySuper_Type=Module["_PySuper_Type"]=3229008;var _PyTupleIter_Type=Module["_PyTupleIter_Type"]=3227248;var _PyUnicodeIter_Type=Module["_PyUnicodeIter_Type"]=3236992;var _PyZip_Type=Module["_PyZip_Type"]=3242288;var __PyBufferWrapper_Type=Module["__PyBufferWrapper_Type"]=3228720;var __PyWeakref_CallableProxyType=Module["__PyWeakref_CallableProxyType"]=3239456;var __PyWeakref_ProxyType=Module["__PyWeakref_ProxyType"]=3239248;var __PyWeakref_RefType=Module["__PyWeakref_RefType"]=3238792;var __PySet_Dummy=Module["__PySet_Dummy"]=3225880;var _PyStructSequence_UnnamedField=Module["_PyStructSequence_UnnamedField"]=3226708;var __Py_ascii_whitespace=Module["__Py_ascii_whitespace"]=308928;var _Py_Version=Module["_Py_Version"]=441604;var _PyImport_Inittab=Module["_PyImport_Inittab"]=3247184;var __PyImport_FrozenBootstrap=Module["__PyImport_FrozenBootstrap"]=4423968;var _PyImport_FrozenModules=Module["_PyImport_FrozenModules"]=4594392;var __PyImport_FrozenStdlib=Module["__PyImport_FrozenStdlib"]=4424304;var __PyImport_FrozenTest=Module["__PyImport_FrozenTest"]=4424560;var _Py_IgnoreEnvironmentFlag=Module["_Py_IgnoreEnvironmentFlag"]=4584204;var _Py_IsolatedFlag=Module["_Py_IsolatedFlag"]=4584224;var _Py_BytesWarningFlag=Module["_Py_BytesWarningFlag"]=4584196;var _Py_InspectFlag=Module["_Py_InspectFlag"]=4584184;var _Py_InteractiveFlag=Module["_Py_InteractiveFlag"]=4584180;var _Py_OptimizeFlag=Module["_Py_OptimizeFlag"]=4584188;var _Py_DebugFlag=Module["_Py_DebugFlag"]=4584168;var _Py_VerboseFlag=Module["_Py_VerboseFlag"]=4584172;var _Py_QuietFlag=Module["_Py_QuietFlag"]=4584176;var _Py_FrozenFlag=Module["_Py_FrozenFlag"]=4584200;var _Py_UnbufferedStdioFlag=Module["_Py_UnbufferedStdioFlag"]=4584216;var _Py_NoSiteFlag=Module["_Py_NoSiteFlag"]=4584192;var _Py_DontWriteBytecodeFlag=Module["_Py_DontWriteBytecodeFlag"]=4584208;var _Py_NoUserSiteDirectory=Module["_Py_NoUserSiteDirectory"]=4584212;var _Py_HashRandomizationFlag=Module["_Py_HashRandomizationFlag"]=4584220;var _Py_FileSystemDefaultEncoding=Module["_Py_FileSystemDefaultEncoding"]=4584272;var _Py_HasFileSystemDefaultEncoding=Module["_Py_HasFileSystemDefaultEncoding"]=4584276;var _Py_FileSystemDefaultEncodeErrors=Module["_Py_FileSystemDefaultEncodeErrors"]=4584280;var __Py_HasFileSystemDefaultEncodeErrors=Module["__Py_HasFileSystemDefaultEncodeErrors"]=4584284;var _Py_UTF8Mode=Module["_Py_UTF8Mode"]=4584164;var __Py_HashSecret=Module["__Py_HashSecret"]=4584288;var _Py_EMSCRIPTEN_SIGNAL_HANDLING=Module["_Py_EMSCRIPTEN_SIGNAL_HANDLING"]=4585404;var __PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET=Module["__PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET"]=472392;var _ffi_type_pointer=Module["_ffi_type_pointer"]=2818868;var _ffi_type_void=Module["_ffi_type_void"]=2818760;var _ffi_type_sint32=Module["_ffi_type_sint32"]=2818832;var _ffi_type_uint8=Module["_ffi_type_uint8"]=2818772;var _ffi_type_double=Module["_ffi_type_double"]=2818892;var _ffi_type_longdouble=Module["_ffi_type_longdouble"]=2818904;var _ffi_type_float=Module["_ffi_type_float"]=2818880;var _ffi_type_sint16=Module["_ffi_type_sint16"]=2818808;var _ffi_type_uint16=Module["_ffi_type_uint16"]=2818796;var _ffi_type_uint32=Module["_ffi_type_uint32"]=2818820;var _ffi_type_sint64=Module["_ffi_type_sint64"]=2818856;var _ffi_type_uint64=Module["_ffi_type_uint64"]=2818844;var _ffi_type_sint8=Module["_ffi_type_sint8"]=2818784;var _environ=Module["_environ"]=4594416;var __deduplicate_map=Module["__deduplicate_map"]=4594396;var _z_errmsg=Module["_z_errmsg"]=4424864;var __length_code=Module["__length_code"]=2829520;var __dist_code=Module["__dist_code"]=2829008;var _deflate_copyright=Module["_deflate_copyright"]=2824176;var _inflate_copyright=Module["_inflate_copyright"]=2828704;var _BZ2_crc32Table=Module["_BZ2_crc32Table"]=4424976;var _BZ2_rNums=Module["_BZ2_rNums"]=4426e3;var ___environ=Module["___environ"]=4594416;var ____environ=Module["____environ"]=4594416;var __environ=Module["__environ"]=4594416;var _timezone=Module["_timezone"]=4595080;var _daylight=Module["_daylight"]=4595084;var _tzname=Module["_tzname"]=4595088;var ___progname=Module["___progname"]=4596304;var ___optreset=Module["___optreset"]=4595268;var _optind=Module["_optind"]=4428264;var ___optpos=Module["___optpos"]=4595272;var _optarg=Module["_optarg"]=4595276;var _optopt=Module["_optopt"]=4595280;var _opterr=Module["_opterr"]=4428268;var _optreset=Module["_optreset"]=4595268;var _h_errno=Module["_h_errno"]=4595404;var ___signgam=Module["___signgam"]=4610700;var __ns_flagdata=Module["__ns_flagdata"]=3016896;var ___progname_full=Module["___progname_full"]=4596308;var _program_invocation_short_name=Module["_program_invocation_short_name"]=4596304;var _program_invocation_name=Module["_program_invocation_name"]=4596308;var ___sig_pending=Module["___sig_pending"]=4600680;var ___sig_actions=Module["___sig_actions"]=4601600;var _signgam=Module["_signgam"]=4610700;var ___THREW__=Module["___THREW__"]=4617600;var ___threwValue=Module["___threwValue"]=4617604;var ___cxa_unexpected_handler=Module["___cxa_unexpected_handler"]=4439556;var ___cxa_terminate_handler=Module["___cxa_terminate_handler"]=4439552;var ___cxa_new_handler=Module["___cxa_new_handler"]=4640384;var _in6addr_any=Module["_in6addr_any"]=3171392;var _in6addr_loopback=Module["_in6addr_loopback"]=3171408;var ___start_em_js=Module["___start_em_js"]=4447048;var ___stop_em_js=Module["___stop_em_js"]=4581890;function invoke_iiii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iii(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_i(index){var sp=stackSave();try{return getWasmTableEntry(index)()}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_ii(index,a1){var sp=stackSave();try{return getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vi(index,a1){var sp=stackSave();try{getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiifi(index,a1,a2,a3,a4,a5){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiidi(index,a1,a2,a3,a4,a5){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiii(index,a1,a2,a3,a4){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_j(index){var sp=stackSave();try{return getWasmTableEntry(index)()}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_ji(index,a1){var sp=stackSave();try{return getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_vii(index,a1,a2){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_jii(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_v(index){var sp=stackSave();try{getWasmTableEntry(index)()}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viii(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viijii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiij(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiid(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiijj(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_jiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_iiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_fiii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_diii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiji(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_jiii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_viif(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viid(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viijj(index,a1,a2,a3,a4){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function applySignatureConversions(wasmExports){wasmExports=Object.assign({},wasmExports);var makeWrapper_pp=f=>a0=>f(a0)>>>0;var makeWrapper_pppp=f=>(a0,a1,a2)=>f(a0,a1,a2)>>>0;var makeWrapper_p=f=>()=>f()>>>0;var makeWrapper_ppp=f=>(a0,a1)=>f(a0,a1)>>>0;var makeWrapper_pP=f=>a0=>f(a0)>>>0;wasmExports["malloc"]=makeWrapper_pp(wasmExports["malloc"]);wasmExports["memcpy"]=makeWrapper_pppp(wasmExports["memcpy"]);wasmExports["__errno_location"]=makeWrapper_p(wasmExports["__errno_location"]);wasmExports["pthread_self"]=makeWrapper_p(wasmExports["pthread_self"]);wasmExports["emscripten_builtin_malloc"]=makeWrapper_pp(wasmExports["emscripten_builtin_malloc"]);wasmExports["emscripten_stack_get_base"]=makeWrapper_p(wasmExports["emscripten_stack_get_base"]);wasmExports["emscripten_stack_get_end"]=makeWrapper_p(wasmExports["emscripten_stack_get_end"]);wasmExports["emscripten_builtin_memalign"]=makeWrapper_ppp(wasmExports["emscripten_builtin_memalign"]);wasmExports["emscripten_stack_get_current"]=makeWrapper_p(wasmExports["emscripten_stack_get_current"]);wasmExports["emscripten_main_runtime_thread_id"]=makeWrapper_p(wasmExports["emscripten_main_runtime_thread_id"]);wasmExports["sbrk"]=makeWrapper_pP(wasmExports["sbrk"]);wasmExports["memalign"]=makeWrapper_ppp(wasmExports["memalign"]);wasmExports["_emscripten_stack_alloc"]=makeWrapper_pp(wasmExports["_emscripten_stack_alloc"]);return wasmExports}Module["addRunDependency"]=addRunDependency;Module["removeRunDependency"]=removeRunDependency;Module["FS_createPath"]=FS.createPath;Module["FS_createLazyFile"]=FS.createLazyFile;Module["FS_createDevice"]=FS.createDevice;Module["ERRNO_CODES"]=ERRNO_CODES;Module["wasmTable"]=wasmTable;Module["FS_createPreloadedFile"]=FS.createPreloadedFile;Module["FS_createDataFile"]=FS.createDataFile;Module["FS_unlink"]=FS.unlink;Module["LZ4"]=LZ4;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(args=[]){var entryFunction=resolveGlobalSymbol("main").sym;if(!entryFunction)return;args.unshift(thisProgram);var argc=args.length;var argv=stackAlloc((argc+1)*4);var argv_ptr=argv;args.forEach(arg=>{HEAPU32[argv_ptr>>>2>>>0]=stringToUTF8OnStack(arg);argv_ptr+=4});HEAPU32[argv_ptr>>>2>>>0]=0;try{var ret=entryFunction(argc,argv);exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(args=arguments_){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(shouldRunNow)callMain(args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;run();moduleRtn=readyPromise; - - - return moduleRtn; -} -); -})(); -globalThis._createPyodideModule = _createPyodideModule; diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.asm.wasm b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.asm.wasm deleted file mode 100755 index 9383f847fe..0000000000 Binary files a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.asm.wasm and /dev/null differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.d.ts b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.d.ts deleted file mode 100644 index 6a1987cf6a..0000000000 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.d.ts +++ /dev/null @@ -1,1642 +0,0 @@ -// Generated by dts-bundle-generator v8.1.2 - -/** - * - * The Pyodide version. - * - * The version here is a Python version, following :pep:`440`. This is different - * from the version in ``package.json`` which follows the node package manager - * version convention. - */ -export declare const version: string; -interface CanvasInterface { - setCanvas2D(canvas: HTMLCanvasElement): void; - getCanvas2D(): HTMLCanvasElement | undefined; - setCanvas3D(canvas: HTMLCanvasElement): void; - getCanvas3D(): HTMLCanvasElement | undefined; -} -type InFuncType = () => null | undefined | string | ArrayBuffer | Uint8Array | number; -declare function setStdin(options?: { - stdin?: InFuncType; - read?: (buffer: Uint8Array) => number; - error?: boolean; - isatty?: boolean; - autoEOF?: boolean; -}): void; -declare function setStdout(options?: { - batched?: (output: string) => void; - raw?: (charCode: number) => void; - write?: (buffer: Uint8Array) => number; - isatty?: boolean; -}): void; -declare function setStderr(options?: { - batched?: (output: string) => void; - raw?: (charCode: number) => void; - write?: (buffer: Uint8Array) => number; - isatty?: boolean; -}): void; -/** @deprecated Use `import type { TypedArray } from "pyodide/ffi"` instead */ -export type TypedArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array; -type FSNode = { - timestamp: number; - rdev: number; - contents: Uint8Array; - mode: number; -}; -type FSStream = { - tty?: { - ops: object; - }; - seekable?: boolean; - stream_ops: FSStreamOps; - node: FSNode; -}; -type FSStreamOps = FSStreamOpsGen; -type FSStreamOpsGen = { - open: (a: T) => void; - close: (a: T) => void; - fsync: (a: T) => void; - read: (a: T, b: Uint8Array, offset: number, length: number, pos: number) => number; - write: (a: T, b: Uint8Array, offset: number, length: number, pos: number) => number; -}; -interface FSType { - unlink: (path: string) => void; - mkdirTree: (path: string, mode?: number) => void; - chdir: (path: string) => void; - symlink: (target: string, src: string) => FSNode; - createDevice: ((parent: string, name: string, input?: (() => number | null) | null, output?: ((code: number) => void) | null) => FSNode) & { - major: number; - }; - closeStream: (fd: number) => void; - open: (path: string, flags: string | number, mode?: number) => FSStream; - makedev: (major: number, minor: number) => number; - mkdev: (path: string, dev: number) => FSNode; - filesystems: any; - stat: (path: string, dontFollow?: boolean) => any; - readdir: (path: string) => string[]; - isDir: (mode: number) => boolean; - isMountpoint: (mode: FSNode) => boolean; - lookupPath: (path: string, options?: { - follow_mount?: boolean; - }) => { - node: FSNode; - }; - isFile: (mode: number) => boolean; - writeFile: (path: string, contents: any, o?: { - canOwn?: boolean; - }) => void; - chmod: (path: string, mode: number) => void; - utime: (path: string, atime: number, mtime: number) => void; - rmdir: (path: string) => void; - mount: (type: any, opts: any, mountpoint: string) => any; - write: (stream: FSStream, buffer: any, offset: number, length: number, position?: number) => number; - close: (stream: FSStream) => void; - ErrnoError: { - new (errno: number): Error; - }; - registerDevice(dev: number, ops: FSStreamOpsGen): void; - syncfs(dir: boolean, oncomplete: (val: void) => void): void; - findObject(a: string, dontResolveLastLink?: boolean): any; - readFile(a: string): Uint8Array; -} -type PackageType = "package" | "cpython_module" | "shared_library" | "static_library"; -interface PackageData { - name: string; - version: string; - fileName: string; - /** @experimental */ - packageType: PackageType; -} -type LoadedPackages = Record; -/** @deprecated Use `import type { PyProxy } from "pyodide/ffi"` instead */ -interface PyProxy { - [x: string]: any; -} -declare class PyProxy { - /** @private */ - $$flags: number; - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; - /** - * @hideconstructor - */ - constructor(); - /** @hidden */ - get [Symbol.toStringTag](): string; - /** - * The name of the type of the object. - * - * Usually the value is ``"module.name"`` but for builtins or - * interpreter-defined types it is just ``"name"``. As pseudocode this is: - * - * .. code-block:: python - * - * ty = type(x) - * if ty.__module__ == 'builtins' or ty.__module__ == "__main__": - * return ty.__name__ - * else: - * ty.__module__ + "." + ty.__name__ - * - */ - get type(): string; - /** - * Returns `str(o)` (unless `pyproxyToStringRepr: true` was passed to - * :js:func:`~globalThis.loadPyodide` in which case it will return `repr(o)`) - */ - toString(): string; - /** - * Destroy the :js:class:`~pyodide.ffi.PyProxy`. This will release the memory. Any further attempt - * to use the object will raise an error. - * - * In a browser supporting :js:data:`FinalizationRegistry`, Pyodide will - * automatically destroy the :js:class:`~pyodide.ffi.PyProxy` when it is garbage collected, however - * there is no guarantee that the finalizer will be run in a timely manner so - * it is better to destroy the proxy explicitly. - * - * @param options - * @param options.message The error message to print if use is attempted after - * destroying. Defaults to "Object has already been destroyed". - * - */ - destroy(options?: { - message?: string; - destroyRoundtrip?: boolean; - }): void; - /** - * Make a new :js:class:`~pyodide.ffi.PyProxy` pointing to the same Python object. - * Useful if the :js:class:`~pyodide.ffi.PyProxy` is destroyed somewhere else. - */ - copy(): PyProxy; - /** - * Converts the :js:class:`~pyodide.ffi.PyProxy` into a JavaScript object as best as possible. By - * default does a deep conversion, if a shallow conversion is desired, you can - * use ``proxy.toJs({depth : 1})``. See :ref:`Explicit Conversion of PyProxy - * ` for more info. - * @param options - * @return The JavaScript object resulting from the conversion. - */ - toJs({ depth, pyproxies, create_pyproxies, dict_converter, default_converter, eager_converter, }?: { - /** How many layers deep to perform the conversion. Defaults to infinite */ - depth?: number; - /** - * If provided, :js:meth:`toJs` will store all PyProxies created in this - * list. This allows you to easily destroy all the PyProxies by iterating - * the list without having to recurse over the generated structure. The most - * common use case is to create a new empty list, pass the list as - * ``pyproxies``, and then later iterate over ``pyproxies`` to destroy all of - * created proxies. - */ - pyproxies?: PyProxy[]; - /** - * If false, :js:meth:`toJs` will throw a - * :py:exc:`~pyodide.ffi.ConversionError` rather than producing a - * :js:class:`~pyodide.ffi.PyProxy`. - */ - create_pyproxies?: boolean; - /** - * A function to be called on an iterable of pairs ``[key, value]``. Convert - * this iterable of pairs to the desired output. For instance, - * :js:func:`Object.fromEntries` would convert the dict to an object, - * :js:func:`Array.from` converts it to an :js:class:`Array` of pairs, and - * ``(it) => new Map(it)`` converts it to a :js:class:`Map` (which is the - * default behavior). - */ - dict_converter?: (array: Iterable<[ - key: string, - value: any - ]>) => any; - /** - * Optional argument to convert objects with no default conversion. See the - * documentation of :meth:`~pyodide.ffi.to_js`. - */ - default_converter?: (obj: PyProxy, convert: (obj: PyProxy) => any, cacheConversion: (obj: PyProxy, result: any) => void) => any; - /** - * Optional callback to convert objects which gets called after ``str``, - * ``int``, ``float``, ``bool``, ``None``, and ``JsProxy`` are converted but - * *before* any default conversions are applied to standard data structures. - * - * Its arguments are the same as `dict_converter`. - * See the documentation of :meth:`~pyodide.ffi.to_js`. - */ - eager_converter?: (obj: PyProxy, convert: (obj: PyProxy) => any, cacheConversion: (obj: PyProxy, result: any) => void) => any; - }): any; -} -declare class PyProxyWithLength extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -/** @deprecated Use `import type { PyProxyWithLength } from "pyodide/ffi"` instead */ -interface PyProxyWithLength extends PyLengthMethods { -} -declare class PyLengthMethods { - /** - * The length of the object. - */ - get length(): number; -} -declare class PyProxyWithGet extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -/** @deprecated Use `import type { PyProxyWithGet } from "pyodide/ffi"` instead */ -interface PyProxyWithGet extends PyGetItemMethods { -} -declare class PyGetItemMethods { - /** - * This translates to the Python code ``obj[key]``. - * - * @param key The key to look up. - * @returns The corresponding value. - */ - get(key: any): any; - /** - * Returns the object treated as a json adaptor. - * - * With a JsonAdaptor: - * 1. property access / modification / deletion is implemented with - * :meth:`~object.__getitem__`, :meth:`~object.__setitem__`, and - * :meth:`~object.__delitem__` respectively. - * 2. If an attribute is accessed and the result implements - * :meth:`~object.__getitem__` then the result will also be a json - * adaptor. - * - * For instance, ``JSON.stringify(proxy.asJsJson())`` acts like an - * inverse to Python's :py:func:`json.loads`. - */ - asJsJson(): PyProxy & {}; -} -declare class PyProxyWithSet extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -/** @deprecated Use `import type { PyProxyWithSet } from "pyodide/ffi"` instead */ -interface PyProxyWithSet extends PySetItemMethods { -} -declare class PySetItemMethods { - /** - * This translates to the Python code ``obj[key] = value``. - * - * @param key The key to set. - * @param value The value to set it to. - */ - set(key: any, value: any): void; - /** - * This translates to the Python code ``del obj[key]``. - * - * @param key The key to delete. - */ - delete(key: any): void; -} -declare class PyProxyWithHas extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -/** @deprecated Use `import type { PyProxyWithHas } from "pyodide/ffi"` instead */ -interface PyProxyWithHas extends PyContainsMethods { -} -declare class PyContainsMethods { - /** - * This translates to the Python code ``key in obj``. - * - * @param key The key to check for. - * @returns Is ``key`` present? - */ - has(key: any): boolean; -} -declare class PyIterable extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -/** @deprecated Use `import type { PyIterable } from "pyodide/ffi"` instead */ -interface PyIterable extends PyIterableMethods { -} -declare class PyIterableMethods { - /** - * This translates to the Python code ``iter(obj)``. Return an iterator - * associated to the proxy. See the documentation for - * :js:data:`Symbol.iterator`. - * - * This will be used implicitly by ``for(let x of proxy){}``. - */ - [Symbol.iterator](): Iterator; -} -declare class PyAsyncIterable extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -/** @deprecated Use `import type { PyAsyncIterable } from "pyodide/ffi"` instead */ -interface PyAsyncIterable extends PyAsyncIterableMethods { -} -declare class PyAsyncIterableMethods { - /** - * This translates to the Python code ``aiter(obj)``. Return an async iterator - * associated to the proxy. See the documentation for :js:data:`Symbol.asyncIterator`. - * - * This will be used implicitly by ``for(await let x of proxy){}``. - */ - [Symbol.asyncIterator](): AsyncIterator; -} -declare class PyIterator extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -/** @deprecated Use `import type { PyIterator } from "pyodide/ffi"` instead */ -interface PyIterator extends PyIteratorMethods { -} -declare class PyIteratorMethods { - /** @private */ - [Symbol.iterator](): this; - /** - * This translates to the Python code ``next(obj)``. Returns the next value of - * the generator. See the documentation for :js:meth:`Generator.next` The - * argument will be sent to the Python generator. - * - * This will be used implicitly by ``for(let x of proxy){}``. - * - * @param arg The value to send to the generator. The value will be assigned - * as a result of a yield expression. - * @returns An Object with two properties: ``done`` and ``value``. When the - * generator yields ``some_value``, ``next`` returns ``{done : false, value : - * some_value}``. When the generator raises a :py:exc:`StopIteration` - * exception, ``next`` returns ``{done : true, value : result_value}``. - */ - next(arg?: any): IteratorResult; -} -declare class PyGenerator extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -/** @deprecated Use `import type { PyGenerator } from "pyodide/ffi"` instead */ -interface PyGenerator extends PyGeneratorMethods { -} -declare class PyGeneratorMethods { - /** - * Throws an exception into the Generator. - * - * See the documentation for :js:meth:`Generator.throw`. - * - * @param exc Error The error to throw into the generator. Must be an - * instanceof ``Error``. - * @returns An Object with two properties: ``done`` and ``value``. When the - * generator yields ``some_value``, ``return`` returns ``{done : false, value - * : some_value}``. When the generator raises a - * ``StopIteration(result_value)`` exception, ``return`` returns ``{done : - * true, value : result_value}``. - */ - throw(exc: any): IteratorResult; - /** - * Throws a :py:exc:`GeneratorExit` into the generator and if the - * :py:exc:`GeneratorExit` is not caught returns the argument value ``{done: - * true, value: v}``. If the generator catches the :py:exc:`GeneratorExit` and - * returns or yields another value the next value of the generator this is - * returned in the normal way. If it throws some error other than - * :py:exc:`GeneratorExit` or :py:exc:`StopIteration`, that error is propagated. See - * the documentation for :js:meth:`Generator.return`. - * - * @param v The value to return from the generator. - * @returns An Object with two properties: ``done`` and ``value``. When the - * generator yields ``some_value``, ``return`` returns ``{done : false, value - * : some_value}``. When the generator raises a - * ``StopIteration(result_value)`` exception, ``return`` returns ``{done : - * true, value : result_value}``. - */ - return(v: any): IteratorResult; -} -declare class PyAsyncIterator extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -/** @deprecated Use `import type { PyAsyncIterator } from "pyodide/ffi"` instead */ -interface PyAsyncIterator extends PyAsyncIteratorMethods { -} -declare class PyAsyncIteratorMethods { - /** @private */ - [Symbol.asyncIterator](): this; - /** - * This translates to the Python code ``anext(obj)``. Returns the next value - * of the asynchronous iterator. The argument will be sent to the Python - * iterator (if it's a generator for instance). - * - * This will be used implicitly by ``for(let x of proxy){}``. - * - * @param arg The value to send to a generator. The value will be assigned as - * a result of a yield expression. - * @returns An Object with two properties: ``done`` and ``value``. When the - * iterator yields ``some_value``, ``next`` returns ``{done : false, value : - * some_value}``. When the giterator is done, ``next`` returns - * ``{done : true }``. - */ - next(arg?: any): Promise>; -} -declare class PyAsyncGenerator extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -/** @deprecated Use `import type { PyAsyncGenerator } from "pyodide/ffi"` instead */ -interface PyAsyncGenerator extends PyAsyncGeneratorMethods { -} -declare class PyAsyncGeneratorMethods { - /** - * Throws an exception into the Generator. - * - * See the documentation for :js:meth:`AsyncGenerator.throw`. - * - * @param exc Error The error to throw into the generator. Must be an - * instanceof ``Error``. - * @returns An Object with two properties: ``done`` and ``value``. When the - * generator yields ``some_value``, ``return`` returns ``{done : false, value - * : some_value}``. When the generator raises a - * ``StopIteration(result_value)`` exception, ``return`` returns ``{done : - * true, value : result_value}``. - */ - throw(exc: any): Promise>; - /** - * Throws a :py:exc:`GeneratorExit` into the generator and if the - * :py:exc:`GeneratorExit` is not caught returns the argument value ``{done: - * true, value: v}``. If the generator catches the :py:exc:`GeneratorExit` and - * returns or yields another value the next value of the generator this is - * returned in the normal way. If it throws some error other than - * :py:exc:`GeneratorExit` or :py:exc:`StopAsyncIteration`, that error is - * propagated. See the documentation for :js:meth:`AsyncGenerator.throw` - * - * @param v The value to return from the generator. - * @returns An Object with two properties: ``done`` and ``value``. When the - * generator yields ``some_value``, ``return`` returns ``{done : false, value - * : some_value}``. When the generator raises a :py:exc:`StopAsyncIteration` - * exception, ``return`` returns ``{done : true, value : result_value}``. - */ - return(v: any): Promise>; -} -declare class PySequence extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -/** @deprecated Use `import type { PySequence } from "pyodide/ffi"` instead */ -interface PySequence extends PySequenceMethods { -} -declare class PySequenceMethods { - /** @hidden */ - get [Symbol.isConcatSpreadable](): boolean; - /** - * See :js:meth:`Array.join`. The :js:meth:`Array.join` method creates and - * returns a new string by concatenating all of the elements in the - * :py:class:`~collections.abc.Sequence`. - * - * @param separator A string to separate each pair of adjacent elements of the - * Sequence. - * - * @returns A string with all Sequence elements joined. - */ - join(separator?: string): string; - /** - * See :js:meth:`Array.slice`. The :js:meth:`Array.slice` method returns a - * shallow copy of a portion of a :py:class:`~collections.abc.Sequence` into a - * new array object selected from ``start`` to ``stop`` (`stop` not included) - * @param start Zero-based index at which to start extraction. Negative index - * counts back from the end of the Sequence. - * @param stop Zero-based index at which to end extraction. Negative index - * counts back from the end of the Sequence. - * @returns A new array containing the extracted elements. - */ - slice(start?: number, stop?: number): any; - /** - * See :js:meth:`Array.lastIndexOf`. Returns the last index at which a given - * element can be found in the Sequence, or -1 if it is not present. - * @param elt Element to locate in the Sequence. - * @param fromIndex Zero-based index at which to start searching backwards, - * converted to an integer. Negative index counts back from the end of the - * Sequence. - * @returns The last index of the element in the Sequence; -1 if not found. - */ - lastIndexOf(elt: any, fromIndex?: number): number; - /** - * See :js:meth:`Array.indexOf`. Returns the first index at which a given - * element can be found in the Sequence, or -1 if it is not present. - * @param elt Element to locate in the Sequence. - * @param fromIndex Zero-based index at which to start searching, converted to - * an integer. Negative index counts back from the end of the Sequence. - * @returns The first index of the element in the Sequence; -1 if not found. - */ - indexOf(elt: any, fromIndex?: number): number; - /** - * See :js:meth:`Array.forEach`. Executes a provided function once for each - * ``Sequence`` element. - * @param callbackfn A function to execute for each element in the ``Sequence``. Its - * return value is discarded. - * @param thisArg A value to use as ``this`` when executing ``callbackFn``. - */ - forEach(callbackfn: (elt: any) => void, thisArg?: any): void; - /** - * See :js:meth:`Array.map`. Creates a new array populated with the results of - * calling a provided function on every element in the calling ``Sequence``. - * @param callbackfn A function to execute for each element in the ``Sequence``. Its - * return value is added as a single element in the new array. - * @param thisArg A value to use as ``this`` when executing ``callbackFn``. - */ - map(callbackfn: (elt: any, index: number, array: any) => U, thisArg?: any): U[]; - /** - * See :js:meth:`Array.filter`. Creates a shallow copy of a portion of a given - * ``Sequence``, filtered down to just the elements from the given array that pass - * the test implemented by the provided function. - * @param predicate A function to execute for each element in the array. It - * should return a truthy value to keep the element in the resulting array, - * and a falsy value otherwise. - * @param thisArg A value to use as ``this`` when executing ``predicate``. - */ - filter(predicate: (elt: any, index: number, array: any) => boolean, thisArg?: any): any[]; - /** - * See :js:meth:`Array.some`. Tests whether at least one element in the - * ``Sequence`` passes the test implemented by the provided function. - * @param predicate A function to execute for each element in the - * ``Sequence``. It should return a truthy value to indicate the element - * passes the test, and a falsy value otherwise. - * @param thisArg A value to use as ``this`` when executing ``predicate``. - */ - some(predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): boolean; - /** - * See :js:meth:`Array.every`. Tests whether every element in the ``Sequence`` - * passes the test implemented by the provided function. - * @param predicate A function to execute for each element in the - * ``Sequence``. It should return a truthy value to indicate the element - * passes the test, and a falsy value otherwise. - * @param thisArg A value to use as ``this`` when executing ``predicate``. - */ - every(predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): boolean; - /** - * See :js:meth:`Array.reduce`. Executes a user-supplied "reducer" callback - * function on each element of the Sequence, in order, passing in the return - * value from the calculation on the preceding element. The final result of - * running the reducer across all elements of the Sequence is a single value. - * @param callbackfn A function to execute for each element in the ``Sequence``. Its - * return value is discarded. - */ - reduce(callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any) => any, initialValue?: any): any; - /** - * See :js:meth:`Array.reduceRight`. Applies a function against an accumulator - * and each value of the Sequence (from right to left) to reduce it to a - * single value. - * @param callbackfn A function to execute for each element in the Sequence. - * Its return value is discarded. - */ - reduceRight(callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any) => any, initialValue: any): any; - /** - * See :js:meth:`Array.at`. Takes an integer value and returns the item at - * that index. - * @param index Zero-based index of the Sequence element to be returned, - * converted to an integer. Negative index counts back from the end of the - * Sequence. - * @returns The element in the Sequence matching the given index. - */ - at(index: number): any; - /** - * The :js:meth:`Array.concat` method is used to merge two or more arrays. - * This method does not change the existing arrays, but instead returns a new - * array. - * @param rest Arrays and/or values to concatenate into a new array. - * @returns A new Array instance. - */ - concat(...rest: ConcatArray[]): any[]; - /** - * The :js:meth:`Array.includes` method determines whether a Sequence - * includes a certain value among its entries, returning true or false as - * appropriate. - * @param elt - * @returns - */ - includes(elt: any): any; - /** - * The :js:meth:`Array.entries` method returns a new iterator object that - * contains the key/value pairs for each index in the ``Sequence``. - * @returns A new iterator object. - */ - entries(): IterableIterator<[ - number, - any - ]>; - /** - * The :js:meth:`Array.keys` method returns a new iterator object that - * contains the keys for each index in the ``Sequence``. - * @returns A new iterator object. - */ - keys(): IterableIterator; - /** - * The :js:meth:`Array.values` method returns a new iterator object that - * contains the values for each index in the ``Sequence``. - * @returns A new iterator object. - */ - values(): IterableIterator; - /** - * The :js:meth:`Array.find` method returns the first element in the provided - * array that satisfies the provided testing function. - * @param predicate A function to execute for each element in the - * ``Sequence``. It should return a truthy value to indicate a matching - * element has been found, and a falsy value otherwise. - * @param thisArg A value to use as ``this`` when executing ``predicate``. - * @returns The first element in the ``Sequence`` that satisfies the provided - * testing function. - */ - find(predicate: (value: any, index: number, obj: any[]) => any, thisArg?: any): any; - /** - * The :js:meth:`Array.findIndex` method returns the index of the first - * element in the provided array that satisfies the provided testing function. - * @param predicate A function to execute for each element in the - * ``Sequence``. It should return a truthy value to indicate a matching - * element has been found, and a falsy value otherwise. - * @param thisArg A value to use as ``this`` when executing ``predicate``. - * @returns The index of the first element in the ``Sequence`` that satisfies - * the provided testing function. - */ - findIndex(predicate: (value: any, index: number, obj: any[]) => any, thisArg?: any): number; - toJSON(this: any): unknown[]; - /** - * Returns the object treated as a json adaptor. - * - * With a JsonAdaptor: - * 1. property access / modification / deletion is implemented with - * :meth:`~object.__getitem__`, :meth:`~object.__setitem__`, and - * :meth:`~object.__delitem__` respectively. - * 2. If an attribute is accessed and the result implements - * :meth:`~object.__getitem__` then the result will also be a json - * adaptor. - * - * For instance, ``JSON.stringify(proxy.asJsJson())`` acts like an - * inverse to Python's :py:func:`json.loads`. - */ - asJsJson(): PyProxy & {}; -} -declare class PyMutableSequence extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -/** @deprecated Use `import type { PyMutableSequence } from "pyodide/ffi"` instead */ -interface PyMutableSequence extends PyMutableSequenceMethods { -} -declare class PyMutableSequenceMethods { - /** - * The :js:meth:`Array.reverse` method reverses a :js:class:`PyMutableSequence` in - * place. - * @returns A reference to the same :js:class:`PyMutableSequence` - */ - reverse(): PyMutableSequence; - /** - * The :js:meth:`Array.sort` method sorts the elements of a - * :js:class:`PyMutableSequence` in place. - * @param compareFn A function that defines the sort order. - * @returns A reference to the same :js:class:`PyMutableSequence` - */ - sort(compareFn?: (a: any, b: any) => number): PyMutableSequence; - /** - * The :js:meth:`Array.splice` method changes the contents of a - * :js:class:`PyMutableSequence` by removing or replacing existing elements and/or - * adding new elements in place. - * @param start Zero-based index at which to start changing the - * :js:class:`PyMutableSequence`. - * @param deleteCount An integer indicating the number of elements in the - * :js:class:`PyMutableSequence` to remove from ``start``. - * @param items The elements to add to the :js:class:`PyMutableSequence`, beginning from - * ``start``. - * @returns An array containing the deleted elements. - */ - splice(start: number, deleteCount?: number, ...items: any[]): any[]; - /** - * The :js:meth:`Array.push` method adds the specified elements to the end of - * a :js:class:`PyMutableSequence`. - * @param elts The element(s) to add to the end of the :js:class:`PyMutableSequence`. - * @returns The new length property of the object upon which the method was - * called. - */ - push(...elts: any[]): any; - /** - * The :js:meth:`Array.pop` method removes the last element from a - * :js:class:`PyMutableSequence`. - * @returns The removed element from the :js:class:`PyMutableSequence`; undefined if the - * :js:class:`PyMutableSequence` is empty. - */ - pop(): any; - /** - * The :js:meth:`Array.shift` method removes the first element from a - * :js:class:`PyMutableSequence`. - * @returns The removed element from the :js:class:`PyMutableSequence`; undefined if the - * :js:class:`PyMutableSequence` is empty. - */ - shift(): any; - /** - * The :js:meth:`Array.unshift` method adds the specified elements to the - * beginning of a :js:class:`PyMutableSequence`. - * @param elts The elements to add to the front of the :js:class:`PyMutableSequence`. - * @returns The new length of the :js:class:`PyMutableSequence`. - */ - unshift(...elts: any[]): any; - /** - * The :js:meth:`Array.copyWithin` method shallow copies part of a - * :js:class:`PyMutableSequence` to another location in the same :js:class:`PyMutableSequence` - * without modifying its length. - * @param target Zero-based index at which to copy the sequence to. - * @param start Zero-based index at which to start copying elements from. - * @param end Zero-based index at which to end copying elements from. - * @returns The modified :js:class:`PyMutableSequence`. - */ - copyWithin(target: number, start?: number, end?: number): any; - /** - * The :js:meth:`Array.fill` method changes all elements in an array to a - * static value, from a start index to an end index. - * @param value Value to fill the array with. - * @param start Zero-based index at which to start filling. Default 0. - * @param end Zero-based index at which to end filling. Default - * ``list.length``. - * @returns - */ - fill(value: any, start?: number, end?: number): any; -} -declare class PyAwaitable extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -/** @deprecated Use `import type { PyAwaitable } from "pyodide/ffi"` instead */ -interface PyAwaitable extends Promise { -} -declare class PyCallable extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyCallable; -} -/** @deprecated Use `import type { PyCallable } from "pyodide/ffi"` instead */ -interface PyCallable extends PyCallableMethods { - (...args: any[]): any; -} -declare class PyCallableMethods { - /** - * The ``apply()`` method calls the specified function with a given this - * value, and arguments provided as an array (or an array-like object). Like - * :js:meth:`Function.apply`. - * - * @param thisArg The ``this`` argument. Has no effect unless the - * :js:class:`~pyodide.ffi.PyCallable` has :js:meth:`captureThis` set. If - * :js:meth:`captureThis` is set, it will be passed as the first argument to - * the Python function. - * @param jsargs The array of arguments - * @returns The result from the function call. - */ - apply(thisArg: any, jsargs: any): any; - /** - * Calls the function with a given this value and arguments provided - * individually. See :js:meth:`Function.call`. - * - * @param thisArg The ``this`` argument. Has no effect unless the - * :js:class:`~pyodide.ffi.PyCallable` has :js:meth:`captureThis` set. If - * :js:meth:`captureThis` is set, it will be passed as the first argument to - * the Python function. - * @param jsargs The arguments - * @returns The result from the function call. - */ - call(thisArg: any, ...jsargs: any): any; - /** - * Call the Python function. The first parameter controls various parameters - * that change the way the call is performed. - * - * @param options - * @param options.kwargs If true, the last argument is treated as a collection - * of keyword arguments. - * @param options.promising If true, the call is made with stack switching - * enabled. Not needed if the callee is an async - * Python function. - * @param options.relaxed If true, extra arguments are ignored instead of - * raising a :py:exc:`TypeError`. - * @param jsargs Arguments to the Python function. - * @returns - */ - callWithOptions({ relaxed, kwargs, promising, }: { - relaxed?: boolean; - kwargs?: boolean; - promising?: boolean; - }, ...jsargs: any): any; - /** - * Call the function with keyword arguments. The last argument must be an - * object with the keyword arguments. - */ - callKwargs(...jsargs: any): any; - /** - * Call the function in a "relaxed" manner. Any extra arguments will be - * ignored. This matches the behavior of JavaScript functions more accurately. - * - * Any extra arguments will be ignored. This matches the behavior of - * JavaScript functions more accurately. Missing arguments are **NOT** filled - * with `None`. If too few arguments are passed, this will still raise a - * TypeError. - * - * This uses :py:func:`pyodide.code.relaxed_call`. - */ - callRelaxed(...jsargs: any): any; - /** - * Call the function with keyword arguments in a "relaxed" manner. The last - * argument must be an object with the keyword arguments. Any extra arguments - * will be ignored. This matches the behavior of JavaScript functions more - * accurately. - * - * Missing arguments are **NOT** filled with ``None``. If too few arguments are - * passed, this will still raise a :py:exc:`TypeError`. Also, if the same argument is - * passed as both a keyword argument and a positional argument, it will raise - * an error. - * - * This uses :py:func:`pyodide.code.relaxed_call`. - */ - callKwargsRelaxed(...jsargs: any): any; - /** - * Call the function with stack switching enabled. The last argument must be - * an object with the keyword arguments. Functions called this way can use - * :py:meth:`~pyodide.ffi.run_sync` to block until an - * :py:class:`~collections.abc.Awaitable` is resolved. Only works in runtimes - * with JS Promise integration. - * - * .. admonition:: Experimental - * :class: warning - * - * This feature is not yet stable. - * - * @experimental - */ - callPromising(...jsargs: any): Promise; - /** - * Call the function with stack switching enabled. The last argument must be - * an object with the keyword arguments. Functions called this way can use - * :py:meth:`~pyodide.ffi.run_sync` to block until an - * :py:class:`~collections.abc.Awaitable` is resolved. Only works in runtimes - * with JS Promise integration. - * - * .. admonition:: Experimental - * :class: warning - * - * This feature is not yet stable. - * - * @experimental - */ - callPromisingKwargs(...jsargs: any): Promise; - /** - * The ``bind()`` method creates a new function that, when called, has its - * ``this`` keyword set to the provided value, with a given sequence of - * arguments preceding any provided when the new function is called. See - * :js:meth:`Function.bind`. - * - * If the :js:class:`~pyodide.ffi.PyCallable` does not have - * :js:meth:`captureThis` set, the ``this`` parameter will be discarded. If it - * does have :js:meth:`captureThis` set, ``thisArg`` will be set to the first - * argument of the Python function. The returned proxy and the original proxy - * have the same lifetime so destroying either destroys both. - * - * @param thisArg The value to be passed as the ``this`` parameter to the - * target function ``func`` when the bound function is called. - * @param jsargs Extra arguments to prepend to arguments provided to the bound - * function when invoking ``func``. - * @returns - */ - bind(thisArg: any, ...jsargs: any): PyProxy; - /** - * Returns a :js:class:`~pyodide.ffi.PyProxy` that passes ``this`` as the first argument to the - * Python function. The returned :js:class:`~pyodide.ffi.PyProxy` has the internal ``captureThis`` - * property set. - * - * It can then be used as a method on a JavaScript object. The returned proxy - * and the original proxy have the same lifetime so destroying either destroys - * both. - * - * For example: - * - * .. code-block:: pyodide - * - * let obj = { a : 7 }; - * pyodide.runPython(` - * def f(self): - * return self.a - * `); - * // Without captureThis, it doesn't work to use f as a method for obj: - * obj.f = pyodide.globals.get("f"); - * obj.f(); // raises "TypeError: f() missing 1 required positional argument: 'self'" - * // With captureThis, it works fine: - * obj.f = pyodide.globals.get("f").captureThis(); - * obj.f(); // returns 7 - * - * @returns The resulting :js:class:`~pyodide.ffi.PyProxy`. It has the same lifetime as the - * original :js:class:`~pyodide.ffi.PyProxy` but passes ``this`` to the wrapped function. - * - */ - captureThis(): PyProxy; -} -declare class PyBuffer extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyBuffer; -} -/** @deprecated Use `import type { PyBuffer } from "pyodide/ffi"` instead */ -interface PyBuffer extends PyBufferMethods { -} -declare class PyBufferMethods { - /** - * Get a view of the buffer data which is usable from JavaScript. No copy is - * ever performed. - * - * We do not support suboffsets, if the buffer requires suboffsets we will - * throw an error. JavaScript nd array libraries can't handle suboffsets - * anyways. In this case, you should use the :js:meth:`~PyProxy.toJs` api or - * copy the buffer to one that doesn't use suboffsets (using e.g., - * :py:func:`numpy.ascontiguousarray`). - * - * If the buffer stores big endian data or half floats, this function will - * fail without an explicit type argument. For big endian data you can use - * :js:meth:`~PyProxy.toJs`. :js:class:`DataView` has support for big endian - * data, so you might want to pass ``'dataview'`` as the type argument in that - * case. - * - * @param type The type of the :js:attr:`~pyodide.ffi.PyBufferView.data` field - * in the output. Should be one of: ``"i8"``, ``"u8"``, ``"u8clamped"``, - * ``"i16"``, ``"u16"``, ``"i32"``, ``"u32"``, ``"i32"``, ``"u32"``, - * ``"i64"``, ``"u64"``, ``"f32"``, ``"f64"``, or ``"dataview"``. This argument - * is optional, if absent :js:meth:`~pyodide.ffi.PyBuffer.getBuffer` will try - * to determine the appropriate output type based on the buffer format string - * (see :std:ref:`struct-format-strings`). - */ - getBuffer(type?: string): PyBufferView; -} -declare class PyDict extends PyProxy { - /** @private */ - static [Symbol.hasInstance](obj: any): obj is PyProxy; -} -/** @deprecated Use `import type { PyDict } from "pyodide/ffi"` instead */ -interface PyDict extends PyProxyWithGet, PyProxyWithSet, PyProxyWithHas, PyProxyWithLength, PyIterable { -} -/** @deprecated Use `import type { PyBufferView } from "pyodide/ffi"` instead */ -declare class PyBufferView { - /** - * The offset of the first entry of the array. For instance if our array - * is 3d, then you will find ``array[0,0,0]`` at - * ``pybuf.data[pybuf.offset]`` - */ - offset: number; - /** - * If the data is read only, you should not modify it. There is no way for us - * to enforce this, but it may cause very weird behavior. See - * :py:attr:`memoryview.readonly`. - */ - readonly: boolean; - /** - * The format string for the buffer. See :ref:`struct-format-strings` - * and :py:attr:`memoryview.format`. - */ - format: string; - /** - * How large is each entry in bytes? See :py:attr:`memoryview.itemsize`. - */ - itemsize: number; - /** - * The number of dimensions of the buffer. If ``ndim`` is 0, the buffer - * represents a single scalar or struct. Otherwise, it represents an - * array. See :py:attr:`memoryview.ndim`. - */ - ndim: number; - /** - * The total number of bytes the buffer takes up. This is equal to - * :js:attr:`buff.data.byteLength `. See - * :py:attr:`memoryview.nbytes`. - */ - nbytes: number; - /** - * The shape of the buffer, that is how long it is in each dimension. - * The length will be equal to ``ndim``. For instance, a 2x3x4 array - * would have shape ``[2, 3, 4]``. See :py:attr:`memoryview.shape`. - */ - shape: number[]; - /** - * An array of of length ``ndim`` giving the number of elements to skip - * to get to a new element in each dimension. See the example definition - * of a ``multiIndexToIndex`` function above. See :py:attr:`memoryview.strides`. - */ - strides: number[]; - /** - * The actual data. A typed array of an appropriate size backed by a segment - * of the WASM memory. - * - * The ``type`` argument of :js:meth:`~pyodide.ffi.PyBuffer.getBuffer` determines - * which sort of :js:class:`TypedArray` or :js:class:`DataView` to return. By - * default :js:meth:`~pyodide.ffi.PyBuffer.getBuffer` will look at the format string - * to determine the most appropriate option. Most often the result is a - * :js:class:`Uint8Array`. - * - * .. admonition:: Contiguity - * :class: warning - * - * If the buffer is not contiguous, the :js:attr:`~PyBufferView.readonly` - * TypedArray will contain data that is not part of the buffer. Modifying - * this data leads to undefined behavior. - * - * .. admonition:: Read only buffers - * :class: warning - * - * If :js:attr:`buffer.readonly ` is ``true``, you - * should not modify the buffer. Modifying a read only buffer leads to - * undefined behavior. - * - */ - data: TypedArray; - /** - * Is it C contiguous? See :py:attr:`memoryview.c_contiguous`. - */ - c_contiguous: boolean; - /** - * Is it Fortran contiguous? See :py:attr:`memoryview.f_contiguous`. - */ - f_contiguous: boolean; - /** - * @private - */ - _released: boolean; - /** - * @private - */ - _view_ptr: number; - /** @private */ - constructor(); - /** - * Release the buffer. This allows the memory to be reclaimed. - */ - release(): void; -} -declare class PythonError extends Error { - /** - * The address of the error we are wrapping. We may later compare this - * against sys.last_exc. - * WARNING: we don't own a reference to this pointer, dereferencing it - * may be a use-after-free error! - * @private - */ - __error_address: number; - /** - * The name of the Python error class, e.g, :py:exc:`RuntimeError` or - * :py:exc:`KeyError`. - */ - type: string; - constructor(type: string, message: string, error_address: number); -} -type NativeFS = { - syncfs: () => Promise; -}; -declare class PyodideAPI { - /** @hidden */ - static version: string; - /** @hidden */ - static loadPackage: (names: string | PyProxy | Array, options?: { - messageCallback?: (message: string) => void; - errorCallback?: (message: string) => void; - checkIntegrity?: boolean; - }) => Promise>; - /** @hidden */ - static loadedPackages: LoadedPackages; - /** @hidden */ - static ffi: { - PyProxy: typeof PyProxy; - PyProxyWithLength: typeof PyProxyWithLength; - PyProxyWithGet: typeof PyProxyWithGet; - PyProxyWithSet: typeof PyProxyWithSet; - PyProxyWithHas: typeof PyProxyWithHas; - PyDict: typeof PyDict; - PyIterable: typeof PyIterable; - PyAsyncIterable: typeof PyAsyncIterable; - PyIterator: typeof PyIterator; - PyAsyncIterator: typeof PyAsyncIterator; - PyGenerator: typeof PyGenerator; - PyAsyncGenerator: typeof PyAsyncGenerator; - PyAwaitable: typeof PyAwaitable; - PyCallable: typeof PyCallable; - PyBuffer: typeof PyBuffer; - PyBufferView: typeof PyBufferView; - PythonError: typeof PythonError; - PySequence: typeof PySequence; - PyMutableSequence: typeof PyMutableSequence; - }; - /** @hidden */ - static setStdin: typeof setStdin; - /** @hidden */ - static setStdout: typeof setStdout; - /** @hidden */ - static setStderr: typeof setStderr; - /** - * - * An alias to the global Python namespace. - * - * For example, to access a variable called ``foo`` in the Python global - * scope, use ``pyodide.globals.get("foo")`` - */ - static globals: PyProxy; - /** - * An alias to the `Emscripten File System API - * `_. - * - * This provides a wide range of POSIX-`like` file/device operations, including - * `mount - * `_ - * which can be used to extend the in-memory filesystem with features like `persistence - * `_. - * - * While all the file systems implementations are enabled, only the default - * ``MEMFS`` is guaranteed to work in all runtime settings. The implementations - * are available as members of ``FS.filesystems``: - * ``IDBFS``, ``NODEFS``, ``PROXYFS``, ``WORKERFS``. - */ - static FS: FSType; - /** - * An alias to the `Emscripten Path API - * `_. - * - * This provides a variety of operations for working with file system paths, such as - * ``dirname``, ``normalize``, and ``splitPath``. - */ - static PATH: any; - /** - * APIs to set a canvas for rendering graphics. - * @summaryLink :ref:`canvas ` - * @omitFromAutoModule - */ - static canvas: CanvasInterface; - /** - * A map from posix error names to error codes. - */ - static ERRNO_CODES: { - [code: string]: number; - }; - /** - * An alias to the Python :ref:`pyodide ` package. - * - * You can use this to call functions defined in the Pyodide Python package - * from JavaScript. - */ - static pyodide_py: PyProxy; - /** - * Inspect a Python code chunk and use :js:func:`pyodide.loadPackage` to install - * any known packages that the code chunk imports. Uses the Python API - * :func:`pyodide.code.find\_imports` to inspect the code. - * - * For example, given the following code as input - * - * .. code-block:: python - * - * import numpy as np - * x = np.array([1, 2, 3]) - * - * :js:func:`loadPackagesFromImports` will call - * ``pyodide.loadPackage(['numpy'])``. - * - * @param code The code to inspect. - * @param options Options passed to :js:func:`pyodide.loadPackage`. - * @param options.messageCallback A callback, called with progress messages - * (optional) - * @param options.errorCallback A callback, called with error/warning messages - * (optional) - * @param options.checkIntegrity If true, check the integrity of the downloaded - * packages (default: true) - */ - static loadPackagesFromImports(code: string, options?: { - messageCallback?: (message: string) => void; - errorCallback?: (message: string) => void; - checkIntegrity?: boolean; - }): Promise>; - /** - * Runs a string of Python code from JavaScript, using :py:func:`~pyodide.code.eval_code` - * to evaluate the code. If the last statement in the Python code is an - * expression (and the code doesn't end with a semicolon), the value of the - * expression is returned. - * - * @param code The Python code to run - * @param options - * @param options.globals An optional Python dictionary to use as the globals. - * Defaults to :js:attr:`pyodide.globals`. - * @param options.locals An optional Python dictionary to use as the locals. - * Defaults to the same as ``globals``. - * @param options.filename An optional string to use as the file name. - * Defaults to ``""``. If a custom file name is given, the - * traceback for any exception that is thrown will show source lines - * (unless the given file name starts with ``<`` and ends with ``>``). - * @returns The result of the Python code translated to JavaScript. See the - * documentation for :py:func:`~pyodide.code.eval_code` for more info. - * @example - * async function main(){ - * const pyodide = await loadPyodide(); - * console.log(pyodide.runPython("1 + 2")); - * // 3 - * - * const globals = pyodide.toPy({ x: 3 }); - * console.log(pyodide.runPython("x + 1", { globals })); - * // 4 - * - * const locals = pyodide.toPy({ arr: [1, 2, 3] }); - * console.log(pyodide.runPython("sum(arr)", { locals })); - * // 6 - * } - * main(); - */ - static runPython(code: string, options?: { - globals?: PyProxy; - locals?: PyProxy; - filename?: string; - }): any; - /** - * Run a Python code string with top level await using - * :py:func:`~pyodide.code.eval_code_async` to evaluate the code. Returns a promise which - * resolves when execution completes. If the last statement in the Python code - * is an expression (and the code doesn't end with a semicolon), the returned - * promise will resolve to the value of this expression. - * - * For example: - * - * .. code-block:: pyodide - * - * let result = await pyodide.runPythonAsync(` - * from js import fetch - * response = await fetch("./pyodide-lock.json") - * packages = await response.json() - * # If final statement is an expression, its value is returned to JavaScript - * len(packages.packages.object_keys()) - * `); - * console.log(result); // 79 - * - * .. admonition:: Python imports - * :class: warning - * - * Since pyodide 0.18.0, you must call :js:func:`loadPackagesFromImports` to - * import any python packages referenced via ``import`` statements in your - * code. This function will no longer do it for you. - * - * @param code The Python code to run - * @param options - * @param options.globals An optional Python dictionary to use as the globals. - * Defaults to :js:attr:`pyodide.globals`. - * @param options.locals An optional Python dictionary to use as the locals. - * Defaults to the same as ``globals``. - * @param options.filename An optional string to use as the file name. - * Defaults to ``""``. If a custom file name is given, the - * traceback for any exception that is thrown will show source lines - * (unless the given file name starts with ``<`` and ends with ``>``). - * @returns The result of the Python code translated to JavaScript. - */ - static runPythonAsync(code: string, options?: { - globals?: PyProxy; - locals?: PyProxy; - filename?: string; - }): Promise; - /** - * Registers the JavaScript object ``module`` as a JavaScript module named - * ``name``. This module can then be imported from Python using the standard - * Python import system. If another module by the same name has already been - * imported, this won't have much effect unless you also delete the imported - * module from :py:data:`sys.modules`. This calls - * :func:`~pyodide.ffi.register_js_module`. - * - * Any attributes of the JavaScript objects which are themselves objects will - * be treated as submodules: - * ```pyodide - * pyodide.registerJsModule("mymodule", { submodule: { value: 7 } }); - * pyodide.runPython(` - * from mymodule.submodule import value - * assert value == 7 - * `); - * ``` - * If you wish to prevent this, try the following instead: - * ```pyodide - * const sys = pyodide.pyimport("sys"); - * sys.modules.set("mymodule", { obj: { value: 7 } }); - * pyodide.runPython(` - * from mymodule import obj - * assert obj.value == 7 - * # attempting to treat obj as a submodule raises ModuleNotFoundError: - * # "No module named 'mymodule.obj'; 'mymodule' is not a package" - * from mymodule.obj import value - * `); - * ``` - * - * @param name Name of the JavaScript module to add - * @param module JavaScript object backing the module - */ - static registerJsModule(name: string, module: object): void; - /** - * Unregisters a JavaScript module with given name that has been previously - * registered with :js:func:`pyodide.registerJsModule` or - * :func:`~pyodide.ffi.register_js_module`. If a JavaScript module with that - * name does not already exist, will throw an error. Note that if the module has - * already been imported, this won't have much effect unless you also delete the - * imported module from :py:data:`sys.modules`. This calls - * :func:`~pyodide.ffi.unregister_js_module`. - * - * @param name Name of the JavaScript module to remove - */ - static unregisterJsModule(name: string): void; - /** - * Convert a JavaScript object to a Python object as best as possible. - * - * This is similar to :py:meth:`~pyodide.ffi.JsProxy.to_py` but for use from - * JavaScript. If the object is immutable or a :js:class:`~pyodide.ffi.PyProxy`, - * it will be returned unchanged. If the object cannot be converted into Python, - * it will be returned unchanged. - * - * See :ref:`type-translations-jsproxy-to-py` for more information. - * - * @param obj The object to convert. - * @param options - * @returns The object converted to Python. - */ - static toPy(obj: any, { depth, defaultConverter, }?: { - /** - * Optional argument to limit the depth of the conversion. - */ - depth: number; - /** - * Optional argument to convert objects with no default conversion. See the - * documentation of :py:meth:`~pyodide.ffi.JsProxy.to_py`. - */ - defaultConverter?: (value: any, converter: (value: any) => any, cacheConversion: (input: any, output: any) => void) => any; - }): any; - /** - * Imports a module and returns it. - * - * If `name` has no dot in it, then `pyimport(name)` is approximately - * equivalent to: - * ```js - * pyodide.runPython(`import ${name}; ${name}`) - * ``` - * except that `name` is not introduced into the Python global namespace. If - * the name has one or more dots in it, say it is of the form `path.name` - * where `name` has no dots but path may have zero or more dots. Then it is - * approximately the same as: - * ```js - * pyodide.runPython(`from ${path} import ${name}; ${name}`); - * ``` - * - * @param mod_name The name of the module to import - * - * @example - * pyodide.pyimport("math.comb")(4, 2) // returns 4 choose 2 = 6 - */ - static pyimport(mod_name: string): any; - /** - * Unpack an archive into a target directory. - * - * @param buffer The archive as an :js:class:`ArrayBuffer` or :js:class:`TypedArray`. - * @param format The format of the archive. Should be one of the formats - * recognized by :py:func:`shutil.unpack_archive`. By default the options are - * ``'bztar'``, ``'gztar'``, ``'tar'``, ``'zip'``, and ``'wheel'``. Several - * synonyms are accepted for each format, e.g., for ``'gztar'`` any of - * ``'.gztar'``, ``'.tar.gz'``, ``'.tgz'``, ``'tar.gz'`` or ``'tgz'`` are - * considered to be - * synonyms. - * - * @param options - * @param options.extractDir The directory to unpack the archive into. Defaults - * to the working directory. - */ - static unpackArchive(buffer: TypedArray | ArrayBuffer, format: string, options?: { - extractDir?: string; - }): void; - /** - * Mounts a :js:class:`FileSystemDirectoryHandle` into the target directory. - * Currently it's only possible to acquire a - * :js:class:`FileSystemDirectoryHandle` in Chrome. - * - * @param path The absolute path in the Emscripten file system to mount the - * native directory. If the directory does not exist, it will be created. If - * it does exist, it must be empty. - * @param fileSystemHandle A handle returned by - * :js:func:`navigator.storage.getDirectory() ` or - * :js:func:`window.showDirectoryPicker() `. - */ - static mountNativeFS(path: string, fileSystemHandle: FileSystemDirectoryHandle): Promise; - /** - * Mounts a host directory into Pyodide file system. Only works in node. - * - * @param emscriptenPath The absolute path in the Emscripten file system to - * mount the native directory. If the directory does not exist, it will be - * created. If it does exist, it must be empty. - * @param hostPath The host path to mount. It must be a directory that exists. - */ - static mountNodeFS(emscriptenPath: string, hostPath: string): void; - /** - * Tell Pyodide about Comlink. - * Necessary to enable importing Comlink proxies into Python. - */ - static registerComlink(Comlink: any): void; - /** - * Sets the interrupt buffer to be ``interrupt_buffer``. This is only useful - * when Pyodide is used in a webworker. The buffer should be a - * :js:class:`SharedArrayBuffer` shared with the main browser thread (or another - * worker). In that case, signal ``signum`` may be sent by writing ``signum`` - * into the interrupt buffer. If ``signum`` does not satisfy 0 < ``signum`` < 65 - * it will be silently ignored. - * - * You can disable interrupts by calling ``setInterruptBuffer(undefined)``. - * - * If you wish to trigger a :py:exc:`KeyboardInterrupt`, write ``SIGINT`` (a 2) - * into the interrupt buffer. - * - * By default ``SIGINT`` raises a :py:exc:`KeyboardInterrupt` and all other signals - * are ignored. You can install custom signal handlers with the signal module. - * Even signals that normally have special meaning and can't be overridden like - * ``SIGKILL`` and ``SIGSEGV`` are ignored by default and can be used for any - * purpose you like. - */ - static setInterruptBuffer(interrupt_buffer: TypedArray): void; - /** - * Throws a :py:exc:`KeyboardInterrupt` error if a :py:exc:`KeyboardInterrupt` has - * been requested via the interrupt buffer. - * - * This can be used to enable keyboard interrupts during execution of JavaScript - * code, just as :c:func:`PyErr_CheckSignals` is used to enable keyboard interrupts - * during execution of C code. - */ - static checkInterrupt(): void; - /** - * Turn on or off debug mode. In debug mode, some error messages are improved - * at a performance cost. - * @param debug If true, turn debug mode on. If false, turn debug mode off. - * @returns The old value of the debug flag. - */ - static setDebug(debug: boolean): boolean; - /** - * - * @param param0 - * @returns - */ - static makeMemorySnapshot({ serializer, }?: { - serializer?: (obj: any) => any; - }): Uint8Array; -} -/** @hidden */ -export type PyodideInterface = typeof PyodideAPI; -/** - * See documentation for loadPyodide. - * @hidden - */ -type ConfigType = { - indexURL: string; - packageCacheDir: string; - lockFileURL: string; - fullStdLib?: boolean; - stdLibURL?: string; - stdin?: () => string; - stdout?: (msg: string) => void; - stderr?: (msg: string) => void; - jsglobals?: object; - _sysExecutable?: string; - args: string[]; - fsInit?: (FS: FSType, info: { - sitePackages: string; - }) => Promise; - env: { - [key: string]: string; - }; - packages: string[]; - _makeSnapshot: boolean; - enableRunUntilComplete: boolean; - checkAPIVersion: boolean; - BUILD_ID: string; -}; -/** - * Load the main Pyodide wasm module and initialize it. - * - * @returns The :ref:`js-api-pyodide` module. - * @example - * async function main() { - * const pyodide = await loadPyodide({ - * fullStdLib: true, - * stdout: (msg) => console.log(`Pyodide: ${msg}`), - * }); - * console.log("Loaded Pyodide"); - * } - * main(); - */ -export declare function loadPyodide(options?: { - /** - * The URL from which Pyodide will load the main Pyodide runtime and - * packages. It is recommended that you leave this unchanged, providing an - * incorrect value can cause broken behavior. - * - * Default: The url that Pyodide is loaded from with the file name - * (``pyodide.js`` or ``pyodide.mjs``) removed. - */ - indexURL?: string; - /** - * The file path where packages will be cached in node. If a package - * exists in ``packageCacheDir`` it is loaded from there, otherwise it is - * downloaded from the JsDelivr CDN and then cached into ``packageCacheDir``. - * Only applies when running in node; ignored in browsers. - * - * Default: same as indexURL - */ - packageCacheDir?: string; - /** - * The URL from which Pyodide will load the Pyodide ``pyodide-lock.json`` lock - * file. You can produce custom lock files with :py:func:`micropip.freeze`. - * Default: ```${indexURL}/pyodide-lock.json``` - */ - lockFileURL?: string; - /** - * Load the full Python standard library. Setting this to false excludes - * unvendored modules from the standard library. - * Default: ``false`` - */ - fullStdLib?: boolean; - /** - * The URL from which to load the standard library ``python_stdlib.zip`` - * file. This URL includes the most of the Python standard library. Some - * stdlib modules were unvendored, and can be loaded separately - * with ``fullStdLib: true`` option or by their package name. - * Default: ```${indexURL}/python_stdlib.zip``` - */ - stdLibURL?: string; - /** - * Override the standard input callback. Should ask the user for one line of - * input. The :js:func:`pyodide.setStdin` function is more flexible and - * should be preferred. - */ - stdin?: () => string; - /** - * Override the standard output callback. The :js:func:`pyodide.setStdout` - * function is more flexible and should be preferred in most cases, but - * depending on the ``args`` passed to ``loadPyodide``, Pyodide may write to - * stdout on startup, which can only be controlled by passing a custom - * ``stdout`` function. - */ - stdout?: (msg: string) => void; - /** - * Override the standard error output callback. The - * :js:func:`pyodide.setStderr` function is more flexible and should be - * preferred in most cases, but depending on the ``args`` passed to - * ``loadPyodide``, Pyodide may write to stdout on startup, which can only - * be controlled by passing a custom ``stdout`` function. - */ - stderr?: (msg: string) => void; - /** - * The object that Pyodide will use for the ``js`` module. - * Default: ``globalThis`` - */ - jsglobals?: object; - /** - * Determine the value of ``sys.executable``. - * @ignore - */ - _sysExecutable?: string; - /** - * Command line arguments to pass to Python on startup. See `Python command - * line interface options - * `_ for - * more details. Default: ``[]`` - */ - args?: string[]; - /** - * Environment variables to pass to Python. This can be accessed inside of - * Python at runtime via :py:data:`os.environ`. Certain environment variables change - * the way that Python loads: - * https://docs.python.org/3.10/using/cmdline.html#environment-variables - * Default: ``{}``. - * If ``env.HOME`` is undefined, it will be set to a default value of - * ``"/home/pyodide"`` - */ - env?: { - [key: string]: string; - }; - /** - * A list of packages to load as Pyodide is initializing. - * - * This is the same as loading the packages with - * :js:func:`pyodide.loadPackage` after Pyodide is loaded except using the - * ``packages`` option is more efficient because the packages are downloaded - * while Pyodide bootstraps itself. - */ - packages?: string[]; - /** - * Opt into the old behavior where :js:func:`PyProxy.toString() ` - * calls :py:func:`repr` and not :py:class:`str() `. - * @deprecated - */ - pyproxyToStringRepr?: boolean; - /** - * Make loop.run_until_complete() function correctly using stack switching. - * Default: ``true``. - */ - enableRunUntilComplete?: boolean; - /** - * If true (default), throw an error if the version of Pyodide core does not - * match the version of the Pyodide js package. - */ - checkAPIVersion?: boolean; - /** - * This is a hook that allows modification of the file system before the - * main() function is called and the intereter is started. When this is - * called, it is guaranteed that there is an empty site-packages directory. - * @experimental - */ - fsInit?: (FS: FSType, info: { - sitePackages: string; - }) => Promise; - /** @ignore */ - _makeSnapshot?: boolean; - /** @ignore */ - _loadSnapshot?: Uint8Array | ArrayBuffer | PromiseLike; - /** @ignore */ - _snapshotDeserializer?: (obj: any) => any; -}): Promise; - -export type {}; -export type {PackageData}; diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.js b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.js deleted file mode 100644 index 7961d07a29..0000000000 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.js +++ /dev/null @@ -1,6 +0,0 @@ -"use strict";var loadPyodide=(()=>{var ne=Object.create;var F=Object.defineProperty;var re=Object.getOwnPropertyDescriptor;var ie=Object.getOwnPropertyNames;var oe=Object.getPrototypeOf,ae=Object.prototype.hasOwnProperty;var s=(e,t)=>F(e,"name",{value:t,configurable:!0}),p=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,i)=>(typeof require<"u"?require:t)[i]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+e+'" is not supported')});var se=(e,t)=>{for(var i in t)F(e,i,{get:t[i],enumerable:!0})},$=(e,t,i,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of ie(t))!ae.call(e,a)&&a!==i&&F(e,a,{get:()=>t[a],enumerable:!(r=re(t,a))||r.enumerable});return e};var b=(e,t,i)=>(i=e!=null?ne(oe(e)):{},$(t||!e||!e.__esModule?F(i,"default",{value:e,enumerable:!0}):i,e)),ce=e=>$(F({},"__esModule",{value:!0}),e);var Fe={};se(Fe,{loadPyodide:()=>B,version:()=>x});function le(e){return!isNaN(parseFloat(e))&&isFinite(e)}s(le,"_isNumber");function w(e){return e.charAt(0).toUpperCase()+e.substring(1)}s(w,"_capitalize");function L(e){return function(){return this[e]}}s(L,"_getter");var _=["isConstructor","isEval","isNative","isToplevel"],I=["columnNumber","lineNumber"],P=["fileName","functionName","source"],de=["args"],ue=["evalOrigin"],O=_.concat(I,P,de,ue);function g(e){if(e)for(var t=0;t-1&&(n=n.replace(/eval code/g,"eval").replace(/(\(eval at [^()]*)|(,.*$)/g,""));var o=n.replace(/^\s+/,"").replace(/\(eval code/g,"(").replace(/^.*?\s+/,""),c=o.match(/ (\(.+\)$)/);o=c?o.replace(c[0],""):o;var l=this.extractLocation(c?c[1]:o),d=c&&o||void 0,u=["eval",""].indexOf(l[0])>-1?void 0:l[0];return new A({functionName:d,fileName:u,lineNumber:l[1],columnNumber:l[2],source:n})},this)},"ErrorStackParser$$parseV8OrIE"),parseFFOrSafari:s(function(r){var a=r.stack.split(` -`).filter(function(n){return!n.match(t)},this);return a.map(function(n){if(n.indexOf(" > eval")>-1&&(n=n.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,":$1")),n.indexOf("@")===-1&&n.indexOf(":")===-1)return new A({functionName:n});var o=/((.*".+"[^@]*)?[^@]*)(?:@)/,c=n.match(o),l=c&&c[1]?c[1]:void 0,d=this.extractLocation(n.replace(o,""));return new A({functionName:l,fileName:d[0],lineNumber:d[1],columnNumber:d[2],source:n})},this)},"ErrorStackParser$$parseFFOrSafari")}}s(fe,"ErrorStackParser");var me=new fe;var j=me;var y=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string"&&!process.browser,T=y&&typeof module<"u"&&typeof module.exports<"u"&&typeof p<"u"&&typeof __dirname<"u",H=y&&!T,Le=typeof globalThis.Bun<"u",pe=typeof Deno<"u",z=!y&&!pe,V=z&&typeof window=="object"&&typeof document=="object"&&typeof document.createElement=="function"&&"sessionStorage"in window&&typeof importScripts!="function",q=z&&typeof importScripts=="function"&&typeof self=="object",Te=typeof navigator=="object"&&typeof navigator.userAgent=="string"&&navigator.userAgent.indexOf("Chrome")==-1&&navigator.userAgent.indexOf("Safari")>-1;var K,U,Y,J,C;async function M(){if(!y||(K=(await import(/* webpackIgnore */"node:url")).default,J=await import(/* webpackIgnore */"node:fs"),C=await import(/* webpackIgnore */"node:fs/promises"),Y=(await import(/* webpackIgnore */"node:vm")).default,U=await import(/* webpackIgnore */"node:path"),W=U.sep,typeof p<"u"))return;let e=J,t=await import(/* webpackIgnore */"node:crypto"),i=await import(/* webpackIgnore */"ws"),r=await import(/* webpackIgnore */"node:child_process"),a={fs:e,crypto:t,ws:i,child_process:r};globalThis.require=function(n){return a[n]}}s(M,"initNodeModules");function ge(e,t){return U.resolve(t||".",e)}s(ge,"node_resolvePath");function ye(e,t){return t===void 0&&(t=location),new URL(e,t).toString()}s(ye,"browser_resolvePath");var D;y?D=ge:D=ye;var W;y||(W="/");function be(e,t){return e.startsWith("file://")&&(e=e.slice(7)),e.includes("://")?{response:fetch(e)}:{binary:C.readFile(e).then(i=>new Uint8Array(i.buffer,i.byteOffset,i.byteLength))}}s(be,"node_getBinaryResponse");function ve(e,t){let i=new URL(e,location);return{response:fetch(i,t?{integrity:t}:{})}}s(ve,"browser_getBinaryResponse");var k;y?k=be:k=ve;async function G(e,t){let{response:i,binary:r}=k(e,t);if(r)return r;let a=await i;if(!a.ok)throw new Error(`Failed to load '${e}': request failed.`);return new Uint8Array(await a.arrayBuffer())}s(G,"loadBinaryFile");var R;if(V)R=s(async e=>await import(/* webpackIgnore */e),"loadScript");else if(q)R=s(async e=>{try{globalThis.importScripts(e)}catch(t){if(t instanceof TypeError)await import(/* webpackIgnore */e);else throw t}},"loadScript");else if(y)R=he;else throw new Error("Cannot determine runtime environment");async function he(e){e.startsWith("file://")&&(e=e.slice(7)),e.includes("://")?Y.runInThisContext(await(await fetch(e)).text()):await import(/* webpackIgnore */K.pathToFileURL(e).href)}s(he,"nodeLoadScript");async function X(e){if(y){await M();let t=await C.readFile(e,{encoding:"utf8"});return JSON.parse(t)}else return await(await fetch(e)).json()}s(X,"loadLockFile");async function Q(){if(T)return __dirname;let e;try{throw new Error}catch(r){e=r}let t=j.parse(e)[0].fileName;if(y&&!t.startsWith("file://")&&(t=`file://${t}`),H){let r=await import(/* webpackIgnore */"node:path");return(await import(/* webpackIgnore */"node:url")).fileURLToPath(r.dirname(t))}let i=t.lastIndexOf(W);if(i===-1)throw new Error("Could not extract indexURL path from pyodide module location");return t.slice(0,i)}s(Q,"calculateDirname");function Z(e){let t=e.FS,i=e.FS.filesystems.MEMFS,r=e.PATH,a={DIR_MODE:16895,FILE_MODE:33279,mount:function(n){if(!n.opts.fileSystemHandle)throw new Error("opts.fileSystemHandle is required");return i.mount.apply(null,arguments)},syncfs:async(n,o,c)=>{try{let l=a.getLocalSet(n),d=await a.getRemoteSet(n),u=o?d:l,m=o?l:d;await a.reconcile(n,u,m),c(null)}catch(l){c(l)}},getLocalSet:n=>{let o=Object.create(null);function c(u){return u!=="."&&u!==".."}s(c,"isRealDir");function l(u){return m=>r.join2(u,m)}s(l,"toAbsolute");let d=t.readdir(n.mountpoint).filter(c).map(l(n.mountpoint));for(;d.length;){let u=d.pop(),m=t.stat(u);t.isDir(m.mode)&&d.push.apply(d,t.readdir(u).filter(c).map(l(u))),o[u]={timestamp:m.mtime,mode:m.mode}}return{type:"local",entries:o}},getRemoteSet:async n=>{let o=Object.create(null),c=await Ee(n.opts.fileSystemHandle);for(let[l,d]of c)l!=="."&&(o[r.join2(n.mountpoint,l)]={timestamp:d.kind==="file"?new Date((await d.getFile()).lastModified):new Date,mode:d.kind==="file"?a.FILE_MODE:a.DIR_MODE});return{type:"remote",entries:o,handles:c}},loadLocalEntry:n=>{let c=t.lookupPath(n).node,l=t.stat(n);if(t.isDir(l.mode))return{timestamp:l.mtime,mode:l.mode};if(t.isFile(l.mode))return c.contents=i.getFileDataAsTypedArray(c),{timestamp:l.mtime,mode:l.mode,contents:c.contents};throw new Error("node type not supported")},storeLocalEntry:(n,o)=>{if(t.isDir(o.mode))t.mkdirTree(n,o.mode);else if(t.isFile(o.mode))t.writeFile(n,o.contents,{canOwn:!0});else throw new Error("node type not supported");t.chmod(n,o.mode),t.utime(n,o.timestamp,o.timestamp)},removeLocalEntry:n=>{var o=t.stat(n);t.isDir(o.mode)?t.rmdir(n):t.isFile(o.mode)&&t.unlink(n)},loadRemoteEntry:async n=>{if(n.kind==="file"){let o=await n.getFile();return{contents:new Uint8Array(await o.arrayBuffer()),mode:a.FILE_MODE,timestamp:new Date(o.lastModified)}}else{if(n.kind==="directory")return{mode:a.DIR_MODE,timestamp:new Date};throw new Error("unknown kind: "+n.kind)}},storeRemoteEntry:async(n,o,c)=>{let l=n.get(r.dirname(o)),d=t.isFile(c.mode)?await l.getFileHandle(r.basename(o),{create:!0}):await l.getDirectoryHandle(r.basename(o),{create:!0});if(d.kind==="file"){let u=await d.createWritable();await u.write(c.contents),await u.close()}n.set(o,d)},removeRemoteEntry:async(n,o)=>{await n.get(r.dirname(o)).removeEntry(r.basename(o)),n.delete(o)},reconcile:async(n,o,c)=>{let l=0,d=[];Object.keys(o.entries).forEach(function(f){let v=o.entries[f],N=c.entries[f];(!N||t.isFile(v.mode)&&v.timestamp.getTime()>N.timestamp.getTime())&&(d.push(f),l++)}),d.sort();let u=[];if(Object.keys(c.entries).forEach(function(f){o.entries[f]||(u.push(f),l++)}),u.sort().reverse(),!l)return;let m=o.type==="remote"?o.handles:c.handles;for(let f of d){let v=r.normalize(f.replace(n.mountpoint,"/")).substring(1);if(c.type==="local"){let N=m.get(v),te=await a.loadRemoteEntry(N);a.storeLocalEntry(f,te)}else{let N=a.loadLocalEntry(f);await a.storeRemoteEntry(m,v,N)}}for(let f of u)if(c.type==="local")a.removeLocalEntry(f);else{let v=r.normalize(f.replace(n.mountpoint,"/")).substring(1);await a.removeRemoteEntry(m,v)}}};e.FS.filesystems.NATIVEFS_ASYNC=a}s(Z,"initializeNativeFS");var Ee=s(async e=>{let t=[];async function i(a){for await(let n of a.values())t.push(n),n.kind==="directory"&&await i(n)}s(i,"collect"),await i(e);let r=new Map;r.set(".",e);for(let a of t){let n=(await e.resolve(a)).join("/");r.set(n,a)}return r},"getFsHandles");function ee(e){let t={noImageDecoding:!0,noAudioDecoding:!0,noWasmDecoding:!1,preRun:Ie(e),quit(i,r){throw t.exited={status:i,toThrow:r},r},print:e.stdout,printErr:e.stderr,thisProgram:e._sysExecutable,arguments:e.args,API:{config:e},locateFile:i=>e.indexURL+i,instantiateWasm:Pe(e.indexURL)};return t}s(ee,"createSettings");function Se(e){return function(t){let i="/";try{t.FS.mkdirTree(e)}catch(r){console.error(`Error occurred while making a home directory '${e}':`),console.error(r),console.error(`Using '${i}' for a home directory instead`),e=i}t.FS.chdir(e)}}s(Se,"createHomeDirectory");function we(e){return function(t){Object.assign(t.ENV,e)}}s(we,"setEnvironment");function Ne(e){return e?[async t=>{t.addRunDependency("fsInitHook");try{await e(t.FS,{sitePackages:t.API.sitePackages})}finally{t.removeRunDependency("fsInitHook")}}]:[]}s(Ne,"callFsInitHook");function _e(e){let t=G(e);return async i=>{let r=i._py_version_major(),a=i._py_version_minor();i.FS.mkdirTree("/lib"),i.API.sitePackages=`/lib/python${r}.${a}/site-packages`,i.FS.mkdirTree(i.API.sitePackages),i.addRunDependency("install-stdlib");try{let n=await t;i.FS.writeFile(`/lib/python${r}${a}.zip`,n)}catch(n){console.error("Error occurred while installing the standard library:"),console.error(n)}finally{i.removeRunDependency("install-stdlib")}}}s(_e,"installStdlib");function Ie(e){let t;return e.stdLibURL!=null?t=e.stdLibURL:t=e.indexURL+"python_stdlib.zip",[...Ne(e.fsInit),_e(t),Se(e.env.HOME),we(e.env),Z]}s(Ie,"getFileSystemInitializationFuncs");function Pe(e){if(typeof WasmOffsetConverter<"u")return;let{binary:t,response:i}=k(e+"pyodide.asm.wasm");return function(r,a){return async function(){try{let n;i?n=await WebAssembly.instantiateStreaming(i,r):n=await WebAssembly.instantiate(await t,r);let{instance:o,module:c}=n;a(o,c)}catch(n){console.warn("wasm instantiation failed!"),console.warn(n)}}(),{}}}s(Pe,"getInstantiateWasmFunc");var x="0.27.7";async function B(e={}){var u,m;await M();let t=e.indexURL||await Q();t=D(t),t.endsWith("/")||(t+="/"),e.indexURL=t;let i={fullStdLib:!1,jsglobals:globalThis,stdin:globalThis.prompt?globalThis.prompt:void 0,lockFileURL:t+"pyodide-lock.json",args:[],env:{},packageCacheDir:t,packages:[],enableRunUntilComplete:!0,checkAPIVersion:!0,BUILD_ID:"e94377f5ce7dcf67e0417b69a0016733c2cfb6b4622ee8c490a6f17eb58e863b"},r=Object.assign(i,e);(u=r.env).HOME??(u.HOME="/home/pyodide"),(m=r.env).PYTHONINSPECT??(m.PYTHONINSPECT="1");let a=ee(r),n=a.API;if(n.lockFilePromise=X(r.lockFileURL),typeof _createPyodideModule!="function"){let f=`${r.indexURL}pyodide.asm.js`;await R(f)}let o;if(e._loadSnapshot){let f=await e._loadSnapshot;ArrayBuffer.isView(f)?o=f:o=new Uint8Array(f),a.noInitialRun=!0,a.INITIAL_MEMORY=o.length}let c=await _createPyodideModule(a);if(a.exited)throw a.exited.toThrow;if(e.pyproxyToStringRepr&&n.setPyProxyToStringMethod(!0),n.version!==x&&r.checkAPIVersion)throw new Error(`Pyodide version does not match: '${x}' <==> '${n.version}'. If you updated the Pyodide version, make sure you also updated the 'indexURL' parameter passed to loadPyodide.`);c.locateFile=f=>{throw new Error("Didn't expect to load any more file_packager files!")};let l;o&&(l=n.restoreSnapshot(o));let d=n.finalizeBootstrap(l,e._snapshotDeserializer);return n.sys.path.insert(0,""),d.version.includes("dev")||n.setCdnUrl(`https://cdn.jsdelivr.net/pyodide/v${d.version}/full/`),n._pyodide.set_excepthook(),await n.packageIndexReady,n.initializeStreams(r.stdin,r.stdout,r.stderr),d}s(B,"loadPyodide");globalThis.loadPyodide=B;return ce(Fe);})(); -try{Object.assign(exports,loadPyodide)}catch(_){} -globalThis.loadPyodide=loadPyodide.loadPyodide; -//# sourceMappingURL=pyodide.js.map diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.mjs b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.mjs deleted file mode 100644 index 5ecef60d60..0000000000 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.mjs +++ /dev/null @@ -1,4 +0,0 @@ -var Q=Object.defineProperty;var s=(e,t)=>Q(e,"name",{value:t,configurable:!0}),R=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,o)=>(typeof require<"u"?require:t)[o]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+e+'" is not supported')});function Z(e){return!isNaN(parseFloat(e))&&isFinite(e)}s(Z,"_isNumber");function E(e){return e.charAt(0).toUpperCase()+e.substring(1)}s(E,"_capitalize");function O(e){return function(){return this[e]}}s(O,"_getter");var w=["isConstructor","isEval","isNative","isToplevel"],N=["columnNumber","lineNumber"],_=["fileName","functionName","source"],ee=["args"],te=["evalOrigin"],P=w.concat(N,_,ee,te);function p(e){if(e)for(var t=0;t-1&&(n=n.replace(/eval code/g,"eval").replace(/(\(eval at [^()]*)|(,.*$)/g,""));var i=n.replace(/^\s+/,"").replace(/\(eval code/g,"(").replace(/^.*?\s+/,""),c=i.match(/ (\(.+\)$)/);i=c?i.replace(c[0],""):i;var l=this.extractLocation(c?c[1]:i),d=c&&i||void 0,u=["eval",""].indexOf(l[0])>-1?void 0:l[0];return new k({functionName:d,fileName:u,lineNumber:l[1],columnNumber:l[2],source:n})},this)},"ErrorStackParser$$parseV8OrIE"),parseFFOrSafari:s(function(r){var a=r.stack.split(` -`).filter(function(n){return!n.match(t)},this);return a.map(function(n){if(n.indexOf(" > eval")>-1&&(n=n.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,":$1")),n.indexOf("@")===-1&&n.indexOf(":")===-1)return new k({functionName:n});var i=/((.*".+"[^@]*)?[^@]*)(?:@)/,c=n.match(i),l=c&&c[1]?c[1]:void 0,d=this.extractLocation(n.replace(i,""));return new k({functionName:l,fileName:d[0],lineNumber:d[1],columnNumber:d[2],source:n})},this)},"ErrorStackParser$$parseFFOrSafari")}}s(ne,"ErrorStackParser");var re=new ne;var M=re;var g=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string"&&!process.browser,A=g&&typeof module<"u"&&typeof module.exports<"u"&&typeof R<"u"&&typeof __dirname<"u",W=g&&!A,Ne=typeof globalThis.Bun<"u",ie=typeof Deno<"u",B=!g&&!ie,$=B&&typeof window=="object"&&typeof document=="object"&&typeof document.createElement=="function"&&"sessionStorage"in window&&typeof importScripts!="function",j=B&&typeof importScripts=="function"&&typeof self=="object",_e=typeof navigator=="object"&&typeof navigator.userAgent=="string"&&navigator.userAgent.indexOf("Chrome")==-1&&navigator.userAgent.indexOf("Safari")>-1;var z,D,V,H,L;async function T(){if(!g||(z=(await import("node:url")).default,H=await import("node:fs"),L=await import("node:fs/promises"),V=(await import("node:vm")).default,D=await import("node:path"),U=D.sep,typeof R<"u"))return;let e=H,t=await import("node:crypto"),o=await import("ws"),r=await import("node:child_process"),a={fs:e,crypto:t,ws:o,child_process:r};globalThis.require=function(n){return a[n]}}s(T,"initNodeModules");function oe(e,t){return D.resolve(t||".",e)}s(oe,"node_resolvePath");function ae(e,t){return t===void 0&&(t=location),new URL(e,t).toString()}s(ae,"browser_resolvePath");var x;g?x=oe:x=ae;var U;g||(U="/");function se(e,t){return e.startsWith("file://")&&(e=e.slice(7)),e.includes("://")?{response:fetch(e)}:{binary:L.readFile(e).then(o=>new Uint8Array(o.buffer,o.byteOffset,o.byteLength))}}s(se,"node_getBinaryResponse");function ce(e,t){let o=new URL(e,location);return{response:fetch(o,t?{integrity:t}:{})}}s(ce,"browser_getBinaryResponse");var F;g?F=se:F=ce;async function q(e,t){let{response:o,binary:r}=F(e,t);if(r)return r;let a=await o;if(!a.ok)throw new Error(`Failed to load '${e}': request failed.`);return new Uint8Array(await a.arrayBuffer())}s(q,"loadBinaryFile");var I;if($)I=s(async e=>await import(e),"loadScript");else if(j)I=s(async e=>{try{globalThis.importScripts(e)}catch(t){if(t instanceof TypeError)await import(e);else throw t}},"loadScript");else if(g)I=le;else throw new Error("Cannot determine runtime environment");async function le(e){e.startsWith("file://")&&(e=e.slice(7)),e.includes("://")?V.runInThisContext(await(await fetch(e)).text()):await import(z.pathToFileURL(e).href)}s(le,"nodeLoadScript");async function J(e){if(g){await T();let t=await L.readFile(e,{encoding:"utf8"});return JSON.parse(t)}else return await(await fetch(e)).json()}s(J,"loadLockFile");async function K(){if(A)return __dirname;let e;try{throw new Error}catch(r){e=r}let t=M.parse(e)[0].fileName;if(g&&!t.startsWith("file://")&&(t=`file://${t}`),W){let r=await import("node:path");return(await import("node:url")).fileURLToPath(r.dirname(t))}let o=t.lastIndexOf(U);if(o===-1)throw new Error("Could not extract indexURL path from pyodide module location");return t.slice(0,o)}s(K,"calculateDirname");function Y(e){let t=e.FS,o=e.FS.filesystems.MEMFS,r=e.PATH,a={DIR_MODE:16895,FILE_MODE:33279,mount:function(n){if(!n.opts.fileSystemHandle)throw new Error("opts.fileSystemHandle is required");return o.mount.apply(null,arguments)},syncfs:async(n,i,c)=>{try{let l=a.getLocalSet(n),d=await a.getRemoteSet(n),u=i?d:l,m=i?l:d;await a.reconcile(n,u,m),c(null)}catch(l){c(l)}},getLocalSet:n=>{let i=Object.create(null);function c(u){return u!=="."&&u!==".."}s(c,"isRealDir");function l(u){return m=>r.join2(u,m)}s(l,"toAbsolute");let d=t.readdir(n.mountpoint).filter(c).map(l(n.mountpoint));for(;d.length;){let u=d.pop(),m=t.stat(u);t.isDir(m.mode)&&d.push.apply(d,t.readdir(u).filter(c).map(l(u))),i[u]={timestamp:m.mtime,mode:m.mode}}return{type:"local",entries:i}},getRemoteSet:async n=>{let i=Object.create(null),c=await de(n.opts.fileSystemHandle);for(let[l,d]of c)l!=="."&&(i[r.join2(n.mountpoint,l)]={timestamp:d.kind==="file"?new Date((await d.getFile()).lastModified):new Date,mode:d.kind==="file"?a.FILE_MODE:a.DIR_MODE});return{type:"remote",entries:i,handles:c}},loadLocalEntry:n=>{let c=t.lookupPath(n).node,l=t.stat(n);if(t.isDir(l.mode))return{timestamp:l.mtime,mode:l.mode};if(t.isFile(l.mode))return c.contents=o.getFileDataAsTypedArray(c),{timestamp:l.mtime,mode:l.mode,contents:c.contents};throw new Error("node type not supported")},storeLocalEntry:(n,i)=>{if(t.isDir(i.mode))t.mkdirTree(n,i.mode);else if(t.isFile(i.mode))t.writeFile(n,i.contents,{canOwn:!0});else throw new Error("node type not supported");t.chmod(n,i.mode),t.utime(n,i.timestamp,i.timestamp)},removeLocalEntry:n=>{var i=t.stat(n);t.isDir(i.mode)?t.rmdir(n):t.isFile(i.mode)&&t.unlink(n)},loadRemoteEntry:async n=>{if(n.kind==="file"){let i=await n.getFile();return{contents:new Uint8Array(await i.arrayBuffer()),mode:a.FILE_MODE,timestamp:new Date(i.lastModified)}}else{if(n.kind==="directory")return{mode:a.DIR_MODE,timestamp:new Date};throw new Error("unknown kind: "+n.kind)}},storeRemoteEntry:async(n,i,c)=>{let l=n.get(r.dirname(i)),d=t.isFile(c.mode)?await l.getFileHandle(r.basename(i),{create:!0}):await l.getDirectoryHandle(r.basename(i),{create:!0});if(d.kind==="file"){let u=await d.createWritable();await u.write(c.contents),await u.close()}n.set(i,d)},removeRemoteEntry:async(n,i)=>{await n.get(r.dirname(i)).removeEntry(r.basename(i)),n.delete(i)},reconcile:async(n,i,c)=>{let l=0,d=[];Object.keys(i.entries).forEach(function(f){let y=i.entries[f],S=c.entries[f];(!S||t.isFile(y.mode)&&y.timestamp.getTime()>S.timestamp.getTime())&&(d.push(f),l++)}),d.sort();let u=[];if(Object.keys(c.entries).forEach(function(f){i.entries[f]||(u.push(f),l++)}),u.sort().reverse(),!l)return;let m=i.type==="remote"?i.handles:c.handles;for(let f of d){let y=r.normalize(f.replace(n.mountpoint,"/")).substring(1);if(c.type==="local"){let S=m.get(y),X=await a.loadRemoteEntry(S);a.storeLocalEntry(f,X)}else{let S=a.loadLocalEntry(f);await a.storeRemoteEntry(m,y,S)}}for(let f of u)if(c.type==="local")a.removeLocalEntry(f);else{let y=r.normalize(f.replace(n.mountpoint,"/")).substring(1);await a.removeRemoteEntry(m,y)}}};e.FS.filesystems.NATIVEFS_ASYNC=a}s(Y,"initializeNativeFS");var de=s(async e=>{let t=[];async function o(a){for await(let n of a.values())t.push(n),n.kind==="directory"&&await o(n)}s(o,"collect"),await o(e);let r=new Map;r.set(".",e);for(let a of t){let n=(await e.resolve(a)).join("/");r.set(n,a)}return r},"getFsHandles");function G(e){let t={noImageDecoding:!0,noAudioDecoding:!0,noWasmDecoding:!1,preRun:ge(e),quit(o,r){throw t.exited={status:o,toThrow:r},r},print:e.stdout,printErr:e.stderr,thisProgram:e._sysExecutable,arguments:e.args,API:{config:e},locateFile:o=>e.indexURL+o,instantiateWasm:ye(e.indexURL)};return t}s(G,"createSettings");function ue(e){return function(t){let o="/";try{t.FS.mkdirTree(e)}catch(r){console.error(`Error occurred while making a home directory '${e}':`),console.error(r),console.error(`Using '${o}' for a home directory instead`),e=o}t.FS.chdir(e)}}s(ue,"createHomeDirectory");function fe(e){return function(t){Object.assign(t.ENV,e)}}s(fe,"setEnvironment");function me(e){return e?[async t=>{t.addRunDependency("fsInitHook");try{await e(t.FS,{sitePackages:t.API.sitePackages})}finally{t.removeRunDependency("fsInitHook")}}]:[]}s(me,"callFsInitHook");function pe(e){let t=q(e);return async o=>{let r=o._py_version_major(),a=o._py_version_minor();o.FS.mkdirTree("/lib"),o.API.sitePackages=`/lib/python${r}.${a}/site-packages`,o.FS.mkdirTree(o.API.sitePackages),o.addRunDependency("install-stdlib");try{let n=await t;o.FS.writeFile(`/lib/python${r}${a}.zip`,n)}catch(n){console.error("Error occurred while installing the standard library:"),console.error(n)}finally{o.removeRunDependency("install-stdlib")}}}s(pe,"installStdlib");function ge(e){let t;return e.stdLibURL!=null?t=e.stdLibURL:t=e.indexURL+"python_stdlib.zip",[...me(e.fsInit),pe(t),ue(e.env.HOME),fe(e.env),Y]}s(ge,"getFileSystemInitializationFuncs");function ye(e){if(typeof WasmOffsetConverter<"u")return;let{binary:t,response:o}=F(e+"pyodide.asm.wasm");return function(r,a){return async function(){try{let n;o?n=await WebAssembly.instantiateStreaming(o,r):n=await WebAssembly.instantiate(await t,r);let{instance:i,module:c}=n;a(i,c)}catch(n){console.warn("wasm instantiation failed!"),console.warn(n)}}(),{}}}s(ye,"getInstantiateWasmFunc");var C="0.27.7";async function $e(e={}){var u,m;await T();let t=e.indexURL||await K();t=x(t),t.endsWith("/")||(t+="/"),e.indexURL=t;let o={fullStdLib:!1,jsglobals:globalThis,stdin:globalThis.prompt?globalThis.prompt:void 0,lockFileURL:t+"pyodide-lock.json",args:[],env:{},packageCacheDir:t,packages:[],enableRunUntilComplete:!0,checkAPIVersion:!0,BUILD_ID:"e94377f5ce7dcf67e0417b69a0016733c2cfb6b4622ee8c490a6f17eb58e863b"},r=Object.assign(o,e);(u=r.env).HOME??(u.HOME="/home/pyodide"),(m=r.env).PYTHONINSPECT??(m.PYTHONINSPECT="1");let a=G(r),n=a.API;if(n.lockFilePromise=J(r.lockFileURL),typeof _createPyodideModule!="function"){let f=`${r.indexURL}pyodide.asm.js`;await I(f)}let i;if(e._loadSnapshot){let f=await e._loadSnapshot;ArrayBuffer.isView(f)?i=f:i=new Uint8Array(f),a.noInitialRun=!0,a.INITIAL_MEMORY=i.length}let c=await _createPyodideModule(a);if(a.exited)throw a.exited.toThrow;if(e.pyproxyToStringRepr&&n.setPyProxyToStringMethod(!0),n.version!==C&&r.checkAPIVersion)throw new Error(`Pyodide version does not match: '${C}' <==> '${n.version}'. If you updated the Pyodide version, make sure you also updated the 'indexURL' parameter passed to loadPyodide.`);c.locateFile=f=>{throw new Error("Didn't expect to load any more file_packager files!")};let l;i&&(l=n.restoreSnapshot(i));let d=n.finalizeBootstrap(l,e._snapshotDeserializer);return n.sys.path.insert(0,""),d.version.includes("dev")||n.setCdnUrl(`https://cdn.jsdelivr.net/pyodide/v${d.version}/full/`),n._pyodide.set_excepthook(),await n.packageIndexReady,n.initializeStreams(r.stdin,r.stdout,r.stderr),d}s($e,"loadPyodide");export{$e as loadPyodide,C as version}; -//# sourceMappingURL=pyodide.mjs.map diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/python_stdlib.zip b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/python_stdlib.zip deleted file mode 100644 index 6cf1e28190..0000000000 Binary files a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/python_stdlib.zip and /dev/null differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python-worker.js b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python-worker.js index 40c6083afc..390ea96747 100644 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python-worker.js +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python-worker.js @@ -38,7 +38,14 @@ self.sendPythonOutput = function (text, isStderr) { self.initPyodide = async function () { try { - importScripts(self.pyodideUrl); + // Module-worker load path. `importScripts` only exists in classic + // workers — Pyodide >= 0.29 actively refuses to load there ("Classic + // web workers are not supported"). We're a module worker, so the + // runtime ships as `pyodide.mjs` and exposes `loadPyodide` via ESM + // exports. The CDN/jsdelivr fallback URL set by patch_index.py also + // points at the .mjs variant. + const pyodideModule = await import(self.pyodideUrl); + const loadPyodide = pyodideModule.loadPyodide || self.loadPyodide; self.pyodide = await loadPyodide({ stdout: (text) => self.sendPythonOutput(text, false), stderr: (text) => self.sendPythonOutput(text, true), @@ -163,8 +170,15 @@ self.initPyodide = async function () { import msgpack as _msgpack def _send_python_output(text, is_stderr): + # Frame exactly like PyodideConnection.send_message: a 0x00 type + # byte (0x00 = MsgPack Flet protocol frame, 0x01 = raw DataChannel + # frame) in front of the packed [action, body]. Without the prefix + # the Dart side reads msgpack's leading 0x92 as an unknown packet + # type and silently drops the line. bytes([0]) avoids a literal + # NUL escape inside this JS template string. flet_js.receive_callback( - _msgpack.packb( + bytes([0]) + + _msgpack.packb( [7, {"text": text, "is_stderr": bool(is_stderr)}] ) ) @@ -206,7 +220,14 @@ self.initPyodide = async function () { }; self.receiveCallback = (message) => { - self.postMessage(message.toJs()); + // `message` is a Pyodide JsProxy wrapping a Python `bytes`. `toJs()` + // gives us a fresh Uint8Array; transferring its underlying ArrayBuffer + // to the main thread skips the structured-clone copy (~hundreds of KB + // per matplotlib frame). Safe because the Uint8Array is freshly + // materialized here, and the original Python `bytes` is untouched + // (Pyodide keeps its own reference). + const bytes = message.toJs(); + self.postMessage(bytes, [bytes.buffer]); } // Same channel as `receiveCallback`, exposed under `flet_js` so the // Python python_output shim can post pre-encoded msgpack frames. diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python.js b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python.js index db2e34a9f0..89e09e6366 100644 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python.js +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python.js @@ -1,5 +1,6 @@ -const defaultPyodideUrl = "https://cdn.jsdelivr.net/pyodide/v0.27.7/full/pyodide.js"; - +// Pyodide URL is injected per build by flet-web's patch_index.py +// (sets flet.pyodideUrl). Falls back to the local pyodide/ directory that +// flet build web / flet publish drop next to the page. let _apps = {}; let _documentUrl = document.URL; @@ -12,7 +13,14 @@ globalThis.jsConnect = async function(appId, args, dartOnMessage) { }; console.log(`Starting up Python worker: ${appId}, args: ${args}`); _apps[appId] = app; - app.worker = new Worker("python-worker.js"); + // Module worker (type: "module") is required by Pyodide >= 0.29 — the + // runtime throws "Classic web workers are not supported" inside any + // worker where `importScripts` is callable. Module workers don't have + // `importScripts`, so the check passes. Older Pyodide lines (0.27.x) + // accept module workers too, so this is forward-compatible across all + // supported Python versions (3.12 → Pyodide 0.27.7, 3.13 → 0.29.4, + // 3.14 → 314.0.0). + app.worker = new Worker("python-worker.js", { type: "module" }); var error; app.worker.onmessage = (event) => { @@ -30,7 +38,11 @@ globalThis.jsConnect = async function(appId, args, dartOnMessage) { // initialize worker app.worker.postMessage({ - pyodideUrl: flet.noCdn ? flet.pyodideUrl : defaultPyodideUrl, + // `.mjs` is the ES-module variant. python-worker.js (now a module + // worker) loads it via dynamic `import()`. The legacy `.js` + // variant relied on `importScripts`, which doesn't exist in a + // module worker. + pyodideUrl: flet.pyodideUrl || "pyodide/pyodide.mjs", args: args, documentUrl: _documentUrl, appPackageUrl: flet.appPackageUrl, diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/main.cpp b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/main.cpp index 7c91006a81..67a07c56f9 100644 --- a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/main.cpp +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/main.cpp @@ -1,12 +1,68 @@ #include #include +#include #include #include "flutter_window.h" #include "utils.h" +// Python's multiprocessing spawn path, including the resource tracker, creates +// child processes by re-executing sys.executable with a CPython-style command +// line. In a flet-built Windows app, sys.executable is this app binary. Detect +// that argv shape before Win32 window/COM/Flutter initialization and run the +// embedded interpreter headlessly instead of starting another GUI app. +// See: https://github.com/flet-dev/flet/issues/4283 +// +// These optional entry points live in dart_bridge.dll. Load the bridge early +// and resolve them dynamically so apps built with older dart_bridge versions +// still launch; they just won't have multiprocessing child interception. +// +// Returns true when this process was handled as a multiprocessing child. In +// that case, exit_code receives the interpreter process exit code. +static bool MaybeRunPythonChild(int& exit_code) { + using SpArgvFn = int (*)(int, wchar_t **); + + int argc = 0; + wchar_t **argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (!argv) { + return false; + } + + bool handled = false; + + // The DLL, and its python3XX.dll dependency, would be loaded moments later by + // the plugin anyway, so eagerly loading it here does not add meaningful cost + // to the normal startup path. + HMODULE bridge = ::LoadLibraryW(L"dart_bridge.dll"); + if (!bridge) { + bridge = ::LoadLibraryW(L"dart_bridge_d.dll"); + } + + if (bridge) { + auto is_mp_invocation = reinterpret_cast( + ::GetProcAddress(bridge, "serious_python_is_mp_invocation_w")); + auto run_python_main = reinterpret_cast( + ::GetProcAddress(bridge, "serious_python_main_w")); + + if (is_mp_invocation && run_python_main && + is_mp_invocation(argc, argv) != 0) { + exit_code = run_python_main(argc, argv); + handled = true; + } + } + + ::LocalFree(argv); + return handled; +} + int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t *command_line, _In_ int show_command) { + // Multiprocessing child re-exec? Run it headlessly and exit, instead of starting Flutter GUI. + int mp_exit_code = 0; + if (MaybeRunPythonChild(mp_exit_code)) { + return mp_exit_code; + } + // Attach to console when present (e.g., 'flutter run') or create a // new console when running with a debugger. if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { diff --git a/website/.gitignore b/website/.gitignore index cf48be5921..16e03de43b 100644 --- a/website/.gitignore +++ b/website/.gitignore @@ -25,6 +25,10 @@ yarn-error.log* .venv/ .crocodocs/ +# Generated by `crocodocs generate` from sidebars.yml (the tracked source). +# Regenerated by `yarn start`/`yarn build` (and CI) before Docusaurus reads it. +/sidebars.js + # Generated CrocoDocs asset mirrors /docs/assets/ /docs/examples/ diff --git a/website/blog/2026-07-14-flet-v-0-86-release-announcement.md b/website/blog/2026-07-14-flet-v-0-86-release-announcement.md new file mode 100644 index 0000000000..2a37305d99 --- /dev/null +++ b/website/blog/2026-07-14-flet-v-0-86-release-announcement.md @@ -0,0 +1,282 @@ +--- +slug: flet-v-0-86-release-announcement +title: "Flet 0.86.0: Faster everywhere — new Android packaging, dart-bridge, and Python 3.14" +authors: feodor +tags: [releases] +--- + +Flet 86 + +Flet 0.86.0 is our "anniversary" release — the last one before 1.0 — and the logo is a nod to [Expo 86](https://en.wikipedia.org/wiki/Expo_86), the World's Fair held in Vancouver in 1986. Expo 86's theme was *"Transportation and Communication"*, and by a happy coincidence that's exactly what this release is about: how Python and Dart **communicate** — a new in-process dart-bridge transport replacing sockets, plus dedicated data channels for bulk binary traffic — and how your app is **transported** to devices, with completely re-designed Android packaging and faster, leaner packaging on every other platform. + +Under the retro logo, 0.86 pays down the last big pieces of technical debt on the road to 1.0: direct Python↔Dart communication without sockets, and a real integration-testing story for your apps. + +Highlights in this release: + +* **Multi-version Python** — bundle Python 3.12, 3.13, or 3.14 on all platforms, with the latest Pyodide 314.0.2 on the web and [70+ pre-built Android and iOS binary packages](https://pypi.flet.dev) for every supported version. +* **dart-bridge** — lightning-fast in-process communication between Python and Dart; no more sockets. +* **Data channels** — dedicated byte channels for bulk binary data, bypassing the control protocol. +* **New [`ft.RawImage`](/docs/controls/rawimage) control** — full-bandwidth pixel streaming from Pillow, NumPy, or camera frames straight to a GPU texture. +* **Faster Matplotlib** — raw RGBA frames over data channels: 2.5× higher FPS on interactive charts. +* **Re-designed Android packaging** — modern, extraction-free, memory-mapped; smaller and faster apps. +* **Faster startup everywhere** — unpacked app bundles, bytecode compilation by default, and lazy `import flet`. +* **Testing framework** — write pytest integration tests for your app and run them on real devices with `flet test`. +* **Flet MCP server** — accurate, version-specific Flet knowledge for your AI agent. +* **Multiprocessing support** in packaged desktop apps, custom boot screens, normalized app storage, and more. + +{/* truncate */} + +## How to upgrade + +If you use pip: + +```bash +pip install 'flet[all]' --upgrade +``` + +If you use uv with `pyproject.toml` and want to upgrade everything: + +```bash +uv sync --upgrade +``` + +If you want to upgrade only Flet packages: + +```bash +uv sync --upgrade-package flet \ + --upgrade-package flet-cli \ + --upgrade-package flet-desktop \ + --upgrade-package flet-web +``` + +## Multi-version Python + +Until now, `flet build` shipped one hardcoded Python version. 0.86 lets you pick the runtime your app bundles — **3.12, 3.13, or 3.14** — on all platforms: Windows, macOS, Linux, Android, iOS, and web. + +```bash +flet build apk --python-version 3.13 +``` + +Or skip the flag and let Flet derive it from `requires-python` in your `pyproject.toml`; with neither, you get the latest supported stable — currently **Python 3.14.6**. Web builds get the matching Pyodide release automatically, up to the latest **Pyodide 314.0.2** for Python 3.14. + +Behind the scenes there's now a **single source of truth for Python runtimes**: a manifest in the [python-build](https://github.com/flet-dev/python-build) repository defines the exact CPython build, Pyodide release, and dart-bridge version for every supported Python line, shared by the Flet CLI and `serious_python`. When a new CPython lands, supporting it is a manifest update — not a coordinated release train. And to make native dependencies just work on mobile, we publish [**70+ pre-built Android and iOS binary packages**](https://pypi.flet.dev) (numpy, pillow, cryptography, pydantic-core, and friends) for every supported Python version. + +More info: + +* PR: [#6577](https://github.com/flet-dev/flet/pull/6577) +* Docs: [Choosing a Python version](/docs/publish#choosing-a-python-version) +* Migration: [Default bundled Python is now 3.14](/docs/updates/breaking-changes/v0-86-0/default-bundled-python-3-14) + +## dart-bridge: in-process Python ↔ Dart + +Since its first release, a packaged Flet app has been two programs talking over a localhost socket: the Flutter client on one side, your Python app on the other. It worked, but it meant socket setup, message copies through the OS, and awkward lifecycle corners on mobile. + +0.86 replaces that with [**dart-bridge**](https://github.com/flet-dev/dart-bridge): the Python interpreter is embedded **in the same process** as the Flutter app, and the two sides exchange messages over an FFI byte channel — no sockets, no network stack, no serialization detours. This is now how every app built with `flet build` runs on desktop and mobile. + +Beyond raw speed, in-process embedding fixes real behaviors: on Android, when the OS keeps the process alive after a back-button quit and restarts only the Dart VM, the transport rebinds to the new VM — your Python process and its in-memory state survive, and the session is rebuilt seamlessly. It's also the foundation that made [multiprocessing support](#multiprocessing-in-desktop-apps) possible. + +## Data channels + +The Flet protocol is great for control updates, but it was never meant for moving megabytes of pixels or audio per frame — every byte went through MsgPack serialization on one side and deserialization on the other. + +New in 0.86, [**data channels**](/docs/types/datachannel) are dedicated byte pipes between Dart and Python for exactly that: image frames, audio buffers, ML tensors. Frames bypass the control protocol entirely; in embedded (dart-bridge) mode each channel is backed by its own bridge, moving **4–7 GiB/s** on an M2 Pro. In dev and web modes, channels transparently mux over the active transport, and Pyodide gets zero-copy outbound sends via transferable ArrayBuffers. + +Data channels are a building block for control authors — and the next two features are the first controls built on top of them. + +More info: + +* Docs: [DataChannel](/docs/types/datachannel) +* Migration: [Protocol framing upgrade](/docs/updates/breaking-changes/v0-86-0/data-channel-protocol-upgrade) + +## New `RawImage` control + +Use [`Image`](/docs/controls/image) for pictures that come from a file or URL. Use the new [**`ft.RawImage`**](/docs/controls/rawimage) when your Python code *produces* pixels — Pillow drawings, NumPy arrays, camera frames, procedural animations — and you want to push them to the screen repeatedly and fast. + +Frames stream over a dedicated data channel: when the client runs on the same machine (desktop app, `flet run`, Pyodide), raw premultiplied RGBA goes straight to a GPU texture with no image encoding or decoding on either side; remote web sessions automatically fall back to compact PNG frames. The `render` methods are awaitable and resolve when the frame is actually displayed, so a plain loop self-paces to display speed: + +```python +raw_image = ft.RawImage(expand=True) +page.add(raw_image) + +while True: + await raw_image.render(produce_pil_image()) +``` + +[`render()`](/docs/controls/rawimage#flet.RawImage.render) accepts Pillow images and NumPy arrays, [`render_rgba()`](/docs/controls/rawimage#flet.RawImage.render_rgba) takes raw pixel bytes, and [`render_encoded()`](/docs/controls/rawimage#flet.RawImage.render_encoded) displays ready-made PNG/JPEG/WebP bytes. Pillow and NumPy are optional dependencies. The control ships with five gallery examples: a photo viewer, a plasma animation, a Pillow paint app, a Mandelbrot explorer, and Game of Life. + +More info: + +* PR: [#6674](https://github.com/flet-dev/flet/pull/6674) +* Docs: [RawImage](/docs/controls/rawimage) + +## Faster Matplotlib + +[`MatplotlibChart`](/docs/controls/charts/matplotlibchart) was the first control migrated to data channels, and interactive charts got dramatically faster in the process. On local transports, per-frame diffing and PNG encode/decode are skipped entirely: uncompressed RGBA frames stream straight from matplotlib's Agg buffer to the screen. A 1600×1000 figure at 2× DPR — 24 MB per frame — went from **7.4 to 18.7 fps**, to the point where matplotlib's own rendering is now the dominant per-frame cost. Remote web clients keep the bandwidth-friendly PNG full+diff pipeline. + +Related: `flet build web` now defaults the renderer to `canvaskit`, because the `auto` renderer's JS↔Dart typed-data boundary made byte-streaming Pyodide apps 6–7× slower per frame. Pass `--renderer auto` to restore the old behavior. + +More info: + +* PR: [#6673](https://github.com/flet-dev/flet/pull/6673) + +## Re-designed Android packaging + +Packaging on Android has been **completely re-done** in 0.86 — this is the release's biggest single piece of engineering. What changed: + +* **No more "legacy" packaging.** Android no longer unpacks native libraries from the `.apk` to disk — it serves them directly from the APK. The `useLegacyPackaging` / `keepDebugSymbols` workarounds are gone from the build template; all you need is `minSdk 23+`. +* **Real native libraries, loaded from memory.** Binary `.so` extension modules no longer hide inside a fake `libsitepackages.so` zip. They now live in proper `lib/{arch}` folders alongside other native libraries and are **memory-mapped directly from the APK** by a custom Python loader — no extraction, no disk copies. +* **Pure-Python-only zips.** `site-packages.zip` now contains only Python files; all platform-dependent binaries — historically the biggest size factor — are stripped out and moved to `lib/{arch}`. +* **Zero-compression, zero-extraction imports.** Both the stdlib and site-packages ship as *stored* (uncompressed) zips that Python imports from directly via `zipimport`, and the app zip ships in Android assets. +* **Compiled by default.** Compiling site-packages and app code on-device used to cost 2–3 seconds of startup on slow devices — now bytecode ships pre-compiled. + +The result: smaller APKs, faster installs, and faster cold starts — with no packaging configuration on your side. For the rare "path-hungry" package that insists on reading its data files via `__file__` instead of `importlib.resources`, the new `--android-extract-packages` flag (or `[tool.flet.android].extract_packages`) ships it extracted to disk. + +More info: + +* PRs: [#6578](https://github.com/flet-dev/flet/pull/6578), [serious-python#223](https://github.com/flet-dev/serious-python/pull/223) +* Migration: [App files unpacked, storage dirs reworked](/docs/updates/breaking-changes/v0-86-0/app-files-unpacked-read-only-bundle), [Compile on by default](/docs/updates/breaking-changes/v0-86-0/compile-on-by-default) + +## Faster startup on all platforms + +Android wasn't the only platform to get a startup diet — three changes speed up every Flet app: + +* **App ships unpacked inside the bundle.** On macOS, iOS, Windows, and Linux your Python sources now live unpacked in the app bundle next to the stdlib and site-packages — the first-launch `app.zip` extraction step is gone entirely. +* **Bytecode compilation is on by default.** `flet build` now compiles your app and its packages to `.pyc`, removing per-launch recompilation. As a bonus, shipping bytecode instead of `.py` sources hides your code from curious eyes. Use `--no-compile-app` / `--no-compile-packages` to opt out. +* **`import flet` is lazy.** The `flet` package used to eagerly execute its full ~270-module public API on import; it now resolves names on first access ([PEP 562](https://peps.python.org/pep-0562/)), so your app loads only what it uses. On a mid-range Android device this cut `import flet` from ~2.0 s to ~0.15 s — reducing total startup time 1.5–2× across all platforms. Type checkers and IDEs are unaffected. + +More info: + +* PRs: [#6597](https://github.com/flet-dev/flet/pull/6597), [#6598](https://github.com/flet-dev/flet/pull/6598) +* Migration: [Compile on by default](/docs/updates/breaking-changes/v0-86-0/compile-on-by-default) + +## Testing framework and `flet test` + +Flet apps can finally be tested the way they ship. The new testing framework lets you write **integration tests** that drive your app like a user would — find controls by key or text, tap buttons, enter text, assert the resulting UI, compare screenshots — while the app runs **on the target device** as a built monolithic app with embedded Python. + +Tests are plain [pytest](https://docs.pytest.org), so fixtures, parametrization, and `-k` filtering all just work: + +```python title="tests/test_main.py" +import flet.testing as ftt + + +async def test_increment(flet_app: ftt.FletTestApp): + tester = flet_app.tester + await tester.pump_and_settle() + + assert (await tester.find_by_text("0")).count == 1 + + await tester.tap(await tester.find_by_key("increment")) + await tester.pump_and_settle() + + assert (await tester.find_by_text("1")).count == 1 +``` + +Run them on the platform of your choice: + +```bash +flet test # current desktop platform +flet test android # attached Android device or emulator +``` + +New apps created with `flet create` include a `tests/` folder and pytest configuration out of the box. + +More info: + +* PR: [#6623](https://github.com/flet-dev/flet/pull/6623) +* Docs: [Integration testing](/docs/getting-started/integration-testing), [`flet test`](/docs/cli/flet-test) + +## Flet MCP server + +AI coding assistants are great at writing Flet apps — until they hallucinate a control property that doesn't exist. The new **`flet-mcp`** package is an [MCP](https://modelcontextprotocol.io) server that gives LLM agents accurate, version-specific knowledge about Flet: look up the real API, search enum members, find icons, search example projects, and inspect CLI options on demand. + +```bash +pip install flet-mcp +``` + +Then point your AI client (Claude Desktop, Claude Code, Cursor, VS Code, ...) at it: + +```json +{ + "mcpServers": { + "flet": { + "command": "flet", + "args": ["mcp"] + } + } +} +``` + +More info: + +* PRs: [#6624](https://github.com/flet-dev/flet/pull/6624), [#6654](https://github.com/flet-dev/flet/pull/6654) +* Docs: [Flet MCP server](/docs/cookbook/flet-mcp) + +## Multiprocessing in desktop apps + +Python `multiprocessing` now works in packaged desktop apps built with `flet build macos` / `windows` / `linux`: `Process`, `ProcessPoolExecutor`, the `spawn` and `forkserver` start methods, and the resource tracker all behave as expected. Previously, each worker process re-executed the app binary itself — launching another GUI instance and hanging. + +Made possible by dart-bridge, worker command lines are now detected before Flutter starts and diverted to a headless embedded Python interpreter. Normal multiprocessing rules apply: guard `ft.run(...)` with `if __name__ == "__main__":`, define worker functions at module top level, and don't touch Flet UI objects from workers. Mobile platforms remain unsupported — iOS and Android don't allow apps to spawn child processes. + +More info: + +* Issue: [#4283](https://github.com/flet-dev/flet/issues/4283), PR: [#6662](https://github.com/flet-dev/flet/pull/6662) +* Docs: [Multiprocessing](/docs/cookbook/multiprocessing) + +## Custom boot screen + +There's a gap between the native splash screen and your app's first frame — the Flutter engine is up, but Python is still starting. In 0.86 that gap is always covered by a configurable **boot screen**. The built-in one is themable from `pyproject.toml` — background colors, spinner, and stage messages for light and dark modes: + +```toml +[tool.flet.boot_screen.flet] +theme_mode = "auto" +spinner_size = 30 +startup_message = "Starting up…" +``` + +If that's not enough, you can replace it entirely with your own Flutter widget shipped as an extension — animated logos, progress art, whatever fits your brand. Startup errors are rendered on the boot screen too, so a failed launch is a readable message instead of a black window. + +More info: + +* Docs: [Boot screen](/docs/publish#boot-screen), [Custom boot screen](/docs/publish#custom-boot-screen) + +## Normalized app storage + +App files now ship in a **read-only bundle**, and the writable storage directories were normalized across platforms: `FLET_APP_STORAGE_DATA` maps to the OS application-support directory and is the working directory of your app, `FLET_APP_STORAGE_TEMP` points to the OS temp directory, and the new `FLET_APP_STORAGE_CACHE` exposes the cache directory. + +The best part is that development mode now mirrors on-device behavior: `flet run` sets the working directory to a hidden, git-ignored `.flet/storage/data` inside your project — so an app that writes files relative to the current directory behaves the same on your laptop as it will on a phone, and stray output files no longer litter your project root. + +More info: + +* Migration: [App files unpacked, storage dirs reworked](/docs/updates/breaking-changes/v0-86-0/app-files-unpacked-read-only-bundle) + +## Other improvements + +* **Swift Package Manager** for iOS and macOS builds, on by default with automatic CocoaPods fallback for non-SPM-ready packages (CocoaPods goes read-only in December 2026). +* New `flet clean` command deletes the app's `build` directory; the `--clear-cache` flag is deprecated ([#6233](https://github.com/flet-dev/flet/issues/6233)). +* Bundled **Flutter bumped to 3.44.2** — built-in Kotlin, Java 17, Gradle 8.14. +* `flet --version --json` emits machine-readable version info for CI ([#6577](https://github.com/flet-dev/flet/pull/6577)). +* Pyodide is no longer pre-baked into the build template — it's downloaded per version and cached under `~/.flet` ([#6577](https://github.com/flet-dev/flet/pull/6577)). +* `compression_quality` for [`FilePicker.pick_files()`](/docs/services/filepicker#flet.FilePicker.pick_files) ([#6573](https://github.com/flet-dev/flet/pull/6573)). +* [`ConsentManager`](/docs/controls/ads/consentmanager) in `flet-ads` for GDPR/EEA consent via Google UMP ([#6615](https://github.com/flet-dev/flet/pull/6615)). +* Stateful controls inside [`ResponsiveRow`](/docs/controls/responsiverow) no longer lose state when a resize crosses a breakpoint ([#6663](https://github.com/flet-dev/flet/pull/6663)). +* `Session.patch_control` mount/unmount scans improved from O(N²) to O(N) ([#6651](https://github.com/flet-dev/flet/pull/6651)). + +## Breaking changes + +0.86 is a foundational release, and a few changes need attention when upgrading: + +* [Default bundled Python is now 3.14](/docs/updates/breaking-changes/v0-86-0/default-bundled-python-3-14) — pin `--python-version 3.12` if your native wheels aren't 3.14-ready yet. +* [App files ship unpacked in a read-only bundle; storage dirs reworked](/docs/updates/breaking-changes/v0-86-0/app-files-unpacked-read-only-bundle) — relative *writes* keep working (cwd is now the data dir); relative *reads* of bundled files should switch to `__file__` or `importlib.resources`. +* [App and packages are compiled to .pyc by default](/docs/updates/breaking-changes/v0-86-0/compile-on-by-default) — pass `--no-compile-app` / `--no-compile-packages` to opt out. +* [Protocol framing upgraded for DataChannel support](/docs/updates/breaking-changes/v0-86-0/data-channel-protocol-upgrade) — pre-0.86 clients and servers can't talk to 0.86 ones. +* [flet.version.pyodide_version removed](/docs/updates/breaking-changes/v0-86-0/removed-pyodide-version-export) and [flet build --clear-cache deprecated](/docs/updates/breaking-changes/v0-86-0/deprecated-clear-cache-flag). + +See the full [CHANGELOG](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0860) for the complete list of changes and fixes. + +## Conclusion + +Expo 86 celebrated moving people and messages; Flet 0.86 celebrates moving bytes and apps. With sockets replaced by an in-process bridge, packaging rebuilt around zero-extraction and pre-compiled bytecode, a real testing story, and any-version Python on every platform, this release closes out the foundational work we wanted done before 1.0. From here, the road to 1.0 is about polish — not plumbing. + +Try it in your apps and share feedback in [GitHub Discussions](https://github.com/flet-dev/flet/discussions) or on [Discord](https://discord.gg/dzWXP8SHG8). + +Happy Flet-ing! diff --git a/website/docs/cli/flet-clean.md b/website/docs/cli/flet-clean.md new file mode 100644 index 0000000000..c05b73b177 --- /dev/null +++ b/website/docs/cli/flet-clean.md @@ -0,0 +1,7 @@ +--- +title: "flet clean" +--- + +import CliClean from '@site/.crocodocs/cli-clean.mdx'; + + diff --git a/website/docs/cli/flet-mcp.md b/website/docs/cli/flet-mcp.md new file mode 100644 index 0000000000..46e830909e --- /dev/null +++ b/website/docs/cli/flet-mcp.md @@ -0,0 +1,7 @@ +--- +title: "flet mcp" +--- + +import CliMcp from '@site/.crocodocs/cli-mcp.mdx'; + + diff --git a/website/docs/cli/flet-publish.md b/website/docs/cli/flet-publish.md index b825bd1c30..a7f827152f 100644 --- a/website/docs/cli/flet-publish.md +++ b/website/docs/cli/flet-publish.md @@ -5,3 +5,12 @@ title: "flet publish" import CliPublish from '@site/.crocodocs/cli-publish.mdx'; + +:::note[`--pre` vs `--python-version`] +`--pre` allows **micropip** to resolve pre-release versions of *Python +packages* at runtime. It is unrelated to which CPython/Pyodide release is +bundled. To choose a pre-release Python interpreter (e.g. 3.15 once it +appears in the supported list), name it explicitly via `--python-version` or +`[project].requires-python` in `pyproject.toml` — see +[Choosing a Python version](../publish/index.md#choosing-a-python-version). +::: diff --git a/website/docs/cli/flet-test.md b/website/docs/cli/flet-test.md new file mode 100644 index 0000000000..2a478b2003 --- /dev/null +++ b/website/docs/cli/flet-test.md @@ -0,0 +1,7 @@ +--- +title: "flet test" +--- + +import CliTest from '@site/.crocodocs/cli-test.mdx'; + + diff --git a/website/docs/controls/ads/consentmanager.md b/website/docs/controls/ads/consentmanager.md new file mode 100644 index 0000000000..e67f59557a --- /dev/null +++ b/website/docs/controls/ads/consentmanager.md @@ -0,0 +1,16 @@ +--- +class_name: "flet_ads.consent_manager.ConsentManager" +examples: "extensions/ads" +example_images: "examples/extensions/ads/media" +title: "ConsentManager" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + + + + diff --git a/website/docs/controls/ads/index.md b/website/docs/controls/ads/index.md index 9f9aad655b..99f4625869 100644 --- a/website/docs/controls/ads/index.md +++ b/website/docs/controls/ads/index.md @@ -106,6 +106,66 @@ testing purposes. **They are not meant to be used in production.** +## Consent (UMP) + +[`ConsentManager`][flet_ads.ConsentManager] wraps Google's +[User Messaging Platform (UMP)](https://developers.google.com/admob/flutter/privacy) to +gather user consent (for example, the GDPR/EEA consent form) before requesting ads. + +The consent message itself is created and published in the +[AdMob console](https://apps.admob.com), not in code: Google serves the +region-appropriate message (EEA/GDPR, a regulated US state, and so on) based on the user's +location. Your app only requests an update and shows the form when required. + +### Testing the consent form + +Force a geography during development with +[`DebugGeography`][flet_ads.DebugGeography] on +[`ConsentDebugSettings`][flet_ads.ConsentDebugSettings]: + +- **Simulators and emulators are automatically registered as test devices**, so the debug + geography applies on them **without** any + [`test_identifiers`][flet_ads.ConsentDebugSettings.test_identifiers]. +- On a **physical device**, register it first: call + [`request_consent_info_update()`][flet_ads.ConsentManager.request_consent_info_update] + once, then read the device's hashed ID from the **native** device log. Add that ID to + `test_identifiers` and re-run. + +The message carrying the hashed ID differs per platform: + +**Android** (`adb logcat`): + +```text +Use new ConsentDebugSettings.Builder().addTestDeviceHashedId("33BE2250B43518CCDA7DE426D04EE231") +to set this as a debug device. +``` + +**iOS** (Xcode console / Console.app): + +```text +To enable debug mode for this device, +set: UMPDebugSettings.testDeviceIdentifiers = @[2077ef9a63d2b398840261c8221a0c9b] +``` + +### Interpreting consent status + +[`ConsentStatus`][flet_ads.ConsentStatus] reflects whether a decision was +*collected*, not what the user chose — it becomes `OBTAINED` whether they consent +**or** decline. To gate ad loading, use [`can_request_ads()`][flet_ads.ConsentManager.can_request_ads]; +when consent is declined the SDK simply serves non-personalized ads. + +Furthermore, the consent status is cached across sessions, so the form is shown only once. When in testing/debug mode, +you can call [`ConsentManager.reset()`][flet_ads.ConsentManager.reset] to replay the flow as a +first-time user. The [test AdMob app ID](#test-values) provided above already has a sample consent message, so it +shows the form during testing; in production your own app ID needs a message **published** in the +AdMob console. + +### Under age of consent + +Setting [`tag_for_under_age_of_consent`][flet_ads.ConsentRequestParameters.tag_for_under_age_of_consent] +to `True` suppresses the consent form — users under the age of consent cannot be asked to +consent. Leave it unset (or `False`) while testing the form. + ## Example diff --git a/website/docs/controls/ads/types/consentdebugsettings.md b/website/docs/controls/ads/types/consentdebugsettings.md new file mode 100644 index 0000000000..2486d33ae5 --- /dev/null +++ b/website/docs/controls/ads/types/consentdebugsettings.md @@ -0,0 +1,7 @@ +--- +title: "ConsentDebugSettings" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/ads/types/consentrequestparameters.md b/website/docs/controls/ads/types/consentrequestparameters.md new file mode 100644 index 0000000000..97898d68bf --- /dev/null +++ b/website/docs/controls/ads/types/consentrequestparameters.md @@ -0,0 +1,7 @@ +--- +title: "ConsentRequestParameters" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/ads/types/consentstatus.md b/website/docs/controls/ads/types/consentstatus.md new file mode 100644 index 0000000000..b91870ed2c --- /dev/null +++ b/website/docs/controls/ads/types/consentstatus.md @@ -0,0 +1,7 @@ +--- +title: "ConsentStatus" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/ads/types/debuggeography.md b/website/docs/controls/ads/types/debuggeography.md new file mode 100644 index 0000000000..5932db3d5d --- /dev/null +++ b/website/docs/controls/ads/types/debuggeography.md @@ -0,0 +1,7 @@ +--- +title: "DebugGeography" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/ads/types/privacyoptionsrequirementstatus.md b/website/docs/controls/ads/types/privacyoptionsrequirementstatus.md new file mode 100644 index 0000000000..4a29bd56d8 --- /dev/null +++ b/website/docs/controls/ads/types/privacyoptionsrequirementstatus.md @@ -0,0 +1,7 @@ +--- +title: "PrivacyOptionsRequirementStatus" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/dropdownm2.md b/website/docs/controls/dropdownm2.md new file mode 100644 index 0000000000..e55db7ff94 --- /dev/null +++ b/website/docs/controls/dropdownm2.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.DropdownM2" +title: "DropdownM2" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/rawimage.md b/website/docs/controls/rawimage.md new file mode 100644 index 0000000000..e67cb159f5 --- /dev/null +++ b/website/docs/controls/rawimage.md @@ -0,0 +1,76 @@ +--- +class_name: "flet.RawImage" +examples: "controls/core/raw_image" +example_images: "test-images/examples/controls/core/golden/macos/raw_image" +title: "RawImage" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## `RawImage` vs `Image` + +Use [`Image`](/docs/controls/image) for pictures that come from a file, URL, +asset or a one-off byte string. Use `RawImage` when your Python code *produces* +pixels — Pillow drawings, NumPy arrays, camera frames, plots, procedural +animations — and you want to push them to the screen repeatedly and fast. + +Every update of `Image.src` travels through the regular Flet protocol and is +decoded from scratch on the client. `RawImage` instead streams frames over a +dedicated data channel: bytes skip the protocol entirely and, when the client +runs on the same machine (desktop app, `flet run`, Pyodide), frames are +transferred as raw RGBA pixels and uploaded straight to a GPU texture — no +image encoding or decoding on either side. Remote web clients automatically +receive compact PNG frames instead. + +The `render` methods are awaitable and resolve when the client has displayed +the frame, so a plain loop self-paces to display speed: + +```python +raw_image = ft.RawImage(expand=True) +page.add(raw_image) + +while True: + await raw_image.render(produce_pil_image()) +``` + +## Examples + +### Photo viewer + +Regular PNG/JPEG/WebP bytes — downloaded, read from a file or pulled from a +database — are displayed with `render_encoded`; the client decodes them with +its image codecs. + + + +### Plasma animation + +Streams a procedurally generated plasma effect with a live FPS counter and a +render-resolution slider. + + + +### Pillow paint + +An interactive paint app: pan gestures draw brush strokes onto a Pillow image +that is streamed to the screen through a dirty-flag render loop. + + + +### Mandelbrot explorer + +Click to zoom into the Mandelbrot set — every zoom is a burst of NumPy-rendered +frames computed in a background thread. + + + +### Game of Life + +Conway's Game of Life on a tiny grid upscaled with crisp nearest-neighbor +filtering; draw cells with the pointer while the simulation runs. + + + + diff --git a/website/docs/controls/spinkit/index.md b/website/docs/controls/spinkit/index.md index a48356dc91..d242104a18 100644 --- a/website/docs/controls/spinkit/index.md +++ b/website/docs/controls/spinkit/index.md @@ -38,6 +38,47 @@ Then import the package in your Flet app: import flet_spinkit as spins ``` +### Boot screen + +`flet-spinkit` also provides a [boot screen](../../publish/index.md#boot-screen) named +`spinkit` — an animated loader shown while your packaged app is starting up. Once +`flet-spinkit` is a dependency, select it in `pyproject.toml`: + +```toml +[tool.flet.boot_screen] +name = "spinkit" + +[tool.flet.boot_screen.spinkit] +spinner = "WanderingCubes" # any SpinKit animation (without the "SpinKit" prefix) +spinner_color_light = "#7c4dff" +spinner_color_dark = "#b388ff" +spinner_size = 60 +bgcolor_light = "#ffffff" +bgcolor_dark = "#0d0d12" +prepare_message = "Preparing your app…" +startup_message = "Starting up…" +``` + +All options are optional: + +| Option | Default | Description | +|--------|---------|-------------| +| `spinner` | `WanderingCubes` | Any SpinKit animation, named without the `SpinKit` prefix (e.g. `Wave`, `FadingCube`, `PouringHourGlass`). Case-insensitive. | +| `theme_mode` | `auto` | `auto` (follow device), `light`, or `dark`. | +| `bgcolor_light` / `bgcolor_dark` | Flet theme background | Background color. | +| `spinner_color_light` / `spinner_color_dark` | Flet theme primary | Spinner color. | +| `spinner_size` | `60` | Spinner size in logical pixels. | +| `text_color_light` / `text_color_dark` | Flet theme on-surface | Message text color. | +| `prepare_message` | none | Text shown while unpacking the app (Android only). | +| `startup_message` | none | Text shown while the Python runtime and app start. | +| `fade_out_duration` | `0` | Fade-out duration in milliseconds when the app becomes ready; `0` removes it instantly. | + +:::tip +This boot screen is a complete, real-world example of the +[`createBootScreen`](../../extend/user-extensions.md#boot-screen) extension hook — +see its source under `flet-spinkit`'s `src/flutter/flet_spinkit/lib/src/boot_screen.dart`. +::: + ## Examples diff --git a/website/docs/cookbook/colors.md b/website/docs/cookbook/colors.md index 73c1706d26..a442ab0ee1 100644 --- a/website/docs/cookbook/colors.md +++ b/website/docs/cookbook/colors.md @@ -2,7 +2,7 @@ title: "Working with Colors" --- - + Flet supports two primary ways of defining colors: @@ -20,7 +20,7 @@ Hex color values follow either of these formats: >>> ft.Container(bgcolor="#ff0000") ``` -## Named Color +## Named Colors Flet uses Material Design [theme colors](https://m3.material.io/styles/color-the-color-system/color-roles) and [color palettes](https://m2.material.io/design/color/the-color-system.html#color-usage-and-palettes). @@ -30,6 +30,8 @@ You can define named colors in two ways: * As a **string** (e.g., `"blue"`, `"redAccent100"`) * Using the `Colors` or `CupertinoColors` **enums** for better type safety and autocompletion +When using strings, use only Flet named color identifiers (the same set exposed by `Colors` / `CupertinoColors`), not arbitrary CSS-like color names. + ```python-repl >>> ft.Container(bgcolor="yellow") >>> ft.Container(bgcolor=ft.Colors.YELLOW) @@ -38,7 +40,7 @@ You can define named colors in two ways: ### Theme Colors - + There are 30 named theme colors in [`Theme.color_scheme`](../types/theme/index.md#flet.Theme.color_scheme) that are generated based on the [`Theme.color_scheme_seed`](../types/theme/index.md#flet.Theme.color_scheme_seed), which defaults to [`Colors.BLUE`](../types/colors.md#flet.Colors.BLUE). @@ -59,13 +61,13 @@ page.theme = ft.Theme( ) ``` - + Theme colors serve as fallback values for most Flet controls. ### Color Palettes - + Originally introduced by Material Design in 2014, **color palettes** are collections of coordinated colors designed to work together harmoniously. @@ -90,7 +92,7 @@ Flet provides multiple ways to set opacity: #### Using `with_opacity` This method is present in both [`Colors`](../types/colors.md) and [`CupertinoColors`](../types/cupertinocolors.md) enums. -It takes a [color](#) and an opacity, and returns a string in the format `"color,opacity"`, understood by Flet. +It takes an opacity and a [color](#), and returns a string in the format `"color,opacity"`, understood by Flet. ```python-repl >>> ft.Colors.with_opacity(0.5, ft.Colors.RED) @@ -114,13 +116,13 @@ For colors in hex format, you can specify the `aa` channel with values between ` Most Flet controls have default colors defined by the [`Theme.color_scheme`](../types/theme/index.md#flet.Theme.color_scheme), and these can be overridden at various levels. - + ### Control Level If a color is provided as value for a control's color-like property, it will be used directly. -```python +```python-repl >>> ft.Card(bgcolor=ft.Colors.GREEN_200) ``` diff --git a/website/docs/cookbook/flet-mcp.md b/website/docs/cookbook/flet-mcp.md new file mode 100644 index 0000000000..40ae34f2cc --- /dev/null +++ b/website/docs/cookbook/flet-mcp.md @@ -0,0 +1,131 @@ +--- +title: "Flet MCP server" +--- + +`flet-mcp` is an [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server +that gives LLM agents and AI coding assistants accurate, version-specific knowledge about +Flet. Instead of relying on the model's training data — which drifts out of date and leads +to hallucinated controls, properties, and enum members — the agent can look up the real +Flet API, search example projects, find icons, and inspect CLI options on demand. + +This is useful both inside AI-powered editors (Claude Desktop, Cursor, VS Code, ...) and +when building your own agents that generate or refactor Flet code. + +## Installation + +```bash +pip install flet-mcp +``` + +This registers a `flet mcp` command (the `flet` CLI must be installed, which it is in any +normal Flet project). The package ships with a pre-built API index, so no extra build step +is required to start using it. + +## Running the server + +Start the server over the default `stdio` transport (used by most desktop AI clients): + +```bash +flet mcp +``` + +Or expose it over HTTP: + +```bash +flet mcp --transport streamable-http --port 8000 +``` + +## Configuring an AI client + +Most MCP-aware clients are configured with a small JSON snippet. For example, in Claude +Desktop's `claude_desktop_config.json`: + +```json +{ + "mcpServers": { + "flet": { + "command": "flet", + "args": ["mcp"] + } + } +} +``` + +Cursor, VS Code, and other clients use the same `command` / `args` shape in their +respective MCP settings. + +## Tool groups + +Tools are organized into groups that you toggle with `FLET_MCP_ENABLE_*` environment +variables read at server startup. The defaults focus on the hallucination-reduction +starter set — **API** and **icons** are on, everything else is off: + +| Group | Variable | Default | Tools | +|---|---|---|---| +| API | `FLET_MCP_ENABLE_API` | on | `list_controls`, `get_api`, `get_enum`, `search_enum_members`, `enum_has_member` | +| Icons | `FLET_MCP_ENABLE_ICONS` | on | `find_icon` | +| Examples | `FLET_MCP_ENABLE_EXAMPLES` | off | `search_examples`, `get_example` | +| CLI | `FLET_MCP_ENABLE_CLI` | off | `get_cli_help` | + +Accepted truthy values are `1`, `true`, and `yes` (case-insensitive). To enable the +example search tools, for instance: + +```bash +FLET_MCP_ENABLE_EXAMPLES=1 flet mcp +``` + +The active groups are also surfaced in the server's startup instructions, so clients that +forward those instructions to the model keep its guidance in sync with what is actually +registered. + +:::note[Documentation search] +A documentation search group (`search_docs` / `get_doc`) is planned but not yet enabled — +it is being reworked to index the current Docusaurus-based docs site. +::: + +## What the tools do + +| Tool | Description | +|------|-------------| +| `get_api` | The primary verifier. Look up any Flet symbol by name — control, service, dataclass type (`ButtonStyle`, `Padding`, ...), event, or enum. A "not found" result is definitive for the installed Flet version. Async methods are flagged `"async": true`, and every entry carries a `"package"` field naming the pip package it lives in (`"flet"` for core, otherwise an extension like `"flet-audio"`). | +| `list_controls` | Browse available controls and services, with optional category/kind filtering. | +| `get_enum` | Get an enum's members. | +| `search_enum_members` | Search large enums (`Icons`, `CupertinoIcons`) by substring. | +| `enum_has_member` | Verify a specific enum member exists before using it. | +| `find_icon` | Search Material and Cupertino icons by keyword, with synonym matching (e.g. "user" finds `account_circle`). | +| `search_examples` | Search Flet example projects by keyword, optionally filtered by platform. | +| `get_example` | Fetch the full source and metadata for an example returned by `search_examples`. | +| `get_cli_help` | Get structured help for the `flet` CLI commands and their options. | + +## Using Flet MCP from your own agent + +The server is also importable as a [FastMCP](https://gofastmcp.com) instance, so a custom +agent can consume it directly. + +With [Pydantic AI](https://ai.pydantic.dev): + +```python +from pydantic_ai import Agent +from pydantic_ai.toolsets import MCPToolset +from flet_mcp import mcp + +agent = Agent("anthropic:claude-sonnet-4-6", toolsets=[MCPToolset(mcp)]) +result = agent.run_sync("Create a Flet app with a login form") +``` + +Or in-process via a FastMCP client — no subprocess, no transport. Set the +`FLET_MCP_ENABLE_*` variables before importing `flet_mcp` so the desired tool groups +register; the client deserializes structured results onto `.data`: + +```python +import asyncio +from fastmcp import Client +from flet_mcp import mcp + +async def main(): + async with Client(mcp) as client: + api = (await client.call_tool("get_api", {"name": "TextField"})).data + print(api["kind"], api["package"], len(api["properties"])) + +asyncio.run(main()) +``` diff --git a/website/docs/cookbook/multiprocessing.md b/website/docs/cookbook/multiprocessing.md new file mode 100644 index 0000000000..d2963ef488 --- /dev/null +++ b/website/docs/cookbook/multiprocessing.md @@ -0,0 +1,169 @@ +--- +title: "Multiprocessing" +--- + +import {CodeExample} from '@site/src/components/crocodocs'; + +In this cookbook recipe, you'll learn how to use Python's built-in +[`multiprocessing`](https://docs.python.org/3/library/multiprocessing.html) module — +including [`concurrent.futures.ProcessPoolExecutor`](https://docs.python.org/3/library/concurrent.futures.html#processpoolexecutor) — +from a Flet app, for true CPU parallelism across processes. + +For I/O-bound work, or work that just needs to stay off the UI thread, prefer +[async or threads](async-apps.md) — they are lighter and work on every platform. +Reach for `multiprocessing` when you need multiple CPU cores doing Python work +at the same time (number crunching, batch processing, ML inference, etc.), or +when you need process isolation for work that may fail or need to be stopped. + +:::important[Platform and Flet version support] +`multiprocessing` works in Flet desktop apps during development ([`flet run`](../cli/flet-run.md)) and +in packaged **desktop** apps built with [`flet build {macos,windows,linux}`](../cli/flet-build.md) +or [`flet debug {macos,windows,linux}`](../cli/flet-debug.md) when using [Flet v0.86.0](../updates/release-notes.md#086x) or newer. + +It is **not supported on iOS and Android** (mobile operating systems don't +allow apps to spawn arbitrary child processes) or **in the browser**. On those +platforms, prefer threads or `asyncio` instead. +::: + +## How does it work? + +In a desktop app packaged with [`flet build`](../publish/index.md), there is no separate `python` executable — +the interpreter is embedded inside your app's binary. When `multiprocessing` spawns a +worker, it re-executes that binary with a CPython helper command line; the binary +recognizes that shape and services it as a plain, windowless Python interpreter. +This also covers multiprocessing's helper processes (the resource tracker and the `forkserver`). + +## Guidelines + +These are standard +[Python `multiprocessing` guidelines](https://docs.python.org/3/library/multiprocessing.html#programming-guidelines) +— but in a packaged Flet app they are **mandatory**, not just good style. + +### Always guard your entry point + +Start your app only under the `if __name__ == "__main__":` guard. For example: + +```python +import flet as ft + +def main(page: ft.Page): + ... + +if __name__ == "__main__": + ft.run(main) +``` + +With the `spawn` and `forkserver` start methods, worker/helper processes need +to safely import your main module. `spawn` is the default on macOS and Windows; +`forkserver` is the default on Linux starting with Python 3.14. Without the +guard, a child process can try to start your whole app again. + +### Use importable, picklable worker functions + +Worker targets, arguments, and return values must be picklable so Python can +send them between processes. In practice: + +* define worker functions at module top level, not inside `main()` or inside a + button handler +* pass plain data such as numbers, strings, lists, dicts, or dataclasses +* do not pass Flet controls, `page`, database connections, open files, lambdas, + or nested functions + +Good: + +```python +def sort_chunk(chunk): + return sorted(chunk) +``` + +Avoid: + +```python +def main(page: ft.Page): + def sort_chunk(chunk): + return sorted(chunk) +``` + +The nested version is not reliably picklable because worker processes need to +import the function by name from a module. + +### Don't touch the GUI from workers + +Worker processes run in a separate interpreter with no connection to your app's +page. Pass data back through [`multiprocessing.Queue`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Queue), +[`Pipe`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Pipe), or +[pool futures](https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Future), +and update the UI from the main process. + +### Others + +- [`sys.executable`](https://docs.python.org/3/library/sys.html#sys.executable) in a packaged app points at your app's binary, not a + `python` executable. That is intentional — don't override it with + [`multiprocessing.set_executable()`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.set_executable). +- You usually do not need [`multiprocessing.freeze_support()`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.freeze_support) in Flet apps. + Calling it inside the `if __name__ == "__main__":` block is harmless, but Flet + does not rely on PyInstaller-style frozen-executable bootstrapping. +- Worker `print()` output is not connected to your app's console log; use a + [`Queue`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Queue) or file-based logging if you need worker diagnostics. +- On Linux, avoid forcing the `fork` [start method](https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods): + your app's process runs the Flutter engine with many active threads, and forking it is unsafe. + Prefer the platform default (usually `forkserver` or `spawn`), or request one explicitly with + [`multiprocessing.set_start_method()`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.set_start_method) + or [`multiprocessing.get_context()`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.get_context). +- Starting a worker costs more in a packaged app than in plain Python — each + spawned child loads your app binary's libraries before Python takes over. + Create pools and long-lived workers once and reuse them, rather than spawning + per button click (see [Keep a persistent worker](#keep-a-persistent-worker) example). + +## Examples + +### Parallel sort with live progress + +Sort chunks of data across all CPU cores and stream progress to the page: + + + +Note how the long-running orchestration is moved off the UI event handler with +[`page.run_thread`](async-apps.md#threading), while the CPU-heavy work runs in the +process pool. The worker function may live in your main module (as above) or in +a separate importable module — both work. + +### Stream progress from a worker + +To show fine-grained progress from inside a single long-running job, pass a +[`multiprocessing.Queue`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Queue) +to the worker and drain it on a background thread. The worker [`put()`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Queue.put)s progress +values and a `None` sentinel when it is done: + + + +### Keep a persistent worker + +Starting a process is not free — especially in a packaged app, where each child +loads your app binary's libraries first. For repeated jobs, start one worker +that stays alive and serves requests over a +[`Pipe`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Pipe), +paying the startup cost once. Expensive setup (loading a model, opening a +dataset) can then also happen once, in the worker: + + + +The worker is started with `daemon=True`, so it is terminated automatically +when your app exits. + +### Cancel a runaway task + +Threads cannot be forcefully stopped from the outside — a worker [`Process`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Process) can, +at any time, with [`terminate()`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Process.terminate). +This makes processes the right tool for jobs you may need to abort, such as +long calls into external libraries: + + + +A background thread [`join()`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Process.join)s the worker and reports how it ended — normally +(exit code `0`) or via cancellation (a negative exit code). + +:::info +[Python's multiprocessing guidelines](https://docs.python.org/3/library/multiprocessing.html#programming-guidelines) +recommend avoiding process termination or doing it only for processes which never use any shared resources. +::: diff --git a/website/docs/cookbook/read-and-write-files.md b/website/docs/cookbook/read-and-write-files.md index 330f231a1f..e2eb53cf1d 100644 --- a/website/docs/cookbook/read-and-write-files.md +++ b/website/docs/cookbook/read-and-write-files.md @@ -9,19 +9,33 @@ Flet makes it easy to work with files and directories on the mobile/desktop devi ### Storage Paths -Flet provides two directory paths for data storage, available as environment variables: -[`FLET_APP_STORAGE_DATA`](../reference/environment-variables.md#flet_app_storage_data) and -[`FLET_APP_STORAGE_TEMP`](../reference/environment-variables.md#flet_app_storage_temp). +Flet provides three pre-created, app-private directory paths as environment variables: -Their values can be gotten as follows: +- [`FLET_APP_STORAGE_DATA`](../reference/environment-variables.md#flet_app_storage_data) — **durable** + data (databases, state, config). Preserved across app updates and backed up; the OS never deletes it. + This is also the program's current working directory, so relative writes land here. +- [`FLET_APP_STORAGE_CACHE`](../reference/environment-variables.md#flet_app_storage_cache) — + **regenerable** cache. The OS may purge it; only store things you can rebuild. +- [`FLET_APP_STORAGE_TEMP`](../reference/environment-variables.md#flet_app_storage_temp) — **throwaway** + scratch (the OS temp dir). May vanish between launches. + +Use `FLET_APP_STORAGE_DATA` for anything you must keep — putting a database in cache or temp risks +silent data loss. + +Their values can be read as follows: ```python import os app_data_path = os.getenv("FLET_APP_STORAGE_DATA") +app_cache_path = os.getenv("FLET_APP_STORAGE_CACHE") app_temp_path = os.getenv("FLET_APP_STORAGE_TEMP") ``` +Because `FLET_APP_STORAGE_DATA` is the working directory, a relative path like `"counter.txt"` resolves +inside it; use `os.path.join(app_data_path, ...)` if you want to be explicit. The same behavior applies +under `flet run` (the dev working directory is `/.flet/storage/data`). + ### Writing to a File To write data to a new/existing file, you can use the built-in [`open`](https://docs.python.org/3/library/functions.html#open) function. diff --git a/website/docs/extend/user-extensions.md b/website/docs/extend/user-extensions.md index efcf1ada06..586d5436a3 100644 --- a/website/docs/extend/user-extensions.md +++ b/website/docs/extend/user-extensions.md @@ -464,6 +464,291 @@ Common pitfalls: You can find source code for this example [here](https://github.com/flet-dev/flet-spinkit). +## Dedicated data channels + +Property updates and method calls between Python and Dart go over Flet's MsgPack-framed control protocol. That works well for widget state and small events but caps at ~1 GB/s with several allocations per frame. For widgets that need to move **bulk binary data** — image frames, audio buffers, file blobs, ML inference tensors — Flet provides **dedicated `DataChannel`s** that bypass MsgPack entirely and reach memory-bandwidth-class throughput on every supported platform. + +Examples of widgets that benefit: + +- A chart receiving a stream of bitmaps from Python (1080p RGBA at 60 fps ≈ 480 MB/s — far above what the control protocol can sustain) +- A camera widget pushing frames Dart → Python for ML inference +- A microphone widget streaming PCM samples to a Python DSP pipeline + +For sub-KB widget state, you don't need this — the regular property protocol is faster end-to-end at that size. Reach for `DataChannel` when payloads start at a few KB and especially when they stream at high rates. + +### How it works + +Allocation lives on the **Dart side**: the widget calls `FletBackend.of(context).openDataChannel()` in `initState`, then **fires a control event named `data_channel_open`** carrying `{channel_name, channel_id}`. The Python side declares an `on_data_channel_open` handler, retrieves the matching channel via `Control.get_data_channel(channel_id)`, and starts sending/receiving bytes. + +Transport is chosen per deployment mode automatically — dedicated `PythonBridge` per channel in embedded native (`flet build` for desktop/mobile), raw-byte frames muxed over `postMessage` with Transferable ArrayBuffer in Pyodide, muxed over the protocol socket in `flet run` dev mode, muxed over WebSocket with a Python server. **Widget code is identical across all modes.** + +### Python-side API + +```python +from typing import Callable, Optional + +import flet as ft + + +@ft.control("MyImageChart") +class MyImageChart(ft.LayoutControl): + on_data_channel_open: Optional[ft.EventHandler[ft.DataChannelOpenEvent]] = None + + def init(self) -> None: + # `init` is the @ft.control post-construct hook (runs before `did_mount`). + # Wire up the channel-capture handler here. + self._frames: Optional[ft.DataChannel] = None + if self.on_data_channel_open is None: + self.on_data_channel_open = self._capture_channel + + def _capture_channel(self, e: ft.DataChannelOpenEvent) -> None: + # `e.channel_name` is the label the Dart side put in the event + # payload — dispatch on it when a widget opens multiple channels. + # Single-channel widgets can ignore it. + self._frames = self.get_data_channel(e.channel_id) + # Optional: subscribe to bytes flowing Dart → Python. + self._frames.on_bytes(self._on_frame_from_dart) + + def push_frame(self, rgba_bytes: bytes) -> None: + """Python → Dart — fire-and-forget byte send.""" + if self._frames is not None: + self._frames.send(rgba_bytes) + + def _on_frame_from_dart(self, payload: bytes) -> None: + # Called from the transport's delivery thread (under the GIL in + # embedded native mode). Push to a `queue.Queue` and let a worker + # drain — don't do heavy CPU work here, it'll starve the transport. + ... +``` + +`ft.DataChannel` is an abstract class — instances come back from `Control.get_data_channel(channel_id)`. Its surface: + +- `send(payload: bytes)` — Python → Dart, fire-and-forget +- `on_bytes(callback: Callable[[bytes], None] | None)` — register a handler for bytes pushed from Dart; pass `None` to clear +- `close()` — release the channel (idempotent; the framework auto-closes on control unmount, you rarely need to call it explicitly) + +The `ft.DataChannelOpenEvent` fields are `channel_name: str` and `channel_id: int`. The field is `channel_name`, not `name`, because `name` is reserved on the base `Event` class for the event's own name (`"data_channel_open"`). + +### Dart-side API + +```dart +import 'package:flet/flet.dart'; + +class MyImageChartState extends State { + late final DataChannel _frames; + StreamSubscription? _sub; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + if (_sub != null) return; // initialise lazily, once + _frames = FletBackend.of(context).openDataChannel(); + _sub = _frames.messages.listen(_onFrameFromPython); + // Tell Python about the channel via a regular control event. + widget.control.triggerEvent("data_channel_open", { + "channel_name": "frames", + "channel_id": _frames.id, + }); + } + + void _onFrameFromPython(Uint8List bytes) { + // hand to a Texture, dart:ui.Image.fromPixels, etc. + } + + void _pushFrameToPython(Uint8List bytes) { + _frames.send(bytes); + } + + @override + void dispose() { + _sub?.cancel(); + _frames.close(); + super.dispose(); + } +} +``` + +`DataChannel` Dart-side surface: + +- `int get id` — the channel identifier that goes into the `data_channel_open` event payload +- `Stream get messages` — bytes pushed from Python +- `bool send(Uint8List bytes)` — Dart → Python, fire-and-forget +- `void close()` — release the channel (idempotent) + +**Allocate the channel in `didChangeDependencies`, not `initState`** — `FletBackend.of(context)` needs an active `BuildContext` and that's the first lifecycle hook where it's safely available. + +Neither side imports `serious_python` or `dart_bridge`. The DataChannel API surface lives entirely in `package:flet` / `flet`, so your extension's dependencies stay the same. + +### Multiple channels per widget + +A control can open as many channels as it needs — each `openDataChannel()` call mints a unique id. Disambiguate them by `channel_name` in the event: + +```dart +// Dart — open two channels, label each +_frames = FletBackend.of(context).openDataChannel(); +_audio = FletBackend.of(context).openDataChannel(); +widget.control.triggerEvent("data_channel_open", { + "channel_name": "frames", + "channel_id": _frames.id, +}); +widget.control.triggerEvent("data_channel_open", { + "channel_name": "audio", + "channel_id": _audio.id, +}); +``` + +```python +# Python — dispatch on channel_name +def _on_data_channel_open(self, e: ft.DataChannelOpenEvent) -> None: + match e.channel_name: + case "frames": + self._frames = self.get_data_channel(e.channel_id) + case "audio": + self._audio = self.get_data_channel(e.channel_id) +``` + +### Threading + backpressure + +The `on_bytes` handler runs **synchronously under the GIL** on whatever OS thread the transport delivered from. For anything CPU-heavy (PNG decode, ML inference) push the payload onto a `queue.Queue` or `asyncio.Queue` and let a worker drain — blocking the delivery thread will starve the transport. + +The receiving side's queue is **unbounded by default**. If a producer outpaces the consumer (camera frames into a slow decoder, matplotlib rotation into Flutter paint), memory grows. For media-streaming widgets, implement backpressure or a drop-old policy on the producer side. A reference example is [`MatplotlibChartCanvas`](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart_canvas.py) — it uses a 1-byte ack frame from Dart so the producer waits per-frame, mirroring matplotlib WebAgg's `waiting` flag pattern. + +### See also + +- **First-party reference widget**: `MatplotlibChartCanvas` — a complete migration from `_invoke_method` PNG dispatch to a 1-byte-opcode data channel, including backpressure ack and the GPU / CPU rendering strategies. [Python](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart_canvas.py) · [Dart](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/matplotlib_chart_canvas.dart) +- **Full design / performance notes** (wire format, cross-mode operation, concurrency model, empirical numbers): [`dedicated-data-channels.md`](https://github.com/flet-dev/serious-python/blob/main/docs/dedicated-data-channels.md) in `flet-dev/serious-python`. +- **Wire-format protocol upgrade** for anyone implementing a custom Flet backend or sidecar: [Flet protocol framing upgraded for DataChannel support](/docs/updates/breaking-changes/v0-86-0/data-channel-protocol-upgrade). + +## Boot screen + +An extension can provide a custom **boot screen** — the screen shown while your +packaged app is starting, before the first page appears (see +[Boot screen](../publish/index.md#boot-screen) in the publishing guide for the +end-user/configuration side). This lets you fully brand the launch experience, +including custom layouts and animations, instead of using the built-in `flet` +screen. + +### The `createBootScreen` hook + +Override `createBootScreen` on your `FletExtension` (in `src/extension.dart`). A +single extension can serve multiple named screens: + +```dart +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'my_boot_screen.dart'; + +class Extension extends FletExtension { + @override + Widget? createBootScreen(String name, Map options, + ValueListenable status) { + switch (name) { + case "my_screen": + return MyBootScreen(options: options, status: status); + default: + return null; // not handled — Flet tries the next extension, then the built-in "flet" screen + } + } +} +``` + +The hook receives: + +- **`name`** — the configured screen name (from `[tool.flet.boot_screen].name`). + Return `null` for names you don't handle. +- **`options`** — the `[tool.flet.boot_screen.]` table from `pyproject.toml` + as a `Map`. Put whatever options your screen needs there. +- **`status`** — a `ValueListenable` that reports the current boot + state. Watch it with a `ValueListenableBuilder` to update the UI live. + +`BootStatus` carries: + +| Field | Type | Description | +|-------|------|-------------| +| `stage` | `BootStage` | `BootStage.preparing` (unpacking the app bundle — Android only) or `BootStage.startingUp` (Python runtime + app starting). | +| `error` | `String?` | Non-null when startup failed; the message is ready for display. | + +### Example widget + +```dart +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +class MyBootScreen extends StatelessWidget { + final Map options; + final ValueListenable status; + + const MyBootScreen({super.key, required this.options, required this.status}); + + @override + Widget build(BuildContext context) { + // Read options from pyproject.toml. Colors accept hex (#rrggbb) or named + // colors via Flet's HexColor helper. + final bgcolor = + HexColor.fromString(null, options["bgcolor"] as String?) ?? Colors.black; + + return ValueListenableBuilder( + valueListenable: status, + builder: (context, boot, _) { + if (boot.error != null) { + return Scaffold( + backgroundColor: bgcolor, + body: Center( + child: Text(boot.error!, + style: const TextStyle(color: Colors.redAccent)), + ), + ); + } + final message = boot.stage == BootStage.preparing + ? "Preparing…" + : "Starting up…"; + return Scaffold( + backgroundColor: bgcolor, + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const CircularProgressIndicator(), + const SizedBox(height: 16), + Text(message, style: const TextStyle(color: Colors.white)), + ], + ), + ), + ); + }, + ); + } +} +``` + +Then select your screen by name in the app's `pyproject.toml`: + +```toml +[tool.flet.boot_screen] +name = "my_screen" + +[tool.flet.boot_screen.my_screen] +bgcolor = "#101020" +``` + +:::note +In a packaged app, the boot screen is rendered by a persistent host overlay so +your widget is **not** remounted between the prepare and startup phases — the +same instance (and its animations) is reused, and the host fades it out when the +app is ready. Drive your UI from `status`, and don't rely on the app's `Theme` +for colors during the prepare phase — read them from `options` so the screen +looks consistent throughout. The host also reads `fade_out_duration` (ms) from +your `options` to control that fade-out. +::: + +:::tip[Real-world example] +The [`flet-spinkit`](../controls/spinkit/index.md#boot-screen) extension ships a +complete `spinkit` boot screen built exactly this way — see +[`boot_screen.dart`](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-spinkit/src/flutter/flet_spinkit/lib/src/boot_screen.dart) +and its [`extension.dart`](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-spinkit/src/flutter/flet_spinkit/lib/src/extension.dart). +::: + ## Examples Flet has controls that are implemented as [built-in extensions](built-in-extensions.md) and could serve as a starting point for your own controls. diff --git a/website/docs/getting-started/integration-testing.md b/website/docs/getting-started/integration-testing.md new file mode 100644 index 0000000000..e155ac104b --- /dev/null +++ b/website/docs/getting-started/integration-testing.md @@ -0,0 +1,404 @@ +--- +title: "Integration testing" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +Flet lets you write **integration tests** for your app and run them with the +[`flet test`](../cli/flet-test.md) command. Tests drive your app the same way a +user would — finding controls by key or text, tapping buttons, entering text and +asserting the resulting UI — while the app runs **on the target device** exactly +as it ships: a built monolithic app with embedded Python. + +Tests are written with [`pytest`](https://docs.pytest.org), so everything you +already know about pytest (fixtures, parametrization, markers, `-k` filtering) +just works. + +:::note[Prerequisites] +`flet test` builds and runs your app the same way [`flet build`](../cli/flet-build.md) +does, so the [Flutter SDK and build prerequisites](../publish/index.md) must be +installed. The first run provisions a test host (and downloads the SDK if +needed), which is slow; subsequent runs are cached and fast. +::: + +## Where tests live + +Put your tests in a `tests/` directory at the **root of your app** — a sibling of +`src/`, not inside it (`src/` is what gets packaged into the on-device app; your +test code stays on the host and drives the app): + +``` +my_app/ +├── pyproject.toml +├── src/ +│ └── main.py # your app +└── tests/ + └── test_main.py # your tests +``` + +A new app created with [`flet create`](../cli/flet-create.md) already includes a +`tests/` folder with a sample test and the required pytest configuration in +`pyproject.toml`: + +```toml +[tool.pytest.ini_options] +asyncio_mode = "auto" +testpaths = ["tests"] +``` + +## Enabling tests in an existing app + +If your app wasn't created with `flet create`, enable testing by editing its +`pyproject.toml`. + +**1. Add the test dependencies** to your development dependencies. The +`flet[test]` extra brings in `pytest`, `pytest-asyncio` and the +screenshot-comparison libraries: + + + +```toml +[dependency-groups] +dev = [ + # ...your existing dev dependencies... + "flet[test]", +] +``` + + +```toml +[project.optional-dependencies] +dev = [ + # ...your existing dev dependencies... + "flet[test]", +] +``` + + + +**2. Configure pytest.** `asyncio_mode = "auto"` is **required** — it runs each +async test on the same event loop as the `flet_app` fixture: + +```toml +[tool.pytest.ini_options] +asyncio_mode = "auto" +testpaths = ["tests"] +``` + +**3. Create a `tests/` directory** and add your first test (see +[Writing a test](#writing-a-test) below). + +## Writing a test + +Test functions are `async` and receive the [`flet_app`][flet.testing.FletTestApp] +fixture, which starts your app and exposes a [tester][flet.testing.Tester] to +drive it. Each test gets a **fresh app instance**, so tests are independent and +can run in any order. + +Here is the counter sample (`tests/test_main.py`) that `flet create` generates: + +```python title="tests/test_main.py" +import flet.testing as ftt + + +async def test_increment(flet_app: ftt.FletTestApp): + tester = flet_app.tester + + await tester.pump_and_settle() + + # Initial state + assert (await tester.find_by_text("0")).count == 1 + + # Tap the increment button (found by its key) and let the UI update + await tester.tap(await tester.find_by_key("increment")) + await tester.pump_and_settle() + + # New state + assert (await tester.find_by_text("1")).count == 1 +``` + +The matching app gives the button a `key` so the test can find it reliably: + +```python title="src/main.py" +import flet as ft + + +def main(page: ft.Page): + counter = ft.Text("0", size=50, data=0) + + def increment_click(e): + counter.data += 1 + counter.value = str(counter.data) + + page.floating_action_button = ft.FloatingActionButton( + icon=ft.Icons.ADD, key="increment", on_click=increment_click + ) + page.add( + ft.SafeArea( + expand=True, + content=ft.Container(content=counter, alignment=ft.Alignment.CENTER), + ) + ) + + +ft.run(main) +``` + +:::tip +Give controls you want to test a stable [`key`](../cookbook/control-refs.md) and +find them with [`find_by_key()`][flet.testing.Tester.find_by_key]. It's more +robust than matching on text, which can change with localization or formatting. +::: + +## The tester API + +[`flet_app.tester`][flet.testing.FletTestApp.tester] finds controls and drives +interactions. **Finder** methods return a [`Finder`][flet.testing.Finder]; +**action** methods take a `Finder`; and **pump** methods let the UI advance. All +methods are awaitable. + +### Finding controls + +| Method | Finds controls by | +| --- | --- | +| [`find_by_key(key)`][flet.testing.Tester.find_by_key] | their `key` | +| [`find_by_text(text)`][flet.testing.Tester.find_by_text] | exact text | +| [`find_by_text_containing(pattern)`][flet.testing.Tester.find_by_text_containing] | a regular-expression match on text | +| [`find_by_icon(icon)`][flet.testing.Tester.find_by_icon] | their icon (e.g. `ft.Icons.ADD`) | +| [`find_by_tooltip(value)`][flet.testing.Tester.find_by_tooltip] | tooltip text | + +A [`Finder`][flet.testing.Finder] reports how many controls matched (via +[`count`][flet.testing.Finder.count]) and lets you pick one with +[`first`][flet.testing.Finder.first], [`last`][flet.testing.Finder.last] or +[`at()`][flet.testing.Finder.at]: + +```python +finder = await tester.find_by_text("Item") +assert finder.count == 3 # number of matches +await tester.tap(finder.first) # first match +await tester.tap(finder.last) # last match +await tester.tap(finder.at(1)) # match at index 1 +``` + +### Interacting + +| Method | Action | +| --- | --- | +| [`tap(finder)`][flet.testing.Tester.tap] | tap a control | +| [`long_press(finder)`][flet.testing.Tester.long_press] | long-press a control | +| [`enter_text(finder, text)`][flet.testing.Tester.enter_text] | type text into a field | +| [`mouse_hover(finder)`][flet.testing.Tester.mouse_hover] | hover the mouse over a control | + +### Pumping + +The UI doesn't update instantly after an interaction. Call +[`pump_and_settle()`][flet.testing.Tester.pump_and_settle] to let the app process +events and render the result before asserting: + +```python +await tester.tap(await tester.find_by_key("submit")) +await tester.pump_and_settle() +assert (await tester.find_by_text("Done")).count == 1 +``` + +Use [`pump(duration=...)`][flet.testing.Tester.pump] to advance by a fixed amount +when you don't want to wait for everything to settle. + +## Screenshot testing + +On **Android and iOS** you can capture a full-screen screenshot of the running +app and compare it against a committed *golden* (reference) image — useful for +catching visual regressions. Full-screen capture is a device feature, so this is +**not available on desktop**. + +[`tester.take_screenshot(name)`][flet.testing.Tester.take_screenshot] captures +the screen as PNG bytes, and +[`flet_app.assert_screenshot(name, bytes)`][flet.testing.FletTestApp.assert_screenshot] +compares them against the golden image, failing the test if they differ beyond a +similarity threshold (≈99% by default): + +```python +async def test_home_screen(flet_app: ftt.FletTestApp): + tester = flet_app.tester + await tester.pump_and_settle() + + flet_app.assert_screenshot("home", await tester.take_screenshot("home")) +``` + +Golden images are **platform-specific** and stored next to your tests, under +`tests/golden///.png` — commit them to your repository. + +To record the goldens the first time (or update them after an intentional UI +change), run with `-u` (`--update-goldens`). This writes the captured screenshots +as the new reference **instead of** comparing: + + + +```bash +uv run flet test android --device-id emulator-5554 -u +``` + + +```bash +flet test android --device-id emulator-5554 -u +``` + + + +:::tip +Render each screenshot on the same device/emulator you record its golden on — +different screen sizes and densities produce different pixels. +::: + +## Running tests + +### On desktop + +From your app directory, run [`flet test`](../cli/flet-test.md). With no +arguments it targets the **current desktop** platform: + + + +```bash +uv run flet test +``` + + +```bash +flet test +``` + + + +### On a mobile emulator/simulator or device + +First, make sure a device is running. Use +[`flet emulators`](../cli/flet-emulators.md) to list available emulators and +start one, then [`flet devices`](../cli/flet-devices.md) to get the id of a +running device: + + + +```bash +uv run flet emulators # list available emulators +uv run flet emulators start # start an emulator +uv run flet devices # list running devices and their ids +``` + + +```bash +flet emulators # list available emulators +flet emulators start # start an emulator +flet devices # list running devices and their ids +``` + + + +Then pass the platform as the first argument and the device id with +`--device-id` (`-d`): + + + +```bash +uv run flet test android --device-id emulator-5554 +uv run flet test ios --device-id +``` + + +```bash +flet test android --device-id emulator-5554 +flet test ios --device-id +``` + + + +### Useful options + +| Option | Description | +| --- | --- | +| `[platform]` | `macos`, `linux`, `windows`, `ios`, `android` (defaults to the current desktop) | +| `-d`, `--device-id` | Target device/emulator id (required for `ios`/`android`) | +| `-k ` | Only run tests matching a pytest keyword expression | +| `--tests-dir ` | Directory containing the tests (default: `tests`) | +| `-v` | Verbose — stream the underlying Flutter build/launch output | + +### Running specific tests + +Use `-k` to run only the tests matching a pytest keyword expression — handy while +iterating on a single test: + + + +```bash +uv run flet test -k test_screenshot +``` + + +```bash +flet test -k test_screenshot +``` + + + +`-k` accepts the full pytest expression syntax, e.g. `-k screenshot`, +`-k "increment or screenshot"`, or `-k "not slow"`. + +When [running with pytest directly](#running-with-pytest-directly) you can also +select a test by its node id: + +```bash +uv run pytest tests/test_main.py::test_increment # a single test +uv run pytest tests/test_main.py # one file +``` + +### Running with pytest directly + +Because tests are plain pytest, you can also run them with `pytest`. The Flet +pytest plugin provisions the test host on demand, so this works without running +`flet test` first (it targets the current desktop platform): + + + +```bash +uv run pytest +``` + + +```bash +pytest +``` + + + +To see the live build/launch output (and the app's `debugPrint`s) while running +under pytest, enable CLI logging at debug level: + +```bash +uv run pytest -s -o log_cli=true -o log_cli_level=DEBUG +``` + +`pytest` has no options of its own for the device target or goldens, so the +`flet test` options map to environment variables: + +| `flet test` option | Environment variable | +| --- | --- | +| `[platform]` | `FLET_TEST_PLATFORM` (e.g. `ios`, `android`) | +| `-d`, `--device-id` | `FLET_TEST_DEVICE` | +| `-u`, `--update-goldens` | `FLET_TEST_GOLDEN=1` | + +```bash +# run on an iOS simulator and (re)record golden screenshots +FLET_TEST_PLATFORM=ios FLET_TEST_DEVICE= FLET_TEST_GOLDEN=1 uv run pytest +``` + +When unset, `pytest` targets the current desktop platform and compares (rather +than records) screenshots. + +:::note[How it works] +`flet test` provisions a Flutter test host from your app (the same pipeline as +`flet build`), embeds your Python code, and runs it on the device. The test code +runs on your computer and drives the on-device app over an independent channel — +so you're testing your app exactly as it ships, including the embedded Python +runtime, not a simulated approximation. +::: diff --git a/website/docs/publish/android.md b/website/docs/publish/android.md index fdd4207de4..d441da011e 100644 --- a/website/docs/publish/android.md +++ b/website/docs/publish/android.md @@ -72,12 +72,23 @@ requires distributing the correct APK for each device. #### Supported target architectures -The following target architectures are supported: +The following target architectures are supported, for every +[bundled Python version](index.md#choosing-a-python-version): -- [`arm64-v8a`](https://developer.android.com/ndk/guides/abis#arm64-v8a) -- [`armeabi-v7a`](https://developer.android.com/ndk/guides/abis#v7a) -- [`x86_64`](https://developer.android.com/ndk/guides/abis#86-64) -- [`x86`](https://developer.android.com/ndk/guides/abis#x86) +- [`arm64-v8a`](https://developer.android.com/ndk/guides/abis#arm64-v8a) (64-bit) +- [`x86_64`](https://developer.android.com/ndk/guides/abis#x86-64) (64-bit) +- [`armeabi-v7a`](https://developer.android.com/ndk/guides/abis#v7a) (32-bit) + +The 32-bit `x86` ABI is not supported — specifying it fails the build since Flet 0.86.0 +(see the [migration guide](../updates/breaking-changes/v0-86-0/android-x86-arch-removed.md)). + +:::note +Flet bundles [its own CPython builds](https://github.com/flet-dev/python-build) for +Android, published for all three ABIs on every supported Python version — including +32-bit `armeabi-v7a`, which upstream CPython dropped in 3.13 +([PEP 738](https://peps.python.org/pep-0738/)). By default, an app is built for all +supported architectures. +::: #### Resolution order @@ -87,8 +98,9 @@ Its value is determined in the following order of precedence: 2. `[tool.flet.android].split_per_abi` 3. `false` -When enabled, 3 APKs are produced by default, one for each of the following ABIs: `arm64-v8a`, -`armeabi-v7a`, and `x86_64`. These can be customized by setting [`target architectures`](index.md#target-architecture). +When enabled, one APK is produced per ABI — by default, one for each +architecture the bundled Python version supports (see above). These can be +customized by setting [`target architectures`](index.md#target-architecture). #### Example @@ -763,6 +775,97 @@ adaptive_icon_background = "#0B6BFF" ``` + +## Extract packages + +On Android, pure Python code is packaged into stored zip assets and imported in place with +[`zipimport`](https://docs.python.org/3/library/zipimport.html). Native extension modules are +loaded memory-mapped directly from the APK. This keeps APKs smaller and avoids unpacking all +site-packages on first launch. + +Most packages work from inside the zip. But packages that read bundled **data files** through a real +filesystem path — for example with `__file__` or `pkg_resources`, instead of the zip-safe +[`importlib.resources`](https://docs.python.org/3/library/importlib.resources.html) — may fail at +runtime because their data lives inside `sitepackages.zip`, where plain `open()` cannot read it. + +List such packages in `extract_packages` to ship them extracted to the app's files directory +instead of inside `sitepackages.zip`. Flet extracts the listed package directories and everything +under them, so `__file__`-relative reads work again. + +Most packages that bundle data (such as `flet` or `certifi`) read it through `importlib.resources`, which +is zip-safe, so they need no entry here. Only add packages that actually fail to find their data +when imported from the zip. + +### Symptoms + +The build succeeds, but the app crashes or errors on the device when the package is imported or +first used. The traceback usually contains a path where `sitepackages.zip` or `stdlib.zip` appears +as a directory component, for example (`matplotlib`): + +```bash +FileNotFoundError: [Errno 2] No such file or directory: + '/data/user/0//files/.../sitepackages.zip/matplotlib/mpl-data/matplotlibrc' +``` + +`NotADirectoryError` or `OSError` with a similar `sitepackages.zip/...` path is also a common sign +that the package computed a data path from `__file__` and tried to read it as a regular file. + +If this happens with one of your dependencies, add that package to `extract_packages` and consider +reporting it in [Flet discussions](https://github.com/flet-dev/flet/discussions) or opening a PR so +it can be added to the known packages list. + +### Resolution order + +1. [`--android-extract-packages`](../cli/flet-build.md#--android-extract-packages) +2. `[tool.flet.android].extract_packages` +3. `[tool.flet].extract_packages` + +### Example + +Each entry is the package's **import name** — its top-level directory under site-packages — not +necessarily its PyPI distribution name. For example, use `sklearn`, not `scikit-learn`; use `cv2`, +not `opencv-python`. + + + +```bash +flet build apk --android-extract-packages package1 package2 +``` + + +```toml +[tool.flet.android] +extract_packages = ["package1", "package2"] +``` + + + +### Wildcards + +An entry is a path relative to site-packages and matches that path and everything under it. +Entries may also contain `*` and `?` wildcards, matched against the top-level directory name: + +```toml +[tool.flet.android] +extract_packages = ["somepackage*"] +``` + +The wildcard form can also extract a sibling `somepackage-.dist-info/` directory. +Use it for packages that read their metadata or data files through `pkg_resources`. + +### Affected packages + +Below are known packages that need to be extracted to work on Android: + +| Package (PyPI) | Entry | Reason | +|-----------------|--------------------|----------------------------------------------------------------------------------------| +| `matplotlib` | `"matplotlib"` | reads `mpl-data` (fonts, `matplotlibrc`) relative to `__file__` | +| `scikit-learn` | `"sklearn"` | loads bundled data files through `__file__`-relative paths | +| `opencv-python` | `"cv2"` | resolves config files and loads its native extension through `__file__`-relative paths | +| `astropy` | `"astropy"` | reads `astropy/CITATION` via `__file__` at import | +| `thinc` | `"thinc"` | reads `thinc/backends/_custom_kernels.cu` via `__file__` at import | +| `spacy` | `"spacy", "thinc"` | imports `thinc` at load and reads its own language data via `__file__`; list both | + ## ADB Tips [Android Debug Bridge (adb)](https://developer.android.com/tools/adb) is a diff --git a/website/docs/publish/index.md b/website/docs/publish/index.md index dbe7221cc4..d228492c65 100644 --- a/website/docs/publish/index.md +++ b/website/docs/publish/index.md @@ -80,7 +80,7 @@ src version = "0.1.0" description = "An Example." readme = "README.md" - requires-python = ">=3.10" + requires-python = ">=3.14" authors = [{ name = "Me", email = "me@example.com" }] dependencies = [ "flet" @@ -123,6 +123,45 @@ In this case, two things to keep in mind: only the direct dependencies required by your app, including `flet`. ::: +## Choosing a Python version + +`flet build` and `flet publish` bundle a specific Python release into your app. +Supported versions and the matching CPython / Pyodide artifacts: + +| Short | CPython runtime | Pyodide (web) | Status | +| ----- | --------------- | ------------- | -------- | +| 3.14 | 3.14.6 | 314.0.0 | default | +| 3.13 | 3.13.14 | 0.29.4 | stable | +| 3.12 | 3.12.13 | 0.27.7 | stable | + +The version is resolved in this order: + +1. **`--python-version X.Y`** — explicit override. Must match a supported short + version (e.g. `flet build apk --python-version 3.13`). +2. **`[project].requires-python`** in `pyproject.toml` — parsed as a PEP 440 + specifier; the **highest** supported short version that satisfies it wins. + `requires-python = ">=3.13,<3.14"` resolves to 3.13; + `requires-python = ">=3.13"` resolves to 3.14. +3. **Default** — the latest supported version (currently `3.14`). + +If neither the CLI flag nor `requires-python` selects a supported version +(e.g. `requires-python = ">=3.20"`), the build fails with a clear error +listing the versions you can choose from. + +For web builds (`flet build web` / `flet publish`), the matching Pyodide +runtime is downloaded into the build output and cached under +`~/.flet/pyodide//` on first use, so subsequent builds reuse it. The +older `0.27.5` bundle that used to ship inside the build template has been +removed in favour of this per-build, versioned download. + +:::note[Pre-release Python (3.15 etc.)] +To bundle a pre-release Python, name it explicitly — `--python-version 3.15` +or `requires-python = "==3.15.*"`. There is **no separate `--pre` flag** for +this. The `--pre` flag on [`flet publish`](../cli/flet-publish.md) is a +different, unrelated option for allowing **micropip** to install pre-release +Python *packages* at runtime. +::: + ## How it works When you run `flet build `, the pipeline is: @@ -131,7 +170,7 @@ When you run `flet build `, the pipeline is: The Flutter app embeds your packaged Python app in its assets and uses `flet` and [`serious_python`](https://pub.dev/packages/serious_python) to run the app and render the UI. The project is cached and reused across builds for rapid iterations; - use [`--clear-cache`](../cli/flet-build.md#--clear-cache) to force a rebuild. + run [`flet clean`](../cli/flet-clean.md) to delete the `build` directory and force a rebuild. 2. Copy custom [icons](#icons) and [splash images](#splash-screen) from `assets` into the Flutter project, then generate: - Icons for all platforms via [`flutter_launcher_icons`](https://pub.dev/packages/flutter_launcher_icons). @@ -776,55 +815,104 @@ web = false ### Boot screen -:::note[Platform support] -[Windows](windows.md), [macOS](macos.md), [Linux](linux.md), -[Android](android.md), and [iOS](ios.md) only. -::: +The boot screen fills the gap between the native [splash screen](#splash-screen) +and your app's first frame — that is, while the Flutter app is up but your +Flet/Python app is not ready yet. It is told which of two stages it is in: -The boot screen is shown while the packaged app archive (`app.zip`) is extracted -to the app data directory (typically on first launch or after the app bundle changes). -It appears after the [splash screen](#splash-screen) and before the -[startup screen](#startup-screen). +1. **Preparing** — the packaged app archive (`app.zip`) is being extracted to the + app data directory (on first launch or after the app bundle changes). This + stage occurs on **Android only**. +2. **Starting up** — the Python runtime and your app are starting, until the + first page is shown (all platforms). If startup fails, the error is shown on + the boot screen. -It is not shown by default. Enable it, for example, when then extraction time is noticeable. +A boot screen is **always rendered**, so this gap is a controlled background +instead of a bare scaffold. By default the built-in `flet` boot screen shows +nothing but a background color — no spinner and no message — until you configure +it. You can also replace it entirely with your own widget +(see [Custom boot screen](#custom-boot-screen)). -#### Example +#### Selecting a boot screen + +A boot screen is addressed by `name`. The default is `flet` (the built-in +screen); custom names are provided by [extensions](#custom-boot-screen). ```toml -[tool.flet.app.boot_screen] # or [tool.flet..app.boot_screen] -show = true -message = "Preparing the app for its first launch…" +[tool.flet.boot_screen] # or [tool.flet..boot_screen] +name = "flet" ``` -### Startup screen +Settings under `[tool.flet..boot_screen]` override the global +`[tool.flet.boot_screen]` per key. -:::note[Platform support] -[Windows](windows.md), [macOS](macos.md), [Linux](linux.md), -[Android](android.md), and [iOS](ios.md) only. -::: +#### Built-in `flet` boot screen + +The built-in screen is configured under a table named after it. All options are +optional: + + + +```toml +[tool.flet.boot_screen.flet] +theme_mode = "auto" # auto (default), light, or dark +bgcolor_light = "#ffffff" +bgcolor_dark = "#000000" +spinner_color_light = "blue" +spinner_color_dark = "yellow" +spinner_size = 30 # 0 or absent → no spinner +text_color_light = "#000000" +text_color_dark = "#ffffff" +prepare_message = "Preparing your app…" # Android only; empty/absent → no message +startup_message = "Starting up…" # empty/absent → no message +``` + + -The startup screen is shown while the Python runtime and your app are starting. -On mobile targets this can include preparing packaged dependencies. It appears -after the [boot screen](#boot-screen). +| Option | Description | +|--------|-------------| +| `theme_mode` | Which color set to use: `auto` (follow the device), `light`, or `dark`. Defaults to `auto`. | +| `bgcolor_light` / `bgcolor_dark` | Background color. When omitted, follows Flet's default theme background. | +| `spinner_color_light` / `spinner_color_dark` | Spinner color. When omitted, follows Flet's default theme primary color. | +| `spinner_size` | Spinner diameter in logical pixels. `0` or absent hides the spinner. | +| `text_color_light` / `text_color_dark` | Message text color. When omitted, follows Flet's default theme on-surface color. | +| `prepare_message` | Text shown during the **preparing** stage (Android only). Empty or absent shows no message. | +| `startup_message` | Text shown during the **starting up** stage. Empty or absent shows no message. | +| `fade_out_duration` | Fade-out duration in milliseconds when the app becomes ready. Defaults to `0` (removed instantly); set a value like `300` to fade out. | -It is not shown by default. +Colors accept the same formats as elsewhere in Flet (hex like `#ffffff` or named +colors like `blue`). -#### Example +#### Custom boot screen + +To take full control of the boot screen — including custom layouts and +animations — provide your own Flutter widget from a Flet extension and reference +it by `name`. See +[Boot screen](../extend/user-extensions.md#boot-screen) in the extension authoring +guide for how to implement one. ```toml -[tool.flet.app.startup_screen] # or [tool.flet..app.startup_screen] -show = true -message = "Starting up the app…" +[tool.flet.boot_screen] +name = "my_screen" + +[tool.flet.boot_screen.my_screen] +# arbitrary options passed to your widget ``` +:::note[Deprecated] +The older `[tool.flet.app.boot_screen]` and `[tool.flet.app.startup_screen]` +settings (with `show` / `message`) are deprecated. They are still honored — and +mapped onto the built-in `flet` boot screen — but you should migrate to +`[tool.flet.boot_screen]`. +::: + ### Hidden app window on startup :::note[Platform support] @@ -1042,9 +1130,15 @@ removes known junk files and any additional globs you specify. (implies `cleanup-packages`) * `cleanup-packages`: remove junk files from site-packages (defaults to `true`) -By default, Flet does **not** compile your app files during packaging. -This allows the build process to complete even if there are syntax errors, -which can be useful for debugging or rapid iteration. +By default, Flet **compiles** both your app and the installed packages to `.pyc` +during packaging. Shipping bytecode avoids recompiling every module on each cold +start — a significant startup win on mobile, where pure Python is imported from a +stored zip and cannot cache bytecode back to disk. + +Pass `--no-compile-app` / `--no-compile-packages` (or set `[tool.flet.compile].app` +/ `[tool.flet.compile].packages` to `false`) to disable it — for example to speed +up iterative builds, or to keep `.py` source in the bundle so the build still +completes with syntax errors present and tracebacks show source lines. #### Resolution order @@ -1053,14 +1147,14 @@ The values of `compile-app` and `cleanup-app` are respectively determined in the 1. [`--compile-app`](../cli/flet-build.md#--compile-app) / [`--cleanup-app`](../cli/flet-build.md#--cleanup-app) 2. `[tool.flet..compile].app` / `[tool.flet..cleanup].app` 3. `[tool.flet.compile].app` / `[tool.flet.cleanup].app` -4. empty list / empty list +4. `True` / empty list The values of `compile-packages` and `cleanup-packages` are respectively determined in the following order of precedence: 1. [`--compile-packages`](../cli/flet-build.md#--compile-packages) / [`--cleanup-packages`](../cli/flet-build.md#--cleanup-packages) 2. `[tool.flet..compile].packages` / `[tool.flet..cleanup].packages` 3. `[tool.flet.compile].packages` / `[tool.flet.cleanup].packages` -4. `False` / `True` +4. `True` / `True` The values of `cleanup-app-files` and `cleanup-package-files` are respectively determined in the following order of precedence: @@ -1152,8 +1246,8 @@ permissions = ["location", "microphone"] is downloaded as a zip artifact from the matching Flet GitHub Release. The version of the template used is determined by the installed Flet version. -The cached project is refreshed when template inputs change or when you pass -[`--clear-cache`](../cli/flet-build.md#--clear-cache). +The cached project is refreshed when template inputs change or after you run +[`flet clean`](../cli/flet-clean.md) to delete the `build` directory. #### Template Source @@ -1496,7 +1590,7 @@ jobs: shell: bash run: | sudo apt update --allow-releaseinfo-change - LINUX_DEPS="$(uv run python -c 'from flet.utils.linux_deps import linux_dependencies; print(" ".join(linux_dependencies))')" + LINUX_DEPS="$(uv run flet --version --json | jq -r '.linux_dependencies | join(" ")')" sudo apt-get install -y --no-install-recommends $LINUX_DEPS sudo apt-get clean @@ -1575,6 +1669,6 @@ dependency is aligned with the same development version before building your app ``` -2. Rebuild the app with the build cache cleared (use [`--clear-cache`](../cli/flet-build.md#--clear-cache); or manually delete `build/flutter`) +2. Rebuild the app with the build cache cleared (run [`flet clean`](../cli/flet-clean.md) to delete the `build` directory) To ensure reproducible builds (ex: in production or CI), prefer using a specific commit SHA, instead of a branch or tag ref. diff --git a/website/docs/publish/web/index.md b/website/docs/publish/web/index.md index cadefd8522..6279b050db 100644 --- a/website/docs/publish/web/index.md +++ b/website/docs/publish/web/index.md @@ -20,6 +20,7 @@ Here is a table comparing Flet app running as a static vs dynamic website: | **Performance** | ⬇️ Slower - Pyodide is currently 3x-5x slower than native Python because of WASM | ✅ Faster - the code is running on the server by native Python. | | **Code protection** | ⬇️ Low - app's code is loaded into a web browser and can be inspected by a user. | ✅ High - the app is running on the server. | | **Hosting** | ✅ Cheap/Free - no code is running on the server and thus the app can be hosted anywhere: GitHub Pages, Cloudflare Pages, Replit, Vercel, a shared hosting or your own VPS. | ⬇️ Paid - the app requires Python code to run on the server and communicate with a web browser via WebSockets. | +| **Python version** | ⬇️ Tied to a specific Pyodide release — pick from the supported set (3.12 / 3.13 / 3.14). See [Choosing a Python version](../index.md#choosing-a-python-version). | ✅ Any Python version that runs your server. | [Static website]: static-website/index.md [Dynamic website]: dynamic-website/index.md diff --git a/website/docs/publish/web/static-website/index.md b/website/docs/publish/web/static-website/index.md index 7b9c15926e..c8fce6c7f6 100644 --- a/website/docs/publish/web/static-website/index.md +++ b/website/docs/publish/web/static-website/index.md @@ -42,6 +42,24 @@ if sys.platform == "emscripten": ``` ::: +:::note[Pyodide and Python version] +The Python version you choose for `flet build web` / `flet publish` pins a +specific Pyodide release — see +[Choosing a Python version](../../index.md#choosing-a-python-version) for the +full matrix and resolution rules. In short: + +| Python | Pyodide | +| ------ | --------- | +| 3.14 | 314.0.0 | +| 3.13 | 0.29.4 | +| 3.12 | 0.27.7 | + +The matching Pyodide runtime is downloaded into the build output and cached +under `~/.flet/pyodide//` on first use. The older `0.27.5` bundle +that used to ship inside the build template has been removed in favour of +this versioned per-build download. +::: + ## Differences There are two ways to publish a static website: [`flet build web`](#flet-build-web) and [`flet publish`](#flet-publish). @@ -188,9 +206,17 @@ route_url_strategy = "hash" Selects the Flutter web renderer: -- `auto` (default) - let Flutter choose the best renderer -- `canvaskit` -- `skwasm` +- `canvaskit` (default) - CanvasKit renderer, with the app compiled to JavaScript +- `skwasm` - Skia WebAssembly renderer, with the app compiled to WebAssembly +- `auto` - let Flutter pick the renderer based on the browser + +:::note +The default is `canvaskit`, not `auto`. With `auto`, Chromium-based browsers +pick `skwasm`, where every byte buffer passed between JavaScript and Dart pays +a costly WebAssembly boundary conversion. Flet web apps exchange bytes with +the Python runtime on every UI update, so `canvaskit` is significantly faster +for them. +::: #### Resolution order @@ -198,20 +224,20 @@ Its value is determined in the following order of precedence: 1. [`--web-renderer`](../../../cli/flet-build.md#--web-renderer) 2. `[tool.flet.web].renderer` -3. `"auto"` +3. `"canvaskit"` #### Example ```bash -flet build web --web-renderer canvaskit +flet build web --web-renderer skwasm ``` ```toml [tool.flet.web] -renderer = "canvaskit" +renderer = "skwasm" ``` diff --git a/website/docs/reference/environment-variables.md b/website/docs/reference/environment-variables.md index d85c18f22f..029e3f104e 100644 --- a/website/docs/reference/environment-variables.md +++ b/website/docs/reference/environment-variables.md @@ -9,19 +9,59 @@ Any other value will be interpreted as `False`. ### `FLET_APP_CONSOLE` -The path to the application's console log file (`console.log`) in the temporary storage directory. +The path to the application's console log file (`console.log`) in the cache storage directory +([`FLET_APP_STORAGE_CACHE`](#flet_app_storage_cache)). Its value is set in production mode. +:::info +In a running Flet app, the equivalent of this environment variable is +[`StoragePaths.get_console_log_filename()`][flet.StoragePaths.get_console_log_filename]. +::: + ### `FLET_APP_STORAGE_DATA` -A directory for the storage of persistent application data that is preserved between app updates. -It is already pre-created and its location depends on the platform the app is running on. +A directory for **durable** application data — databases, state, config — that is preserved between +app updates, backed up by the OS, and never auto-deleted. It is pre-created, app-private, and its +location depends on the platform (it maps to the platform's *application support* directory: +`%APPDATA%\\\data` on Windows, `~/Library/Application Support//data` on +macOS, `~/.local/share//data` on Linux, the app-sandboxed support dir on iOS/Android). + +In production this directory is also the Python program's **current working directory**, so relative +file writes (e.g. `open("app.db", "w")`, `sqlite3.connect("app.db")`) land here. In `flet run` (dev +mode) it is `/.flet/storage/data`. + +:::info +In a running Flet app, this maps to a `data` subdirectory of +[`StoragePaths.get_application_support_directory()`][flet.StoragePaths.get_application_support_directory]. +::: + +### `FLET_APP_STORAGE_CACHE` + +A directory for **regenerable** cached data. The OS may purge it under storage pressure (and the +platform "clear cache" action wipes it), so only store things you can rebuild. Pre-created and +app-private; it maps to the platform's *caches* directory (`%LOCALAPPDATA%\\` on +Windows, `~/Library/Caches/` on macOS, `~/.cache/` on Linux, the app cache dir on +iOS/Android). In `flet run` it is `/.flet/storage/cache`. + +:::info +In a running Flet app, the equivalent of this environment variable is +[`StoragePaths.get_application_cache_directory()`][flet.StoragePaths.get_application_cache_directory]. +::: ### `FLET_APP_STORAGE_TEMP` -A directory for the storage of temporary application files, i.e. cache. -It is already pre-created and its location depends on the platform the app is running on. +A directory for **throwaway** temporary files — the OS temporary directory (`getTemporaryDirectory()`). +It is the most volatile of the three and may be cleared between launches, so don't rely on its contents +persisting. (On Android it resolves to the same directory as +[`FLET_APP_STORAGE_CACHE`](#flet_app_storage_cache).) In `flet run` it is `/.flet/storage/temp`, +and Python's `tempfile` is pointed here too (via `TMPDIR`). Equivalent to Python's +`tempfile.gettempdir()`. + +:::info +In a running Flet app, the equivalent of this environment variable is +[`StoragePaths.get_temporary_directory()`][flet.StoragePaths.get_temporary_directory]. +::: ### `FLET_APP_USER_MODEL_ID` diff --git a/website/docs/services/storagepaths.md b/website/docs/services/storagepaths.md index 9e8e7c2670..ee6f3ef20b 100644 --- a/website/docs/services/storagepaths.md +++ b/website/docs/services/storagepaths.md @@ -8,6 +8,16 @@ import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/croc +:::note Relationship to the `FLET_APP_STORAGE_*` environment variables +`StoragePaths` exposes the raw platform directories. The pre-created +[`FLET_APP_STORAGE_*`](../reference/environment-variables.md#flet_app_storage_data) env vars map onto +them: `FLET_APP_STORAGE_CACHE` = `get_application_cache_directory()`, `FLET_APP_STORAGE_TEMP` = +`get_temporary_directory()`, and `FLET_APP_STORAGE_DATA` = a flet-owned **`data` subdirectory** of +`get_application_support_directory()` (which is also the app's current working directory). Prefer the +env vars for app storage; use `StoragePaths` when you need a different platform directory (e.g. +Documents or Downloads). +::: + ## Examples diff --git a/website/docs/studio/privacy-policy.md b/website/docs/studio/privacy-policy.md index f5480d5814..630a935475 100644 --- a/website/docs/studio/privacy-policy.md +++ b/website/docs/studio/privacy-policy.md @@ -4,9 +4,9 @@ title: "Privacy Policy" # Flet Studio Privacy Policy -**Effective date:** May 26, 2026 +**Effective date:** July 14, 2026 -This Privacy Policy explains how **Appveyor Systems Inc.** ("AppVeyor", "we", "us", or "our") collects, uses, shares, and protects personal information in connection with the Flet Studio service ("Flet Studio", "the Service"). Flet Studio is a hosted browser-based development environment for building Python applications with the Flet framework. +This Privacy Policy explains how **Appveyor Systems Inc.** ("AppVeyor", "we", "us", or "our") collects, uses, shares, and protects personal information in connection with the Flet Studio service ("Flet Studio", "the Service"). Flet Studio is a hosted development environment and runtime for building applications with the Flet framework. This policy applies to information we collect from users of Flet Studio at https://flet.app (and any related domains we operate for the Service) and through the Flet Studio web application. @@ -26,7 +26,7 @@ Separately, when you build a Flet application using Flet Studio and that applica ### 1.3 Scope -This policy covers personal information processed by Flet Studio as currently implemented. Some features described in our marketing materials or roadmap (for example, paid subscriptions, email notifications, and AI assistance) are not yet integrated. If we add features that materially change how personal information is processed, we will update this policy as described in Section 12. +This policy covers personal information processed by Flet Studio as currently implemented, including paid plans, AI credit purchases, AI-assisted development, and email communications. If we add features that materially change how personal information is processed, we will update this policy as described in Section 12. --- @@ -34,31 +34,41 @@ This policy covers personal information processed by Flet Studio as currently im ### 2.1 Information you provide -**Account profile.** When you create an account, we store the information needed to identify you and authenticate your sessions. Today, this is primarily provided through GitHub OAuth and includes: +**Account profile.** When you create an account, we store the information needed to identify you and authenticate your sessions. This is provided through the identity provider you sign in with (GitHub, Google, or Microsoft) and includes: - Your email address -- Your full name (if available from GitHub) -- A unique GitHub user identifier -- Your GitHub username +- Your full name (if available from the provider) +- A unique user identifier issued by the provider +- Your username or handle (where the provider exposes one) - Your profile avatar URL **Account and team information.** For each account, we store the account name, a URL-safe slug, the account type (personal or team), the plan tier, and — for team accounts — the membership and role of each member. **Content you create or upload.** When you use Flet Studio, we store the app source code, files, and versions that you create, edit, or upload to the Service, along with their metadata (file path, size, timestamps, app name, description, dependencies, tags). This content is stored in object storage hosted by our infrastructure provider, Railway. +**AI conversations.** When you use the AI agent, we store your prompts, the AI's responses (including generated code and a record of the actions the AI took in your project), and any ratings you give on responses. Conversations are stored in our database, per app and per account, until you delete the conversation or the associated app, until your account is deleted, or until we remove them under a data-retention policy we may adopt. + +**Billing information.** When you purchase a paid plan or AI credits, Stripe collects your payment card details and billing address at checkout. We store your Stripe customer and subscription identifiers, your plan status, and records of your purchases and credit grants, and we retain billing addresses and purchase records for bookkeeping in QuickBooks Online. + +**Newsletter subscription.** When you create an account, your email address and name are added to the Flet Studio newsletter mailing list, operated by Mailgun. Your subscription and unsubscribe status is maintained by Mailgun, not in our database. You can unsubscribe at any time using the toggle in account settings, the unsubscribe link in every newsletter email, or your mail client's unsubscribe function. + ### 2.2 Information collected automatically **Sign-in and security data.** When you sign in, we record the timestamp of your most recent successful sign-in and the IP address from which it occurred. We also maintain an internal token version counter that is used to invalidate active sessions when you sign out or change credentials. We use this information to maintain account security, detect suspicious activity, and provide an audit trail. **Usage data.** To enforce per-account quotas and prevent abuse, we maintain daily counters of certain actions (for example, how many gallery clones or archive uploads you have performed in the last 24 hours) and a running total of the storage your account is consuming. These counters are tied to your account, not to individual sign-in sessions. +**AI usage metering.** For each AI agent run, we record the model used, its token counts, and the resulting credit cost in a usage ledger tied to your account. We use these records to bill AI usage against your credits and to enforce quotas. + **Server-side telemetry.** When telemetry is enabled, our server software emits operational traces and logs to a server-side observability tool (Pydantic Logfire) to help us diagnose errors, investigate incidents, and monitor performance. These traces may incidentally include account or request identifiers; we apply a PII-scrubbing rule to redact sensitive fields. Telemetry is configurable and is not enabled in all environments. We do **not** use client-side analytics services. We do not load Google Analytics, Mixpanel, Segment, advertising pixels, or any similar product into the Flet Studio web application. ### 2.3 Information from third parties -When you authenticate via GitHub OAuth, we receive the profile fields listed in Section 2.1 from GitHub. We do not receive your GitHub password and we do not request access to your private repositories unless you explicitly grant a scope that permits it. +When you authenticate via GitHub, Google, or Microsoft, we receive the profile fields listed in Section 2.1 from the provider you choose. We do not receive your password for that provider, and we do not request access to your private repositories or files unless you explicitly grant a scope that permits it. + +When you make a purchase, we receive payment and subscription status events from Stripe (for example, that a payment succeeded, a subscription renewed, or a subscription was cancelled). These events reference Stripe identifiers. --- @@ -67,13 +77,17 @@ When you authenticate via GitHub OAuth, we receive the profile fields listed in We use personal information to: - Provide the Service: authenticate you, render your accounts and projects, store and serve your content +- Operate AI-assisted development features: your prompts, conversation history, and the project context needed to generate a response are sent to our AI model providers (see Section 5.1) +- Improve the Service: we may review AI conversations to diagnose problems with the AI features and improve their quality (for example, refining prompts, tooling, and agent behavior) +- Process payments, maintain billing and credit-usage records, and calculate applicable taxes +- Send the Flet Studio newsletter with product news and updates — you can opt out at any time (see Section 2.1) - Enforce per-account limits and prevent abuse of the Service - Maintain the security and integrity of the Service, including investigating fraud, abuse, or unauthorized access - Diagnose, debug, and improve the Service through server-side telemetry - Communicate with you about your account or service-related matters when you contact us - Comply with legal obligations -We do **not** use your personal information for advertising, profiling, automated decision-making with legal effects, or training machine-learning models. +We do **not** use your personal information or User Content for advertising, for profiling, or for automated decision-making that produces legal or similarly significant effects (for example, suspending an account by algorithm with no human review), and we do **not** use them to train machine-learning models — nor do we permit our AI model providers to do so (see Section 5.1). --- @@ -81,10 +95,10 @@ We do **not** use your personal information for advertising, profiling, automate If you are located in the European Economic Area, the United Kingdom, or Switzerland, we rely on the following legal bases under the GDPR (or its UK equivalent) when we process your personal information: -- **Performance of a contract** — to provide the Service you have signed up for. This covers account creation, authentication, storage of your content, and quota enforcement. -- **Legitimate interests** — to keep the Service secure, prevent abuse, debug and improve the Service, and maintain operational telemetry. We balance these interests against your rights and interests, and we apply data-minimization measures (such as PII scrubbing in telemetry) accordingly. -- **Compliance with a legal obligation** — when we are required to retain, disclose, or process personal information to comply with applicable law. -- **Consent** — where we ask for it explicitly. Today, our processing is not consent-based; if we introduce features that require consent (for example, optional marketing communications), we will request it separately and you will be able to withdraw it at any time. +- **Performance of a contract** — to provide the Service you have signed up for. This covers account creation, authentication, storage of your content, quota enforcement, paid subscriptions and credit purchases, and providing the AI features you invoke. +- **Legitimate interests** — to keep the Service secure, prevent abuse, debug and improve the Service, maintain operational telemetry, and send the Flet Studio newsletter to existing account holders with product news and updates (with an easy opt-out at any time and the right to object described in Section 10). +- **Compliance with a legal obligation** — when we are required to retain, disclose, or process personal information to comply with applicable law (for example, retaining billing records for tax purposes). +- **Consent** — where we ask for it explicitly. If we introduce features that require consent, we will request it separately and you will be able to withdraw it at any time. --- @@ -100,13 +114,20 @@ We rely on a small number of third-party service providers to operate Flet Studi | Service provider | Purpose | Data shared | |---|---|---| -| **GitHub** | OAuth identity provider used to authenticate accounts | Authentication exchange; we receive profile fields listed in Section 2.1 | +| **GitHub, Google, Microsoft** | OAuth identity providers used to authenticate accounts | Authentication exchange; we receive the profile fields listed in Section 2.1 from the provider you choose | | **Railway** | Hosting for our application servers, our managed PostgreSQL database, and the object storage that holds user-uploaded content | All personal information stored by the Service is hosted on Railway infrastructure | +| **xAI** | AI model provider for the AI agent | Your prompts, conversation history, app source code and files (including images), and your name, email address, and username. Sent only when you use AI features; **not used to train models** | +| **OpenAI** | AI model provider for the AI agent | Same as xAI; **not used to train models** | +| **Stripe** | Payment processing, subscription management, and tax calculation | Email address, account identifier, plan, and — collected by Stripe directly at checkout — your billing address and payment card details; your purchase history | +| **Mailgun** | Newsletter and email delivery | Email address, full name, and newsletter subscription/suppression status | | **Pydantic Logfire** | Server-side observability and tracing | Request traces, query traces, and error spans; PII-scrubbed before transmission | +| **Intuit QuickBooks Online** | Accounting and bookkeeping | Billing address, purchase and invoice records | + +Our agreements with our AI model providers do not permit them to use your data to train their models. ### 5.2 Legal and safety disclosures -We may disclose personal information when we believe in good faith that disclosure is required by law, by a valid legal process (such as a subpoena or court order), or is necessary to protect the rights, property, or safety of Appveyor Systems Inc., our users, or the public. +We may disclose personal information when we believe in good faith that disclosure is required by law or by a valid legal process (such as a subpoena or court order). ### 5.3 Business transfers @@ -131,7 +152,11 @@ We do **not** set any advertising cookies, analytics cookies, social-media cooki - **User content** (apps, files, versions) is retained for as long as your account is active or until you delete it. - **Sign-in metadata** (last sign-in timestamp, last sign-in IP) is overwritten on each new sign-in; older values are not kept. - **Usage counters** are kept per day and are not retained beyond what is needed for quota enforcement and operational analysis. -- **Server-side telemetry** (Logfire traces and logs) is retained for the period configured with our observability provider, which is short by default. +- **AI conversations** are retained until you delete the conversation or the associated app, or until your account is deleted. +- **Billing records** (purchase and credit-usage ledgers, invoices) are retained for as long as required by applicable tax and accounting law, generally seven years in Canada, even after account deletion. +- **Newsletter list membership** is maintained by Mailgun until you unsubscribe; when we process an account-deletion request, we also remove your address from the mailing list. +- **Server-side telemetry** (Logfire traces and logs) is retained for a limited period configured with our observability provider. +- We may adopt shorter retention periods for specific data categories in the future; if we do, we will update this policy. - **Account deletion**: when you request deletion of your account, we delete or anonymize your account profile, content, and associated records within 30 days, except where we are required to retain certain information to comply with legal obligations or to resolve disputes. To request deletion, email privacy@flet.dev from the email address associated with your account. diff --git a/website/docs/studio/terms-of-service.md b/website/docs/studio/terms-of-service.md index b005ecfcfd..dd603383e6 100644 --- a/website/docs/studio/terms-of-service.md +++ b/website/docs/studio/terms-of-service.md @@ -4,9 +4,9 @@ title: "Terms of Service" # Flet Studio Terms of Service -**Effective date:** May 26, 2026 +**Effective date:** July 14, 2026 -These Terms of Service ("Terms") form a binding agreement between you and **Appveyor Systems Inc.** ("AppVeyor", "we", "us", or "our") and govern your access to and use of the Flet Studio service ("Flet Studio" or the "Service"). Flet Studio is a hosted browser-based development environment and runtime for building applications with the Flet framework. +These Terms of Service ("Terms") form a binding agreement between you and **Appveyor Systems Inc.** ("AppVeyor", "we", "us", or "our") and govern your access to and use of the Flet Studio service ("Flet Studio" or the "Service"). Flet Studio is a hosted development environment and runtime for building applications with the Flet framework. Please read these Terms carefully. By accessing or using Flet Studio, you agree to be bound by these Terms and by our [Privacy Policy](privacy-policy.md). If you do not agree, you must not use the Service. @@ -16,13 +16,13 @@ Please read these Terms carefully. By accessing or using Flet Studio, you agree By creating an account, signing in, or otherwise using Flet Studio, you confirm that you have read, understood, and agree to be bound by these Terms. If you are accepting these Terms on behalf of a company, organization, or other legal entity, you represent and warrant that you have the authority to bind that entity to these Terms, in which case "you" refers to that entity. -We may update these Terms from time to time as described in Section 13.4. Your continued use of the Service after an update takes effect constitutes acceptance of the updated Terms. +We may update these Terms from time to time as described in Section 14.4. Your continued use of the Service after an update takes effect constitutes acceptance of the updated Terms. --- ## 2. The Service -Flet Studio provides a hosted environment that allows you to create, edit, store, run, and share applications written in Python using the Flet framework. The Service includes account management, project storage, code editing, application execution, and related features. +Flet Studio provides a hosted environment that allows you to create, edit, store, run, and share applications written in Python using the Flet framework. The Service includes account management, project storage, code editing, AI-assisted development, application execution, sharing and publishing, and related features. Flet Studio is currently delivered through the browser; we may also offer desktop or mobile applications in the future. We may add, modify, or discontinue features at any time. Where a change materially and adversely affects the way you use the Service, we will use commercially reasonable efforts to provide advance notice through the Service or by email. @@ -36,7 +36,7 @@ You must be at least 16 years old to use Flet Studio. If you are using the Servi ### 3.2 Account creation -You can create an account by signing in with a supported identity provider (currently GitHub) or, where available, by creating a local account with an email and password. You must provide accurate and complete information, and you must keep it accurate over time. +You can create an account by signing in with a supported identity provider (currently GitHub, Google, or Microsoft) or, where available, by creating a local account with an email and password. You must provide accurate and complete information, and you must keep it accurate over time. ### 3.3 Account security @@ -50,6 +50,10 @@ You may not create multiple personal accounts to circumvent quotas, restrictions Information you provide when creating and using an account is processed in accordance with our [Privacy Policy](privacy-policy.md). +### 3.6 Communications + +We send service and transactional emails about your account and the Service (for example, security notices and billing communications); you cannot opt out of these while you hold an account. Account holders are also subscribed to the Flet Studio newsletter with product news and updates. You can unsubscribe from the newsletter at any time using the toggle in your account settings or the unsubscribe link included in every newsletter email. + --- ## 4. Acceptable Use @@ -106,48 +110,80 @@ We will respond to valid notices in a manner consistent with applicable copyrigh --- -## 6. Plans, Pricing, and the Free Tier +## 6. AI Features + +Flet Studio includes an AI agent that can read, generate, and modify your app code based on your instructions. + +**Third-party model providers.** To generate responses, your prompts, conversation history, app file contents (including images), and basic profile information (your name, email address, and username) are sent to third-party AI model providers, as described in our [Privacy Policy](privacy-policy.md). + +**AI output.** AI output is generated automatically. It **may be inaccurate or incomplete, and generated code may not work or may contain security issues**. You are responsible for reviewing and testing AI output before relying on it. AI output stored in your apps is treated as your User Content under Section 5. + +**AI credits.** AI usage consumes AI credits, metered by model token usage at the rates displayed within the Service. Your plan includes a monthly credit allowance, and additional credits can be purchased (see Section 7). + +Your use of AI features is subject to Section 4 (Acceptable Use); you may not use them to generate unlawful or malicious content or attempt to circumvent usage metering. + +--- + +## 7. Plans, Billing, and Payments + +### 7.1 Plans + +Flet Studio is offered under a free plan and one or more paid plans. The current plans, their features and limits, and their prices — together with the price of AI credit packs — are listed on our [pricing page](https://flet.app/pricing). We may change plan limits and pricing with reasonable advance notice; where we materially reduce a limit, we will provide notice through the Service or by email. A price change for a subscription takes effect at the start of a subsequent billing period. + +### 7.2 AI credit packs + +AI credit packs are one-time purchases. Purchased credits do not expire while your account remains active. Monthly plan credits reset each billing cycle and do not roll over. AI credits have no cash value and are not transferable. + +### 7.3 Payment processing + +Payments are processed by our third-party payment processor, **Stripe**. By making a purchase you agree to Stripe's terms applicable to the payment. Your card details are collected by Stripe directly and are not received or stored by AppVeyor. Paid plans are billed in advance and **renew automatically each month until cancelled**. You can manage or cancel your subscription at any time through the billing portal in your account settings; cancellation takes effect at the end of the current billing period, and you retain paid-plan features until then. When a subscription ends, your account reverts to the free plan and its limits. + +### 7.4 Taxes + +Prices shown do not include taxes. Applicable sales tax will be calculated based on your billing address and itemized at checkout. + +### 7.5 Refunds -Today, Flet Studio is offered as a **Free** plan at no charge. The Free plan includes limits on, but not limited to, the number of applications, private applications, storage, files per application, project versions, file sizes, archive sizes, and daily operation counts (such as gallery clones and archive uploads). The current Free-plan limits are documented within the Service and may be reviewed at any time. +All fees and credit purchases are **non-refundable except where required by applicable law**. We do not provide credits or prorated refunds for partial billing periods, and unused AI credits are not redeemable for cash. -We reserve the right to change Free-plan limits with reasonable advance notice. Where we materially reduce a limit, we will provide notice through the Service or by email. +### 7.6 Non-payment -We may introduce paid plans in the future. Paid plans, when offered, will be governed by additional terms presented at the time of purchase, including pricing, billing, refunds, and applicable taxes. Nothing in these Terms creates an obligation on AppVeyor to offer a paid plan or any particular feature. +If a payment for your subscription fails and cannot be collected after our payment processor's retries, we may downgrade your account to the free plan or suspend paid features. --- -## 7. Service Availability and Modifications +## 8. Service Availability and Modifications -We strive to keep Flet Studio available and performant, but the Service is provided **without any uptime or availability guarantee**, particularly for users on the Free plan. We may perform scheduled or emergency maintenance, suspend access to all or part of the Service, or modify, deprecate, or discontinue features at any time. +We strive to keep Flet Studio available and performant, but the Service is provided **without any uptime or availability guarantee**. We may perform scheduled or emergency maintenance, suspend access to all or part of the Service, or modify, deprecate, or discontinue features at any time. Where a change materially and adversely affects how you use the Service, we will use commercially reasonable efforts to provide advance notice through the Service or by email. --- -## 8. Suspension and Termination +## 9. Suspension and Termination -### 8.1 Termination by you +### 9.1 Termination by you You may stop using Flet Studio at any time. You may delete your account by emailing legal@flet.dev from the email address associated with your account. -### 8.2 Suspension or termination by AppVeyor +### 9.2 Suspension or termination by AppVeyor We may suspend or terminate your access to all or part of the Service: - Immediately, if we reasonably believe you have breached these Terms, your account presents a security risk, you are abusing the Service, or we are required to do so by law - With reasonable notice, for any other reason -### 8.3 Effect of termination +### 9.3 Effect of termination Upon termination, your right to use the Service ends immediately. We will handle your account data and User Content in accordance with our [Privacy Policy](privacy-policy.md), which provides that account data and User Content are deleted or anonymized within 30 days of a deletion request, subject to backups and legal retention requirements. -### 8.4 Survival +### 9.4 Survival -The following sections survive termination of these Terms: Section 5.1 (Ownership), Section 5.4 (Your responsibility), Section 9 (Disclaimers), Section 10 (Limitation of Liability), Section 11 (Indemnification), Section 12 (Governing Law and Dispute Resolution), and Section 13 (General Provisions), together with any other provision that by its nature should survive. +The following sections survive termination of these Terms: Section 5.1 (Ownership), Section 5.4 (Your responsibility), Section 7.5 (Refunds), Section 10 (Disclaimers), Section 11 (Limitation of Liability), Section 12 (Indemnification), Section 13 (Governing Law and Dispute Resolution), and Section 14 (General Provisions), together with any other provision that by its nature should survive. --- -## 9. Disclaimers +## 10. Disclaimers THE SERVICE IS PROVIDED **"AS IS" AND "AS AVAILABLE"** WITHOUT WARRANTIES OF ANY KIND, WHETHER EXPRESS, IMPLIED, OR STATUTORY. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, APPVEYOR DISCLAIMS ALL WARRANTIES, INCLUDING WITHOUT LIMITATION ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, ACCURACY, QUIET ENJOYMENT, AND ANY WARRANTIES ARISING FROM COURSE OF DEALING OR USAGE OF TRADE. @@ -157,7 +193,7 @@ Some jurisdictions do not allow the exclusion of certain warranties, so some of --- -## 10. Limitation of Liability +## 11. Limitation of Liability TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW: @@ -169,7 +205,7 @@ These limitations apply regardless of the legal theory on which a claim is based --- -## 11. Indemnification +## 12. Indemnification You agree to defend, indemnify, and hold harmless Appveyor Systems Inc., its affiliates, and their respective officers, directors, employees, and agents from and against any and all claims, damages, losses, liabilities, costs, and expenses (including reasonable legal fees) arising out of or related to: @@ -182,7 +218,7 @@ We may, at our option, assume the exclusive defense and control of any matter su --- -## 12. Governing Law and Dispute Resolution +## 13. Governing Law and Dispute Resolution These Terms, and any dispute or claim arising out of or in connection with them or their subject matter (including non-contractual disputes or claims), are governed by **the laws of the Province of British Columbia and the federal laws of Canada applicable therein**, without regard to conflict-of-laws principles. @@ -192,41 +228,41 @@ These Terms do not require mandatory arbitration, and nothing in these Terms is --- -## 13. General Provisions +## 14. General Provisions -### 13.1 Entire agreement +### 14.1 Entire agreement These Terms, together with the [Privacy Policy](privacy-policy.md) and any additional terms you accept at the time of purchasing a paid feature, constitute the entire agreement between you and AppVeyor concerning the Service and supersede all prior or contemporaneous agreements on the same subject. -### 13.2 Severability +### 14.2 Severability If any provision of these Terms is held to be invalid or unenforceable, that provision will be enforced to the maximum extent permissible, and the remaining provisions will remain in full force and effect. -### 13.3 No waiver +### 14.3 No waiver Our failure to enforce any right or provision of these Terms will not be deemed a waiver of that right or provision. -### 13.4 Changes to these Terms +### 14.4 Changes to these Terms We may modify these Terms from time to time. When we make material changes, we will update the "Effective date" above and, where appropriate, notify you through the Service or by email before the changes take effect. Your continued use of the Service after the new Terms take effect constitutes acceptance. -### 13.5 Assignment +### 14.5 Assignment You may not assign or transfer these Terms or your account without our prior written consent. We may assign these Terms to an affiliate or in connection with a merger, acquisition, reorganization, or sale of assets, on notice to you. -### 13.6 Relationship of the parties +### 14.6 Relationship of the parties Nothing in these Terms creates a partnership, joint venture, agency, employment, or fiduciary relationship between you and AppVeyor. -### 13.7 Force majeure +### 14.7 Force majeure Neither party will be liable for failure or delay in performance caused by events beyond its reasonable control, including acts of God, war, terrorism, civil unrest, labor disputes, internet or telecommunications outages, governmental actions, or epidemics. -### 13.8 Notices +### 14.8 Notices We may give notices to you through the Service, by posting on our website, or by email to the address associated with your account. You must give notices to us in writing at **legal@flet.dev**. -### 13.9 Contact +### 14.9 Contact **Appveyor Systems Inc.** Email: legal@flet.dev diff --git a/website/docs/studio/whats-new.md b/website/docs/studio/whats-new.md index 004ba61e66..1c31457ac5 100644 --- a/website/docs/studio/whats-new.md +++ b/website/docs/studio/whats-new.md @@ -8,6 +8,13 @@ New features, improvements, and bug fixes in Flet Studio, listed in reverse-chronological order. Flet Studio ships independently of the Flet SDK — see [Flet release notes](../updates/release-notes.md) for SDK changes. +## July 14, 2026 + +* New AI agent that helps you build and modify Flet apps with natural-language instructions. +* Paid Creator plan and AI credit packs, with billing powered by Stripe. +* Flet Studio newsletter — manage your subscription in account settings. +* Updated [Terms of Service](terms-of-service.md) and [Privacy Policy](privacy-policy.md) to cover AI features, paid plans, and the newsletter. + ## May 29, 2026 * New sign in options: Google and Microsoft. diff --git a/website/docs/types/datachannel.md b/website/docs/types/datachannel.md new file mode 100644 index 0000000000..302585ec6f --- /dev/null +++ b/website/docs/types/datachannel.md @@ -0,0 +1,7 @@ +--- +title: "DataChannel" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/datachannelopenevent.md b/website/docs/types/datachannelopenevent.md new file mode 100644 index 0000000000..23744d0fb5 --- /dev/null +++ b/website/docs/types/datachannelopenevent.md @@ -0,0 +1,7 @@ +--- +title: "DataChannelOpenEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/finder.md b/website/docs/types/finder.md deleted file mode 100644 index 8446c3b26f..0000000000 --- a/website/docs/types/finder.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Finder" ---- - -::: flet.testing.finder.Finder diff --git a/website/docs/types/flettestapp.md b/website/docs/types/flettestapp.md deleted file mode 100644 index 93170351a6..0000000000 --- a/website/docs/types/flettestapp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "FletTestApp" ---- - -::: flet.testing.flet_test_app.FletTestApp diff --git a/website/docs/types/run.md b/website/docs/types/run.md new file mode 100644 index 0000000000..adb52c1185 --- /dev/null +++ b/website/docs/types/run.md @@ -0,0 +1,7 @@ +--- +title: "run" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/run_async.md b/website/docs/types/run_async.md new file mode 100644 index 0000000000..bccaae5dce --- /dev/null +++ b/website/docs/types/run_async.md @@ -0,0 +1,7 @@ +--- +title: "run_async" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/tester.md b/website/docs/types/tester.md deleted file mode 100644 index 415180a981..0000000000 --- a/website/docs/types/tester.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Tester" ---- - -::: flet.testing.tester.Tester diff --git a/website/docs/types/testing/disposalmode.md b/website/docs/types/testing/disposalmode.md new file mode 100644 index 0000000000..64747d6b1e --- /dev/null +++ b/website/docs/types/testing/disposalmode.md @@ -0,0 +1,7 @@ +--- +title: "DisposalMode" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/testing/finder.md b/website/docs/types/testing/finder.md new file mode 100644 index 0000000000..71df9954c4 --- /dev/null +++ b/website/docs/types/testing/finder.md @@ -0,0 +1,7 @@ +--- +title: "Finder" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/testing/flettestapp.md b/website/docs/types/testing/flettestapp.md new file mode 100644 index 0000000000..9957c97933 --- /dev/null +++ b/website/docs/types/testing/flettestapp.md @@ -0,0 +1,7 @@ +--- +title: "FletTestApp" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/testing/tester.md b/website/docs/types/testing/tester.md new file mode 100644 index 0000000000..2d9835a48b --- /dev/null +++ b/website/docs/types/testing/tester.md @@ -0,0 +1,7 @@ +--- +title: "Tester" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/updates/breaking-changes/index.md b/website/docs/updates/breaking-changes/index.md index bdb3f1ecf6..007e668502 100644 --- a/website/docs/updates/breaking-changes/index.md +++ b/website/docs/updates/breaking-changes/index.md @@ -22,13 +22,29 @@ This page lists the guides created for each release. The following guides are available. They're sorted by release, with the most recent release first. Each guide explains the change, the reason for it, and how to migrate your code. +### Released in Flet 0.86.0 + +#### Breaking changes + +- [App files ship unpacked in a read-only bundle; storage dirs reworked](/docs/updates/breaking-changes/v0-86-0/app-files-unpacked-read-only-bundle) +- [Android: site-packages ship zipped; some packages need `extract_packages`](/docs/updates/breaking-changes/v0-86-0/android-extract-packages) +- [Android: `x86` removed from target architectures](/docs/updates/breaking-changes/v0-86-0/android-x86-arch-removed) +- [Default bundled Python version is now 3.14](/docs/updates/breaking-changes/v0-86-0/default-bundled-python-3-14) +- [App and packages are compiled to `.pyc` by default](/docs/updates/breaking-changes/v0-86-0/compile-on-by-default) +- [`flet.version.pyodide_version` and `PYODIDE_VERSION` removed](/docs/updates/breaking-changes/v0-86-0/removed-pyodide-version-export) +- [Flet protocol framing upgraded for DataChannel support](/docs/updates/breaking-changes/v0-86-0/data-channel-protocol-upgrade) + +#### Deprecations + +- [`flet build --clear-cache` flag deprecated](/docs/updates/breaking-changes/v0-86-0/deprecated-clear-cache-flag) + ### Released in Flet 0.85.0 #### Breaking changes -- [Deprecated spacing and border helper functions removed](/docs/updates/breaking-changes/removed-spacing-border-helpers) +- [Deprecated spacing and border helper functions removed](/docs/updates/breaking-changes/v0-85-0/removed-spacing-border-helpers) #### Deprecations -- [`DragTargetEvent` coordinate fields deprecated](/docs/updates/breaking-changes/deprecated-drag-target-event-coordinates) -- [`Video` control APIs deprecated](/docs/updates/breaking-changes/deprecated-video-apis) +- [`DragTargetEvent` coordinate fields deprecated](/docs/updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates) +- [`Video` control APIs deprecated](/docs/updates/breaking-changes/v0-85-0/deprecated-video-apis) diff --git a/website/docs/updates/breaking-changes/deprecated-drag-target-event-coordinates.md b/website/docs/updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates.md similarity index 91% rename from website/docs/updates/breaking-changes/deprecated-drag-target-event-coordinates.md rename to website/docs/updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates.md index 43703876cc..51a70b0207 100644 --- a/website/docs/updates/breaking-changes/deprecated-drag-target-event-coordinates.md +++ b/website/docs/updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates.md @@ -8,7 +8,7 @@ title: "DragTargetEvent coordinate fields deprecated" This guide is accurate as of Flet 0.85.0. Later releases might add new APIs or additional migration paths. -The [breaking changes and deprecations index](.) lists the guides created for each release. +The [breaking changes and deprecations index](../index.md) lists the guides created for each release. ::: ## Summary @@ -62,4 +62,4 @@ If your code needs page-level coordinates instead, use - API documentation: [`DragTargetEvent`][flet.DragTargetEvent] - Issues and PRs: [#6387](https://github.com/flet-dev/flet/issues/6387), [#6401](https://github.com/flet-dev/flet/pull/6401) -- Release notes: [Flet 0.85.0](../release-notes.md#085x) +- Release notes: [Flet 0.85.0](../../release-notes.md#085x) diff --git a/website/docs/updates/breaking-changes/deprecated-video-apis.md b/website/docs/updates/breaking-changes/v0-85-0/deprecated-video-apis.md similarity index 91% rename from website/docs/updates/breaking-changes/deprecated-video-apis.md rename to website/docs/updates/breaking-changes/v0-85-0/deprecated-video-apis.md index c49986ef81..10580e1164 100644 --- a/website/docs/updates/breaking-changes/deprecated-video-apis.md +++ b/website/docs/updates/breaking-changes/v0-85-0/deprecated-video-apis.md @@ -8,7 +8,7 @@ title: "Video control APIs deprecated" This guide is accurate as of Flet 0.85.0. Later releases might add new APIs or additional migration paths. -The [breaking changes and deprecations index](.) lists the guides created for each release. +The [breaking changes and deprecations index](../index.md) lists the guides created for each release. ::: ## Summary @@ -81,4 +81,4 @@ been added to the page. - API documentation: [`Video`][flet_video.Video] - Issues and PRs: [PR #6463](https://github.com/flet-dev/flet/pull/6463) -- Release notes: [Flet 0.85.0](../release-notes.md#085x) +- Release notes: [Flet 0.85.0](../../release-notes.md#085x) diff --git a/website/docs/updates/breaking-changes/removed-spacing-border-helpers.md b/website/docs/updates/breaking-changes/v0-85-0/removed-spacing-border-helpers.md similarity index 93% rename from website/docs/updates/breaking-changes/removed-spacing-border-helpers.md rename to website/docs/updates/breaking-changes/v0-85-0/removed-spacing-border-helpers.md index cdad6bdb9e..de24bfee25 100644 --- a/website/docs/updates/breaking-changes/removed-spacing-border-helpers.md +++ b/website/docs/updates/breaking-changes/v0-85-0/removed-spacing-border-helpers.md @@ -8,7 +8,7 @@ title: "Deprecated spacing and border helper functions removed" This guide is accurate as of Flet 0.85.0. Later releases might add new APIs or additional migration paths. -The [breaking changes and deprecations index](.) lists the guides created for each release. +The [breaking changes and deprecations index](../index.md) lists the guides created for each release. ::: ## Summary @@ -74,4 +74,4 @@ card = ft.Container( - API documentation: [`Border`][flet.Border], [`BorderRadius`][flet.BorderRadius], [`Padding`][flet.Padding] - Issues and PRs: [#6425](https://github.com/flet-dev/flet/pull/6425) -- Release notes: [Flet 0.85.0](../release-notes.md#085x) +- Release notes: [Flet 0.85.0](../../release-notes.md#085x) diff --git a/website/docs/updates/breaking-changes/v0-86-0/android-extract-packages.md b/website/docs/updates/breaking-changes/v0-86-0/android-extract-packages.md new file mode 100644 index 0000000000..8909a9a2a9 --- /dev/null +++ b/website/docs/updates/breaking-changes/v0-86-0/android-extract-packages.md @@ -0,0 +1,89 @@ +--- +title: "Android: site-packages ship zipped; some packages need extract_packages" +--- + +# Android: site-packages ship zipped; some packages need `extract_packages` + +:::note +This guide is accurate as of Flet 0.86.0. Later releases might add new APIs or +additional migration paths. + +The [breaking changes and deprecations index](../index.md) lists the guides created for each release. +::: + +## Summary + +Flet 0.86.0 changes how Python code is packaged into Android apps (`flet build apk` / `aab`): + +- **Native extension modules** (`.so` files) are loaded **memory-mapped directly from the APK** — + no extraction to disk. +- **Pure Python code** — the standard library and your site-packages — ships in *stored* zip + assets (`stdlib.zip`, `sitepackages.zip`) and is imported **in place** via + [`zipimport`](https://docs.python.org/3/library/zipimport.html), so it is no longer duplicated + per ABI or unpacked on first launch. + +This makes APKs significantly smaller and removes the need for `useLegacyPackaging` / +`keepDebugSymbols` workarounds. Importing from a zip is transparent to most packages. + +Some packages still locate bundled data files through a real filesystem path, usually with +`__file__` or `pkg_resources`, instead of the zip-safe +[`importlib.resources`](https://docs.python.org/3/library/importlib.resources.html). Those packages +must be listed in **`extract_packages`** so they ship extracted to disk. + +This affects **Android only**. On macOS, iOS, Windows, and Linux, site-packages ship unpacked; +web (Pyodide) is unchanged. + +For the maintained feature documentation, including examples, wildcard behavior, and the current +list of known affected packages, see +[Android packaging: extract packages](../../../publish/android.md#extract-packages). + +## Symptoms + +The build succeeds, but the app crashes or errors on the device when the package is imported or +first used. The traceback usually contains a path where `sitepackages.zip` or `stdlib.zip` appears +as a directory component, for example: + +```bash +FileNotFoundError: [Errno 2] No such file or directory: + '/data/user/0//files/.../sitepackages.zip/matplotlib/mpl-data/matplotlibrc' +``` + +`NotADirectoryError` or `OSError` with a similar `sitepackages.zip/...` path is also a common sign +that the package computed a data path from `__file__` and tried to read it as a regular file. + +## Migration guide + +Add the failing package's import name to your `pyproject.toml`: + +```toml +[tool.flet.android] +extract_packages = ["matplotlib", "sklearn"] +``` + +or pass them on the command line: + +```bash +flet build apk --android-extract-packages matplotlib sklearn +``` + +An entry is the package's **import name** — its top-level directory under site-packages — not +the PyPI distribution name: `sklearn`, not `scikit-learn`; `cv2`, not `opencv-python`. + +Flet extracts the listed package directories and everything under them to the app's files directory, +so `__file__`-relative reads work again. + +### No action needed for + +- Apps targeting only desktop, iOS, or web. +- Android apps whose dependencies are all zip-safe (the common case) — the change is then purely + a size win. + +## Timeline + +- Changed in: `0.86.0` + +## References + +- [Android packaging: extract packages](../../../publish/android.md#extract-packages) +- [`flet build` CLI reference](../../../cli/flet-build.md) +- Release notes: [Flet 0.86.0](../../release-notes.md) diff --git a/website/docs/updates/breaking-changes/v0-86-0/android-x86-arch-removed.md b/website/docs/updates/breaking-changes/v0-86-0/android-x86-arch-removed.md new file mode 100644 index 0000000000..431014eb9f --- /dev/null +++ b/website/docs/updates/breaking-changes/v0-86-0/android-x86-arch-removed.md @@ -0,0 +1,70 @@ +--- +title: "Android: x86 removed from target architectures" +--- + +# Android: `x86` removed from target architectures + +:::note +This guide is accurate as of Flet 0.86.0. Later releases might add new APIs or +additional migration paths. + +The [breaking changes and deprecations index](../index.md) lists the guides created for each release. +::: + +## Summary + +The 32-bit `x86` ABI is no longer a valid Android target architecture. Starting with Flet 0.86.0, +`flet build apk` / `aab` validates the requested architectures upfront, and a build that includes +`x86` — via `--arch`, `[tool.flet.android].target_arch`, or `[tool.flet].target_arch` — fails +immediately with: + +``` +Invalid Android architecture(s): x86. +Supported: armeabi-v7a, arm64-v8a, x86_64. +``` + +In earlier Flet versions `x86` was listed as a supported value and accepted without error — but it +never produced a working app for x86 devices: Flutter has no x86 release (AOT) support and has +since removed the target entirely, and the bundled CPython distributions were never built for +x86. The value was silently passed through and effectively ignored. + +## Background + +Flet 0.86.0 reworked the Android build pipeline (see the +[`extract_packages` guide](android-extract-packages.md)): requested ABIs are now explicitly mapped +to Flutter `--target-platform` values and to bundled Python distributions, so an ABI that neither +Flutter nor Python supports is rejected at the start of the build instead of silently doing +nothing. `x86` has also been removed from the build templates and documentation throughout. + +## Migration guide + +Remove `x86` from your architecture lists: + +```toml +[tool.flet.android] +target_arch = ["arm64-v8a", "armeabi-v7a", "x86_64"] # drop "x86" +``` + +or from the command line: + +```bash +flet build apk --arch arm64-v8a x86_64 +``` + +Nothing is lost by dropping it — previous builds never shipped a working x86 app. If you were +targeting x86 for Android *emulators*, use an `x86_64` (or `arm64-v8a`) emulator system image +instead; x86 images are only published for long-obsolete API levels. + +All three supported ABIs — `arm64-v8a`, `x86_64`, and `armeabi-v7a` — are available for +every [bundled Python version](../../../publish/index.md#choosing-a-python-version); see +[supported target architectures](../../../publish/android.md#supported-target-architectures). + +## Timeline + +- Changed in: `0.86.0` + +## References + +- [Android: supported target architectures](../../../publish/android.md#supported-target-architectures) +- [Flutter Android deployment docs](https://docs.flutter.dev/deployment/android) +- Release notes: [Flet 0.86.0](../../release-notes.md) diff --git a/website/docs/updates/breaking-changes/v0-86-0/app-files-unpacked-read-only-bundle.md b/website/docs/updates/breaking-changes/v0-86-0/app-files-unpacked-read-only-bundle.md new file mode 100644 index 0000000000..fa0b2ded40 --- /dev/null +++ b/website/docs/updates/breaking-changes/v0-86-0/app-files-unpacked-read-only-bundle.md @@ -0,0 +1,121 @@ +--- +title: "App files ship unpacked in a read-only bundle; storage dirs reworked" +--- + +# App files ship unpacked in a read-only bundle; storage dirs reworked + +:::note +This guide is accurate as of Flet 0.86.0. Later releases might add new APIs or +additional migration paths. + +The [breaking changes and deprecations index](../index.md) lists the guides created for each release. +::: + +## Summary + +Flet 0.86.0 (with `serious_python` 4.0.0) changes how a packaged app's Python files are shipped and +where the app reads and writes data: + +- **App files ship unpacked inside the app bundle**, next to the Python standard library and + site-packages, on macOS / iOS / Windows / Linux. There is no first-launch `app.zip` extraction. On + **Android** the app ships as a *stored* `app.zip` asset inside the APK and is unpacked once + (version-keyed) to the app's files directory on the first launch after an install/update. Web + (Pyodide) is unchanged. +- The app directory is now **read-only** (signed `.app`, iOS bundle, `Program Files`, the APK). +- The Python program's **current working directory** moved from the app directory to a writable, + app-private data directory, exposed as `FLET_APP_STORAGE_DATA`. +- `FLET_APP_STORAGE_DATA` now maps to the OS *application support* directory (a `data` subdir), + **not** the user's Documents folder. +- The storage env vars are now a clean three-tier set: `FLET_APP_STORAGE_DATA` (durable), + the new **`FLET_APP_STORAGE_CACHE`** (regenerable), and `FLET_APP_STORAGE_TEMP` (now the OS temp + dir, previously the cache dir). +- `flet run` (dev mode) now sets the working directory to a hidden, git-ignored + `/.flet/storage/data`, mirroring a built app. + +## Background + +Previously your Python sources were zipped into `app/app.zip`, shipped as a Flutter asset, and +extracted at runtime on first launch — while the stdlib and site-packages already shipped unpacked +inside the bundle. Lifting app-file handling into `serious_python` removes the first-launch unzip and +the hash bookkeeping, and puts your code in the same place as the stdlib. Because that place is +read-only, the working directory has to move somewhere writable — and the natural home for app data +is the OS *application support* directory, which is app-private on every platform (no Documents +clutter, no manual scoping). + +## Migration guide + +### Write data to the storage dirs, not next to your code + +The app directory is read-only. Relative writes resolve against the **current working directory**, +which is now `FLET_APP_STORAGE_DATA` (a writable, durable, app-private dir). `open("app.db", "w")` and +`sqlite3.connect("app.db")` keep working — the file just lands in the data dir instead of next to your +`.py` files, and now persists across app updates. + +### Read shipped files via `__file__`, not relative paths + +Relative **reads** of files you bundle with your app (e.g. `open("seed.json")`) no longer resolve +against your app folder. Read bundled data relative to your module instead: + +```python +from pathlib import Path + +SEED = Path(__file__).parent / "seed.json" +data = SEED.read_text() +``` + +or use `importlib.resources`, or place the file under your Flet `assets/` directory and resolve it via +`FLET_ASSETS_DIR`. + +### Storage environment variables + +| Variable | Meaning | Lifetime | +| --- | --- | --- | +| `FLET_APP_STORAGE_DATA` | Durable app data (= the working directory) | Never auto-deleted; backed up | +| `FLET_APP_STORAGE_CACHE` | Regenerable cache (**new**) | OS may purge under storage pressure | +| `FLET_APP_STORAGE_TEMP` | OS temp / scratch (**changed** — was the cache dir) | Most volatile; may vanish between launches | + +If you relied on `FLET_APP_STORAGE_TEMP` for data that should survive (it used to be the cache dir), +switch to `FLET_APP_STORAGE_CACHE` (or `FLET_APP_STORAGE_DATA` for must-keep data). + +### Physical locations + +`FLET_APP_STORAGE_DATA` (= the working directory): + +| Platform | Location | +| --- | --- | +| Windows | `%APPDATA%\\\data` (e.g. `C:\Users\\AppData\Roaming\\\data`) | +| macOS | `~/Library/Application Support//data` (sandboxed apps: redirected into the app container) | +| Linux | `${XDG_DATA_HOME:-~/.local/share}//data` | +| iOS | `/Library/Application Support//data` | +| Android | `/data/data//files/data` | +| `flet run` (dev) | `/.flet/storage/data` | + +`FLET_APP_STORAGE_CACHE` and `FLET_APP_STORAGE_TEMP`: + +| Platform | `FLET_APP_STORAGE_CACHE` | `FLET_APP_STORAGE_TEMP` | +| --- | --- | --- | +| Windows | `%LOCALAPPDATA%\\` | `%TEMP%` (`…\AppData\Local\Temp`) | +| macOS | `~/Library/Caches/` | `$TMPDIR` (e.g. `/var/folders/.../T/`) | +| Linux | `${XDG_CACHE_HOME:-~/.cache}/` | system temp (`$TMPDIR`, fallback `/tmp`) | +| iOS | `/Library/Caches/` | `/tmp` | +| Android | `getCacheDir()` (`/data/data//cache`) | same as `CACHE` (`getCacheDir()`) | +| `flet run` (dev) | `/.flet/storage/cache` | `/.flet/storage/temp` | + +### `flet run` dev storage + +`flet run` now creates a hidden `/.flet/` directory (with `storage/{data,cache,temp}`) and +runs your app with the working directory set to `.flet/storage/data`, so dev behaves like a built app +(including the read-shipped-files change above). The directory writes its own `.gitignore` and is +ignored by Git automatically; the old visible `storage/` directory is no longer used. + +## Timeline + +- Changed in: `0.86.0` + +## References + +- Environment variables: [`FLET_APP_STORAGE_DATA`](../../../reference/environment-variables.md#flet_app_storage_data), + [`FLET_APP_STORAGE_CACHE`](../../../reference/environment-variables.md#flet_app_storage_cache), + [`FLET_APP_STORAGE_TEMP`](../../../reference/environment-variables.md#flet_app_storage_temp) +- Cookbook: [Read and write files](../../../cookbook/read-and-write-files.md) +- Release notes: [Flet 0.86.0](../../release-notes.md) diff --git a/website/docs/updates/breaking-changes/v0-86-0/compile-on-by-default.md b/website/docs/updates/breaking-changes/v0-86-0/compile-on-by-default.md new file mode 100644 index 0000000000..bf5ee97629 --- /dev/null +++ b/website/docs/updates/breaking-changes/v0-86-0/compile-on-by-default.md @@ -0,0 +1,78 @@ +--- +title: "App and packages are compiled to .pyc by default" +--- + +# App and packages are compiled to `.pyc` by default + +:::note +This guide is accurate as of Flet 0.86.0. Later releases might add new APIs or +additional migration paths. + +The [breaking changes and deprecations index](../index.md) lists the guides created for each release. +::: + +## Summary + +`flet build` now **compile your app and the installed +packages to `.pyc` by default** (via `python -m compileall -b`, with the original +`.py` files removed from the bundle). Previously compilation was off unless you +opted in with `--compile-app` / `--compile-packages` or +`[tool.flet.compile]` in `pyproject.toml`. + +Shipping bytecode removes per-launch recompilation. The win is largest on +**mobile**, where pure Python is imported from a stored, in-place zip +(`zipimport`) that cannot cache bytecode back to disk — so without precompiled +`.pyc`, every module is recompiled from source on **every** cold start. On a +mid-range Android device this costs roughly 1–2 seconds of startup, scaling with +the number of modules imported. + +## Background + +Compilation has always been available behind the `--compile-app` / +`--compile-packages` flags; it just defaulted off. With the move to in-place +`zipimport` packaging on Android, leaving it off meant a recurring cold-start tax +on every launch, so the default was flipped on. + +Compiled web builds were verified to load correctly in Pyodide: the standalone +CPython used to compile and the Pyodide runtime share the same minor version +(e.g. 3.14), and CPython keeps the `.pyc` magic number stable across patch +releases of a minor version, so the bytecode is accepted. + +## Migration guide + +Most apps need no changes — builds simply start faster. + +If you relied on uncompiled builds (to keep `.py` source in the bundle for +debugging, to let a build complete despite syntax errors, or to speed up +iterative builds), opt out explicitly. + +### Opt out via the CLI flag + +The flags are now `argparse.BooleanOptionalAction`, so each gets a `--no-` form +(the original `--compile-app` / `--compile-packages` still work): + +```bash +flet build apk --no-compile-app --no-compile-packages +``` + +### Opt out in `pyproject.toml` + +```toml +[tool.flet.compile] +app = false +packages = false +``` + +Per-platform overrides also work, e.g. `[tool.flet.android.compile]`. The +resolution order is CLI flag → `[tool.flet..compile]` → +`[tool.flet.compile]` → default (`true`). + +## Timeline + +- Changed in: `0.86.0` + +## References + +- API documentation: [Compilation and cleanup](/docs/publish#compilation-and-cleanup) +- Issues and PRs: [#6598](https://github.com/flet-dev/flet/pull/6598) +- Release notes: [Flet 0.86.0](../../release-notes.md) diff --git a/website/docs/updates/breaking-changes/v0-86-0/data-channel-protocol-upgrade.md b/website/docs/updates/breaking-changes/v0-86-0/data-channel-protocol-upgrade.md new file mode 100644 index 0000000000..c0ea0ded5b --- /dev/null +++ b/website/docs/updates/breaking-changes/v0-86-0/data-channel-protocol-upgrade.md @@ -0,0 +1,111 @@ +--- +title: "Flet protocol framing upgraded for DataChannel support" +--- + +# Flet protocol framing upgraded for DataChannel support + +:::note +This guide is accurate as of Flet 0.86.0. Later releases might add new APIs or +additional migration paths. + +The [breaking changes and deprecations index](../index.md) lists the guides created for each release. +::: + +## Summary + +Flet 0.86.0 introduces dedicated **data channels** for widgets that need to +move bulk binary data (image frames, audio buffers, ML tensors) between Dart +and Python without going through the MsgPack control protocol. + +Enabling this required a one-time upgrade of the Flet protocol's wire format: + +- **Stream-oriented transports** (`flet run` dev mode over UDS / TCP) now use + **4-byte little-endian length-prefixed framing**. The previous streaming + `msgpack.Unpacker.feed` decode is gone. +- **Every transport** (sockets, WebSocket, `dart_bridge` FFI, Pyodide + `postMessage`) now puts a **1-byte type discriminator** at the head of each + packet: + - `0x00` — MsgPack-encoded Flet control frame (widget state, events) — same + contents as before, just with a type byte in front. + - `0x01` — raw DataChannel frame (`[channel_id:u32 LE][payload]`). + +The new format is **not backwards-compatible**: a Flet 0.85 client cannot talk +to a Flet 0.86 server, and vice versa. The `flet-cli` dev server and the +in-process Python runtime were upgraded together in this release. + +## Background + +Flet's previous wire format on UDS / TCP relied on `msgpack.Unpacker.feed` to +re-assemble messages from arbitrary byte-stream chunks. That works for +MsgPack-only traffic but doesn't compose with a second logical stream of raw +bytes — you can't tell a partial MsgPack value from the start of a raw frame +without an out-of-band marker. + +Adding the 1-byte type byte + 4-byte length prefix solves this in the smallest +possible way: + +- Receivers read `[length][type][...]`, fan out by type byte, no streaming + decoder state to maintain. +- Message-oriented transports (WebSocket, `postMessage`, `dart_bridge`) drop + the length prefix since each message is already one packet; they keep the + type byte. +- Per-frame overhead is 5 bytes (message-oriented) or 9 bytes (stream-oriented) + — under 1% at any payload size that motivates a data channel. + +## Migration guide + +### Most users — nothing to change + +If you only use `flet build` artifacts or run `flet run` with the matching +`flet` package version (the default install pulls both at once), there's +nothing to do. The CLI and the runtime are version-locked. + +### Users running `flet-cli` and the `flet` Python package from different installs + +Make sure both come from the same release. The common gotcha is a global +`flet` install plus a project-local `flet` in `.venv` at different versions +— upgrade or pin both to ≥ `0.86.0` (or both to ≤ `0.85.x`). + +A version mismatch will surface as a connection failure during `flet run` +with a parse error in the dev-server log. + +### Users with custom backends or sidecars speaking the Flet protocol + +The wire format changed. Update your encoder/decoder: + +- **Inbound on a stream transport** (UDS / TCP): read 4 bytes (length, u32 LE), + read that many bytes, the first byte is the type discriminator, the rest is + the payload. +- **Inbound on a message transport** (WebSocket, `postMessage`): each + message's first byte is the type discriminator, the rest is the payload. +- **Outbound**: same shape, mirrored. + +Treat `0x01` (raw DataChannel) frames as opaque if you don't use data channels +— forward them along or drop them, never feed them to your MsgPack decoder. + +### Code that depended on `StreamingMsgpackDeserializer` + +The Dart-side class `package:flet/src/transport/streaming_msgpack_deserializer.dart` +is removed. There are no public consumers — it was an internal helper for +stream-transport framing that's no longer needed now that every packet is +length-delimited. If you imported it (you shouldn't have), decode each inbound +buffer with one-shot `msgpack.deserialize(bytes)` instead. + +### Custom widgets that override `MatplotlibChartCanvas` + +`MatplotlibChartCanvas` now transports its `apply_full` / `apply_diff` / +`clear` frames through a [DataChannel] rather than `_invoke_method` arguments. +The Python-facing method signatures are unchanged (`apply_full(image_bytes: +bytes)`, etc.), and they remain the documented API. But if you subclassed the +canvas and overrode the Dart-side `_invokeMethod` handler, that override no +longer fires — the Dart side now consumes a 1-byte opcode + PNG payload from +the channel directly. + +## Timeline + +- Changed in: `0.86.0` + +## References + +- API: `flet.DataChannel` (Python) and `FletBackend.openDataChannel` (Dart) — see the module docstrings in `flet/data_channel.py`; dedicated reference pages will be added in a follow-up. +- Release notes: [Flet 0.86.0](../../release-notes.md) diff --git a/website/docs/updates/breaking-changes/v0-86-0/default-bundled-python-3-14.md b/website/docs/updates/breaking-changes/v0-86-0/default-bundled-python-3-14.md new file mode 100644 index 0000000000..61ad2e3d8d --- /dev/null +++ b/website/docs/updates/breaking-changes/v0-86-0/default-bundled-python-3-14.md @@ -0,0 +1,89 @@ +--- +title: "Default bundled Python version is now 3.14" +--- + +# Default bundled Python version is now 3.14 + +:::note +This guide is accurate as of Flet 0.86.0. Later releases might add new APIs or +additional migration paths. + +The [breaking changes and deprecations index](../index.md) lists the guides created for each release. +::: + +## Summary + +Flet 0.86.0 introduces multi-version bundled CPython support to `flet build` +and `flet publish`. The bundled Python interpreter is now selected per build +(see [Choosing a Python version](/docs/publish#choosing-a-python-version)) and +the **default is the latest supported stable** — currently CPython 3.14. +Earlier Flet releases implicitly bundled CPython 3.12 via the single-version +`serious_python` 1.x. + +Apps that depend on Python packages whose pre-built wheels aren't yet +available for 3.14 (typically packages with C/Rust extensions that haven't +caught up to the new ABI) need to pin a previous Python version. + +## Background + +Multi-version Python support landed in +[#6577](https://github.com/flet-dev/flet/pull/6577) and is tracked by the +central registry in +[`flet_cli/utils/python_versions.py`](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-cli/src/flet_cli/utils/python_versions.py). +The supported short versions are `3.12`, `3.13`, and `3.14` (each pinned to a +specific CPython patch + Pyodide release on the registry side). + +The default flips to the latest stable so new projects get the most recent +Python by default. Existing projects without a pin start picking it up too on +their next build. + +## Migration guide + +You can pin a different Python version in three equivalent ways. Use whichever +fits your project layout. + +### Pin in `pyproject.toml` (recommended) + +Add or update `[project].requires-python`: + +```toml +[project] +requires-python = ">=3.12,<3.13" +``` + +`flet build` parses the specifier and picks the **highest supported short +version** that satisfies it. So `>=3.12,<3.13` resolves to 3.12, +`>=3.13,<3.14` resolves to 3.13, and `>=3.14` resolves to 3.14 (the default). + +### Pin via the CLI flag + +Pass `--python-version` on every invocation: + +```bash +flet build apk --python-version 3.12 +flet publish --python-version 3.12 +``` + +The CLI flag overrides anything in `pyproject.toml`. + +### Pin via environment variable + +Export `SERIOUS_PYTHON_VERSION` in the shell that runs `flet build`: + +```bash +export SERIOUS_PYTHON_VERSION=3.12 +flet build apk +``` + +Useful in CI pipelines where you don't want to thread the flag through every +job. + +## Timeline + +- Changed in: `0.86.0` + +## References + +- API documentation: [Choosing a Python version](/docs/publish#choosing-a-python-version) +- Issues and PRs: [#6577](https://github.com/flet-dev/flet/pull/6577) +- Release notes: [Flet 0.86.0](../../release-notes.md) diff --git a/website/docs/updates/breaking-changes/v0-86-0/deprecated-clear-cache-flag.md b/website/docs/updates/breaking-changes/v0-86-0/deprecated-clear-cache-flag.md new file mode 100644 index 0000000000..a3aec1aef1 --- /dev/null +++ b/website/docs/updates/breaking-changes/v0-86-0/deprecated-clear-cache-flag.md @@ -0,0 +1,59 @@ +--- +title: "flet build --clear-cache flag deprecated" +--- + +# `flet build --clear-cache` flag deprecated + +:::note +This guide is accurate as of Flet 0.86.0. Later releases might add new APIs or +additional migration paths. + +The [breaking changes and deprecations index](../index.md) lists the guides created for each release. +::: + +## Summary + +Flet 0.86.0 deprecated the `--clear-cache` flag of +[`flet build`](../../../cli/flet-build.md) and [`flet debug`](../../../cli/flet-debug.md). + +Use the new [`flet clean`](../../../cli/flet-clean.md) command instead. + +## Context + +`--clear-cache` only deleted the Flutter bootstrap project (`build/flutter`), +and only when the build template hash had changed — so it was a no-op in the +common case and never reset the rest of the `build` directory. + +The new [`flet clean`](../../../cli/flet-clean.md) command deletes the entire +`build` directory (the Flutter bootstrap project, cached artifacts, hash stamps, +and generated output) unconditionally, giving a predictable, full reset before +the next build. + +## Migration guide + +Before: + +```bash +flet build web --clear-cache +``` + +After: + +```bash +flet clean +flet build web +``` + +`flet clean` accepts an optional [path](../../../cli/flet-clean.md#python_app_path) to the app directory (defaults to the +current directory), so you can target another project with `flet clean path/to/app`. + +## Timeline + +- Deprecated in: `0.86.0` +- Removal in: `0.89.0` + +## References + +- CLI documentation: [`flet clean`](../../../cli/flet-clean.md), [`flet build`](../../../cli/flet-build.md) +- Issues and PRs: [#6233](https://github.com/flet-dev/flet/issues/6233) +- Release notes: [Flet 0.86.0](../../release-notes.md) diff --git a/website/docs/updates/breaking-changes/v0-86-0/removed-pyodide-version-export.md b/website/docs/updates/breaking-changes/v0-86-0/removed-pyodide-version-export.md new file mode 100644 index 0000000000..cbc344ca77 --- /dev/null +++ b/website/docs/updates/breaking-changes/v0-86-0/removed-pyodide-version-export.md @@ -0,0 +1,78 @@ +--- +title: "flet.version.pyodide_version and PYODIDE_VERSION removed" +--- + +# `flet.version.pyodide_version` and `PYODIDE_VERSION` removed + +:::note +This guide is accurate as of Flet 0.86.0. Later releases might add new APIs or +additional migration paths. + +The [breaking changes and deprecations index](../index.md) lists the guides created for each release. +::: + +## Summary + +Flet 0.86.0 removed the module-level `flet.version.pyodide_version` attribute +and the matching `PYODIDE_VERSION` constant. The single fixed-string export no +longer makes sense now that Pyodide is selected **per build** as part of the +multi-version bundled Python support — the bundled release depends on which +Python version your app pins, not a global default. + +## Background + +Earlier Flet releases used a single Pyodide pin in `flet.version` to drive the +`flet --version` output and let tooling read which Pyodide release `flet build +web` would bundle. With +[multi-version Python support](/docs/publish#choosing-a-python-version) the +mapping is now Python-version-aware (`3.12 → 0.27.7`, `3.13 → 0.29.4`, +`3.14 → 314.0.0`). It is loaded on demand from +[python-build's date-keyed `manifest.json`](https://github.com/flet-dev/python-build) +— the single source of truth shared with serious_python — via +[`flet_cli/utils/python_versions.py`](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-cli/src/flet_cli/utils/python_versions.py), +so it is no longer hand-maintained. + +## Migration guide + +If you imported the constant somewhere — typically from `flet.version` — +switch to looking the release up from the new registry. + +Code before migration: + +```python +import flet.version + +print(f"Bundled Pyodide: {flet.version.pyodide_version}") +``` + +Code after migration: + +```python +from flet_cli.utils.python_versions import get_supported_python_versions + +for release in get_supported_python_versions(): + print(f" {release.short} → Pyodide {release.pyodide}") +``` + +If you only need the version that `flet build` is about to bundle, resolve +the Python release the same way the CLI does: + +```python +from flet_cli.utils.python_versions import ( + get_default_python_version, + get_release, +) + +release = get_release(get_default_python_version()) +print(f"Default Pyodide: {release.pyodide}") +``` + +## Timeline + +- Removed in: `0.86.0` + +## References + +- API documentation: [Choosing a Python version](/docs/publish#choosing-a-python-version) +- Issues and PRs: [#6577](https://github.com/flet-dev/flet/pull/6577) +- Release notes: [Flet 0.86.0](../../release-notes.md) diff --git a/website/docs/updates/release-notes.md b/website/docs/updates/release-notes.md index 329edee14f..a39a075677 100644 --- a/website/docs/updates/release-notes.md +++ b/website/docs/updates/release-notes.md @@ -8,8 +8,14 @@ This page links release announcements, changelogs, and migration notes for Flet ## Stable releases +### 0.86.x + +- 0.86.0: [Announcement](/blog/flet-v-0-86-release-announcement), [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0860), [Breaking changes and deprecations](breaking-changes/index.md#released-in-flet-0860) + ### 0.85.x +- 0.85.3: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0853) +- 0.85.2: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0852) - 0.85.1: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0851) - 0.85.0: [Announcement](/blog/flet-v-0-85-release-announcement), [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0850), [Breaking changes and deprecations](breaking-changes/index.md#released-in-flet-0850) @@ -213,12 +219,14 @@ This page links release announcements, changelogs, and migration notes for Flet - 0.1.56: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0156) - 0.1.55: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0155) - 0.1.54: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0154) +- 0.1.53: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0153) - 0.1.52: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0152) - 0.1.51: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0151) - 0.1.50: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0150-1) - 0.1.49: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0149) - 0.1.48: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0148) - 0.1.47: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0147) +- 0.1.46: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0146) - 0.1.43: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0143) - 0.1.42: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0142) - 0.1.41: [Changelog](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0141) diff --git a/website/package.json b/website/package.json index ce3c2442c6..1efad5ac9a 100644 --- a/website/package.json +++ b/website/package.json @@ -12,11 +12,11 @@ }, "dependencies": { "@docsearch/docusaurus-adapter": "^4.6.2", - "@docusaurus/core": "^3.10.0", - "@docusaurus/faster": "^3.10.0", - "@docusaurus/plugin-client-redirects": "^3.10.0", - "@docusaurus/preset-classic": "^3.10.0", - "@docusaurus/theme-mermaid": "^3.10.0", + "@docusaurus/core": "^3.10.1", + "@docusaurus/faster": "^3.10.1", + "@docusaurus/plugin-client-redirects": "^3.10.1", + "@docusaurus/preset-classic": "^3.10.1", + "@docusaurus/theme-mermaid": "^3.10.1", "@hcaptcha/react-hcaptcha": "^1.0.0", "@mdx-js/react": "^3.0.0", "clsx": "^1.1.1", diff --git a/website/sidebars.js b/website/sidebars.js deleted file mode 100644 index b052322b52..0000000000 --- a/website/sidebars.js +++ /dev/null @@ -1,4111 +0,0 @@ -// Generated by CrocoDocs from website/sidebars.yml. -// Do not edit by hand. - -module.exports = { - "docs": [ - { - "type": "doc", - "id": "index", - "label": "Introduction" - }, - { - "type": "category", - "label": "Getting started", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "getting-started/installation" - }, - { - "type": "doc", - "id": "getting-started/create-flet-app" - }, - { - "type": "doc", - "id": "getting-started/running-app" - }, - { - "type": "doc", - "id": "getting-started/testing-on-mobile" - } - ] - }, - { - "type": "category", - "label": "Tutorials", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "tutorials/calculator", - "label": "Calculator" - }, - { - "type": "doc", - "id": "tutorials/todo", - "label": "ToDo" - }, - { - "type": "doc", - "id": "tutorials/chat", - "label": "Chat" - }, - { - "type": "doc", - "id": "tutorials/solitaire", - "label": "Solitaire" - } - ] - }, - { - "type": "category", - "label": "Cookbook", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "cookbook/expanding-controls", - "label": "Expanding Controls" - }, - { - "type": "doc", - "id": "cookbook/colors", - "label": "Colors" - }, - { - "type": "doc", - "id": "cookbook/fonts", - "label": "Fonts" - }, - { - "type": "doc", - "id": "cookbook/theming", - "label": "Theming" - }, - { - "type": "doc", - "id": "cookbook/assets", - "label": "Assets" - }, - { - "type": "doc", - "id": "cookbook/animations", - "label": "Animations" - }, - { - "type": "doc", - "id": "cookbook/adaptive-apps", - "label": "Adaptive apps" - }, - { - "type": "doc", - "id": "cookbook/keyboard-shortcuts", - "label": "Keyboard Shortcuts" - }, - { - "type": "doc", - "id": "cookbook/drag-and-drop", - "label": "Drag and Drop" - }, - { - "type": "doc", - "id": "cookbook/large-lists", - "label": "Large Lists" - }, - { - "type": "doc", - "id": "cookbook/accessibility", - "label": "Accessibility" - }, - { - "type": "doc", - "id": "cookbook/navigation-and-routing", - "label": "Navigation and Routing" - }, - { - "type": "doc", - "id": "cookbook/router", - "label": "Router" - }, - { - "type": "doc", - "id": "cookbook/control-refs", - "label": "Control Refs" - }, - { - "type": "doc", - "id": "cookbook/custom-controls", - "label": "Custom Controls" - }, - { - "type": "doc", - "id": "cookbook/declarative-vs-imperative-crud-app", - "label": "Declarative vs Imperative CRUD app" - }, - { - "type": "doc", - "id": "cookbook/async-apps", - "label": "Async apps" - }, - { - "type": "doc", - "id": "cookbook/read-and-write-files", - "label": "Read and Write Files" - }, - { - "type": "doc", - "id": "cookbook/client-storage", - "label": "Client Storage" - }, - { - "type": "doc", - "id": "cookbook/session-storage", - "label": "Session Storage" - }, - { - "type": "doc", - "id": "cookbook/pub-sub", - "label": "PubSub" - }, - { - "type": "doc", - "id": "cookbook/subprocess", - "label": "Subprocess" - }, - { - "type": "doc", - "id": "cookbook/logging", - "label": "Logging" - }, - { - "type": "doc", - "id": "cookbook/authentication", - "label": "Authentication" - }, - { - "type": "doc", - "id": "cookbook/encrypting-sensitive-data", - "label": "Encrypting sensitive data" - }, - { - "type": "doc", - "id": "cookbook/declarative-dialogs", - "label": "Declarative dialogs" - } - ] - }, - { - "type": "category", - "label": "Publishing Flet app", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "publish/android", - "label": "Android" - }, - { - "type": "doc", - "id": "publish/ios", - "label": "iOS" - }, - { - "type": "doc", - "id": "publish/linux", - "label": "Linux" - }, - { - "type": "doc", - "id": "publish/macos", - "label": "macOS" - }, - { - "type": "doc", - "id": "publish/windows", - "label": "Windows" - }, - { - "type": "category", - "label": "Web", - "collapsed": true, - "items": [ - { - "type": "category", - "label": "Dynamic Website", - "collapsed": true, - "items": [ - { - "type": "category", - "label": "Hosting", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "publish/web/dynamic-website/hosting/fly-io", - "label": "Fly.io" - }, - { - "type": "doc", - "id": "publish/web/dynamic-website/hosting/replit", - "label": "Replit" - }, - { - "type": "doc", - "id": "publish/web/dynamic-website/hosting/self-hosting", - "label": "Self-Hosting" - } - ], - "link": { - "type": "doc", - "id": "publish/web/dynamic-website/hosting/index" - } - } - ], - "link": { - "type": "doc", - "id": "publish/web/dynamic-website/index" - } - }, - { - "type": "category", - "label": "Static Website", - "collapsed": true, - "items": [ - { - "type": "category", - "label": "Hosting", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "publish/web/static-website/hosting/cloudflare", - "label": "Cloudflare" - }, - { - "type": "doc", - "id": "publish/web/static-website/hosting/github-pages", - "label": "GitHub Pages" - } - ] - } - ], - "link": { - "type": "doc", - "id": "publish/web/static-website/index" - } - } - ], - "link": { - "type": "doc", - "id": "publish/web/index" - } - } - ], - "link": { - "type": "doc", - "id": "publish/index" - } - }, - { - "type": "category", - "label": "Extending Flet", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "extend/user-extensions" - }, - { - "type": "doc", - "id": "extend/built-in-extensions" - } - ] - }, - { - "type": "category", - "label": "Stay up to date", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "updates/release-notes", - "label": "Release notes" - }, - { - "type": "category", - "label": "Breaking changes and deprecations", - "collapsed": true, - "items": [ - { - "type": "category", - "label": "v0.85.0", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "updates/breaking-changes/removed-spacing-border-helpers", - "label": "Deprecated spacing and border helper functions removed" - }, - { - "type": "doc", - "id": "updates/breaking-changes/deprecated-drag-target-event-coordinates", - "label": "DragTargetEvent coordinate fields deprecated" - }, - { - "type": "doc", - "id": "updates/breaking-changes/deprecated-video-apis", - "label": "Video control APIs deprecated" - } - ] - } - ], - "link": { - "type": "doc", - "id": "updates/breaking-changes/index" - } - }, - { - "type": "doc", - "id": "updates/compatibility-policy", - "label": "Compatibility policy" - } - ], - "link": { - "type": "doc", - "id": "updates/index" - } - }, - { - "type": "category", - "label": "Reference", - "collapsed": true, - "items": [ - { - "type": "category", - "label": "Controls", - "collapsed": true, - "items": [ - { - "type": "category", - "label": "Ads", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/ads/bannerad", - "label": "BannerAd" - }, - { - "type": "doc", - "id": "controls/ads/basead", - "label": "BaseAd" - }, - { - "type": "doc", - "id": "controls/ads/interstitialad", - "label": "InterstitialAd" - } - ], - "link": { - "type": "doc", - "id": "controls/ads/index" - } - }, - { - "type": "doc", - "id": "controls/alertdialog", - "label": "AlertDialog" - }, - { - "type": "doc", - "id": "controls/animatedswitcher", - "label": "AnimatedSwitcher" - }, - { - "type": "doc", - "id": "controls/appbar", - "label": "AppBar" - }, - { - "type": "doc", - "id": "controls/autocomplete", - "label": "AutoComplete" - }, - { - "type": "doc", - "id": "controls/autofillgroup", - "label": "AutofillGroup" - }, - { - "type": "doc", - "id": "types/badge", - "label": "Badge" - }, - { - "type": "doc", - "id": "controls/banner", - "label": "Banner" - }, - { - "type": "doc", - "id": "controls/bottomappbar", - "label": "BottomAppBar" - }, - { - "type": "doc", - "id": "controls/bottomsheet", - "label": "BottomSheet" - }, - { - "type": "doc", - "id": "controls/button", - "label": "Button" - }, - { - "type": "doc", - "id": "controls/camera/index", - "label": "Camera" - }, - { - "type": "category", - "label": "Canvas", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/canvas/arc", - "label": "Arc" - }, - { - "type": "doc", - "id": "controls/canvas/circle", - "label": "Circle" - }, - { - "type": "doc", - "id": "controls/canvas/color", - "label": "Color" - }, - { - "type": "doc", - "id": "controls/canvas/fill", - "label": "Fill" - }, - { - "type": "doc", - "id": "controls/canvas/image", - "label": "Image" - }, - { - "type": "doc", - "id": "controls/canvas/line", - "label": "Line" - }, - { - "type": "doc", - "id": "controls/canvas/oval", - "label": "Oval" - }, - { - "type": "doc", - "id": "controls/canvas/path", - "label": "Path" - }, - { - "type": "doc", - "id": "controls/canvas/points", - "label": "Points" - }, - { - "type": "doc", - "id": "controls/canvas/rect", - "label": "Rect" - }, - { - "type": "doc", - "id": "controls/canvas/shadow", - "label": "Shadow" - }, - { - "type": "doc", - "id": "controls/canvas/shape", - "label": "Shape" - }, - { - "type": "doc", - "id": "controls/canvas/text", - "label": "Text" - } - ], - "link": { - "type": "doc", - "id": "controls/canvas/index" - } - }, - { - "type": "doc", - "id": "controls/card", - "label": "Card" - }, - { - "type": "category", - "label": "Charts", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/charts/barchart", - "label": "BarChart" - }, - { - "type": "doc", - "id": "controls/charts/candlestickchart", - "label": "CandlestickChart" - }, - { - "type": "doc", - "id": "controls/charts/linechart", - "label": "LineChart" - }, - { - "type": "doc", - "id": "controls/charts/matplotlibchart", - "label": "MatplotlibChart" - }, - { - "type": "doc", - "id": "controls/charts/matplotlibchartwithtoolbar", - "label": "MatplotlibChartWithToolbar" - }, - { - "type": "doc", - "id": "controls/charts/piechart", - "label": "PieChart" - }, - { - "type": "doc", - "id": "controls/charts/plotlychart", - "label": "PlotlyChart" - }, - { - "type": "doc", - "id": "controls/charts/radarchart", - "label": "RadarChart" - }, - { - "type": "doc", - "id": "controls/charts/scatterchart", - "label": "ScatterChart" - } - ], - "link": { - "type": "doc", - "id": "controls/charts/index" - } - }, - { - "type": "doc", - "id": "controls/checkbox", - "label": "Checkbox" - }, - { - "type": "doc", - "id": "controls/chip", - "label": "Chip" - }, - { - "type": "doc", - "id": "controls/circleavatar", - "label": "CircleAvatar" - }, - { - "type": "doc", - "id": "controls/codeeditor/index", - "label": "CodeEditor" - }, - { - "type": "category", - "label": "Color pickers", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/colorpickers/colorpicker", - "label": "ColorPicker" - }, - { - "type": "doc", - "id": "controls/colorpickers/blockpicker", - "label": "BlockPicker" - }, - { - "type": "doc", - "id": "controls/colorpickers/hueringpicker", - "label": "HueRingPicker" - }, - { - "type": "doc", - "id": "controls/colorpickers/materialpicker", - "label": "MaterialPicker" - }, - { - "type": "doc", - "id": "controls/colorpickers/multiplechoiceblockpicker", - "label": "MultipleChoiceBlockPicker" - }, - { - "type": "doc", - "id": "controls/colorpickers/slidepicker", - "label": "SlidePicker" - } - ], - "link": { - "type": "doc", - "id": "controls/colorpickers/index" - } - }, - { - "type": "doc", - "id": "controls/column", - "label": "Column" - }, - { - "type": "doc", - "id": "controls/container", - "label": "Container" - }, - { - "type": "doc", - "id": "controls/contextmenu", - "label": "ContextMenu" - }, - { - "type": "category", - "label": "CupertinoActionSheet", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/cupertinoactionsheetaction", - "label": "CupertinoActionSheetAction" - } - ], - "link": { - "type": "doc", - "id": "controls/cupertinoactionsheet/index" - } - }, - { - "type": "doc", - "id": "controls/cupertinoactivityindicator", - "label": "CupertinoActivityIndicator" - }, - { - "type": "doc", - "id": "controls/cupertinoalertdialog", - "label": "CupertinoAlertDialog" - }, - { - "type": "doc", - "id": "controls/cupertinoappbar", - "label": "CupertinoAppBar" - }, - { - "type": "doc", - "id": "controls/cupertinobottomsheet", - "label": "CupertinoBottomSheet" - }, - { - "type": "doc", - "id": "controls/cupertinobutton", - "label": "CupertinoButton" - }, - { - "type": "doc", - "id": "controls/cupertinocheckbox", - "label": "CupertinoCheckbox" - }, - { - "type": "category", - "label": "CupertinoContextMenu", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/cupertinocontextmenuaction", - "label": "CupertinoContextMenuAction" - } - ], - "link": { - "type": "doc", - "id": "controls/cupertinocontextmenu/index" - } - }, - { - "type": "doc", - "id": "controls/cupertinodatepicker", - "label": "CupertinoDatePicker" - }, - { - "type": "doc", - "id": "controls/cupertinodialogaction", - "label": "CupertinoDialogAction" - }, - { - "type": "doc", - "id": "controls/cupertinofilledbutton", - "label": "CupertinoFilledButton" - }, - { - "type": "doc", - "id": "controls/cupertinolisttile", - "label": "CupertinoListTile" - }, - { - "type": "doc", - "id": "controls/cupertinonavigationbar", - "label": "CupertinoNavigationBar" - }, - { - "type": "doc", - "id": "controls/cupertinopicker", - "label": "CupertinoPicker" - }, - { - "type": "doc", - "id": "controls/cupertinoradio", - "label": "CupertinoRadio" - }, - { - "type": "doc", - "id": "controls/cupertinosegmentedbutton", - "label": "CupertinoSegmentedButton" - }, - { - "type": "doc", - "id": "controls/cupertinoslider", - "label": "CupertinoSlider" - }, - { - "type": "doc", - "id": "controls/cupertinoslidingsegmentedbutton", - "label": "CupertinoSlidingSegmentedButton" - }, - { - "type": "doc", - "id": "controls/cupertinoswitch", - "label": "CupertinoSwitch" - }, - { - "type": "doc", - "id": "controls/cupertinotextfield", - "label": "CupertinoTextField" - }, - { - "type": "doc", - "id": "controls/cupertinotimerpicker", - "label": "CupertinoTimerPicker" - }, - { - "type": "doc", - "id": "controls/cupertinotintedbutton", - "label": "CupertinoTintedButton" - }, - { - "type": "doc", - "id": "controls/datepicker", - "label": "DatePicker" - }, - { - "type": "doc", - "id": "controls/daterangepicker", - "label": "DateRangePicker" - }, - { - "type": "category", - "label": "DataTable", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/datacell", - "label": "DataCell" - }, - { - "type": "doc", - "id": "controls/datacolumn", - "label": "DataColumn" - }, - { - "type": "doc", - "id": "controls/datarow", - "label": "DataRow" - } - ], - "link": { - "type": "doc", - "id": "controls/datatable/index" - } - }, - { - "type": "category", - "label": "DataTable2", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/datatable2/datacolumn2", - "label": "DataColumn2" - }, - { - "type": "doc", - "id": "controls/datatable2/datarow2", - "label": "DataRow2" - } - ], - "link": { - "type": "doc", - "id": "controls/datatable2/index" - } - }, - { - "type": "doc", - "id": "controls/dismissible", - "label": "Dismissible" - }, - { - "type": "doc", - "id": "controls/divider", - "label": "Divider" - }, - { - "type": "doc", - "id": "controls/dragtarget", - "label": "DragTarget" - }, - { - "type": "doc", - "id": "controls/draggable", - "label": "Draggable" - }, - { - "type": "category", - "label": "Dropdown", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/dropdownoption", - "label": "DropdownOption" - } - ], - "link": { - "type": "doc", - "id": "controls/dropdown/index" - } - }, - { - "type": "doc", - "id": "controls/expansionpanel", - "label": "ExpansionPanel" - }, - { - "type": "doc", - "id": "controls/expansionpanellist", - "label": "ExpansionPanelList" - }, - { - "type": "doc", - "id": "controls/expansiontile", - "label": "ExpansionTile" - }, - { - "type": "doc", - "id": "controls/filledbutton", - "label": "FilledButton" - }, - { - "type": "doc", - "id": "controls/fillediconbutton", - "label": "FilledIconButton" - }, - { - "type": "doc", - "id": "controls/filledtonalbutton", - "label": "FilledTonalButton" - }, - { - "type": "doc", - "id": "controls/filledtonaliconbutton", - "label": "FilledTonalIconButton" - }, - { - "type": "doc", - "id": "controls/fletapp", - "label": "FletApp" - }, - { - "type": "doc", - "id": "controls/floatingactionbutton", - "label": "FloatingActionButton" - }, - { - "type": "doc", - "id": "controls/gesturedetector", - "label": "GestureDetector" - }, - { - "type": "doc", - "id": "controls/gridview", - "label": "GridView" - }, - { - "type": "doc", - "id": "controls/hero", - "label": "Hero" - }, - { - "type": "doc", - "id": "controls/icon", - "label": "Icon" - }, - { - "type": "doc", - "id": "controls/iconbutton", - "label": "IconButton" - }, - { - "type": "doc", - "id": "controls/image", - "label": "Image" - }, - { - "type": "doc", - "id": "controls/interactiveviewer", - "label": "InteractiveViewer" - }, - { - "type": "doc", - "id": "controls/keyboardlistener", - "label": "KeyboardListener" - }, - { - "type": "doc", - "id": "controls/listtile", - "label": "ListTile" - }, - { - "type": "doc", - "id": "controls/listview", - "label": "ListView" - }, - { - "type": "doc", - "id": "controls/lottie/index", - "label": "Lottie" - }, - { - "type": "category", - "label": "Map", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/map/mapcontrol", - "label": "Map" - }, - { - "type": "category", - "label": "Layers", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/map/maplayer" - }, - { - "type": "doc", - "id": "controls/map/tilelayer" - }, - { - "type": "doc", - "id": "controls/map/markerlayer" - }, - { - "type": "doc", - "id": "controls/map/overlayimagelayer" - }, - { - "type": "doc", - "id": "controls/map/circlelayer" - }, - { - "type": "doc", - "id": "controls/map/polygonlayer" - }, - { - "type": "doc", - "id": "controls/map/polylinelayer" - } - ] - }, - { - "type": "category", - "label": "Markers", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/map/marker" - }, - { - "type": "doc", - "id": "controls/map/circlemarker" - }, - { - "type": "doc", - "id": "controls/map/polygonmarker" - }, - { - "type": "doc", - "id": "controls/map/polylinemarker" - } - ] - }, - { - "type": "category", - "label": "Overlays", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/map/baseoverlayimage" - }, - { - "type": "doc", - "id": "controls/map/overlayimage" - }, - { - "type": "doc", - "id": "controls/map/rotatedoverlayimage" - } - ] - }, - { - "type": "category", - "label": "Attributions", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/map/sourceattribution" - }, - { - "type": "doc", - "id": "controls/map/simpleattribution" - }, - { - "type": "doc", - "id": "controls/map/richattribution" - }, - { - "type": "doc", - "id": "controls/map/textsourceattribution" - }, - { - "type": "doc", - "id": "controls/map/imagesourceattribution" - } - ] - } - ], - "link": { - "type": "doc", - "id": "controls/map/index" - } - }, - { - "type": "doc", - "id": "controls/markdown", - "label": "Markdown" - }, - { - "type": "doc", - "id": "controls/menubar", - "label": "MenuBar" - }, - { - "type": "doc", - "id": "controls/menuitembutton", - "label": "MenuItemButton" - }, - { - "type": "doc", - "id": "controls/mergesemantics", - "label": "MergeSemantics" - }, - { - "type": "doc", - "id": "controls/multiview", - "label": "MultiView" - }, - { - "type": "category", - "label": "NavigationBar", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/navigationbardestination", - "label": "NavigationBarDestination" - } - ], - "link": { - "type": "doc", - "id": "controls/navigationbar/index" - } - }, - { - "type": "category", - "label": "NavigationDrawer", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/navigationdrawerdestination", - "label": "NavigationDrawerDestination" - } - ], - "link": { - "type": "doc", - "id": "controls/navigationdrawer/index" - } - }, - { - "type": "category", - "label": "NavigationRail", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/navigationraildestination", - "label": "NavigationRailDestination" - } - ], - "link": { - "type": "doc", - "id": "controls/navigationrail/index" - } - }, - { - "type": "doc", - "id": "controls/outlinedbutton", - "label": "OutlinedButton" - }, - { - "type": "doc", - "id": "controls/outlinediconbutton", - "label": "OutlinedIconButton" - }, - { - "type": "doc", - "id": "controls/page", - "label": "Page" - }, - { - "type": "doc", - "id": "controls/pagelet", - "label": "Pagelet" - }, - { - "type": "doc", - "id": "controls/pageview", - "label": "PageView" - }, - { - "type": "doc", - "id": "controls/placeholder", - "label": "Placeholder" - }, - { - "type": "doc", - "id": "controls/popupmenubutton", - "label": "PopupMenuButton" - }, - { - "type": "doc", - "id": "controls/progressbar", - "label": "ProgressBar" - }, - { - "type": "doc", - "id": "controls/progressring", - "label": "ProgressRing" - }, - { - "type": "doc", - "id": "controls/radio", - "label": "Radio" - }, - { - "type": "doc", - "id": "controls/radiogroup", - "label": "RadioGroup" - }, - { - "type": "doc", - "id": "controls/rangeslider", - "label": "RangeSlider" - }, - { - "type": "doc", - "id": "controls/reorderabledraghandle", - "label": "ReorderableDragHandle" - }, - { - "type": "doc", - "id": "controls/reorderablelistview", - "label": "ReorderableListView" - }, - { - "type": "doc", - "id": "controls/responsiverow", - "label": "ResponsiveRow" - }, - { - "type": "doc", - "id": "controls/rotatedbox", - "label": "RotatedBox" - }, - { - "type": "doc", - "id": "controls/router", - "label": "Router" - }, - { - "type": "doc", - "id": "controls/row", - "label": "Row" - }, - { - "type": "doc", - "id": "controls/rive/index", - "label": "Rive" - }, - { - "type": "doc", - "id": "controls/safearea", - "label": "SafeArea" - }, - { - "type": "doc", - "id": "controls/searchbar", - "label": "SearchBar" - }, - { - "type": "category", - "label": "SegmentedButton", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/segment", - "label": "Segment" - } - ], - "link": { - "type": "doc", - "id": "controls/segmentedbutton/index" - } - }, - { - "type": "doc", - "id": "controls/selectionarea", - "label": "SelectionArea" - }, - { - "type": "doc", - "id": "controls/semantics", - "label": "Semantics" - }, - { - "type": "doc", - "id": "controls/screenshot", - "label": "Screenshot" - }, - { - "type": "doc", - "id": "controls/shadermask", - "label": "ShaderMask" - }, - { - "type": "doc", - "id": "controls/shimmer", - "label": "Shimmer" - }, - { - "type": "category", - "label": "SpinKit", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/spinkit/chasingdots", - "label": "ChasingDots" - }, - { - "type": "doc", - "id": "controls/spinkit/circle", - "label": "Circle" - }, - { - "type": "doc", - "id": "controls/spinkit/cubegrid", - "label": "CubeGrid" - }, - { - "type": "doc", - "id": "controls/spinkit/dancingsquare", - "label": "DancingSquare" - }, - { - "type": "doc", - "id": "controls/spinkit/doublebounce", - "label": "DoubleBounce" - }, - { - "type": "doc", - "id": "controls/spinkit/dualring", - "label": "DualRing" - }, - { - "type": "doc", - "id": "controls/spinkit/fadingcircle", - "label": "FadingCircle" - }, - { - "type": "doc", - "id": "controls/spinkit/fadingcube", - "label": "FadingCube" - }, - { - "type": "doc", - "id": "controls/spinkit/fadingfour", - "label": "FadingFour" - }, - { - "type": "doc", - "id": "controls/spinkit/fadinggrid", - "label": "FadingGrid" - }, - { - "type": "doc", - "id": "controls/spinkit/foldingcube", - "label": "FoldingCube" - }, - { - "type": "doc", - "id": "controls/spinkit/hourglass", - "label": "HourGlass" - }, - { - "type": "doc", - "id": "controls/spinkit/pianowave", - "label": "PianoWave" - }, - { - "type": "doc", - "id": "controls/spinkit/pouringhourglass", - "label": "PouringHourGlass" - }, - { - "type": "doc", - "id": "controls/spinkit/pouringhourglassrefined", - "label": "PouringHourGlassRefined" - }, - { - "type": "doc", - "id": "controls/spinkit/pulse", - "label": "Pulse" - }, - { - "type": "doc", - "id": "controls/spinkit/pulsinggrid", - "label": "PulsingGrid" - }, - { - "type": "doc", - "id": "controls/spinkit/pumpingheart", - "label": "PumpingHeart" - }, - { - "type": "doc", - "id": "controls/spinkit/ring", - "label": "Ring" - }, - { - "type": "doc", - "id": "controls/spinkit/ripple", - "label": "Ripple" - }, - { - "type": "doc", - "id": "controls/spinkit/rotatingcircle", - "label": "RotatingCircle" - }, - { - "type": "doc", - "id": "controls/spinkit/rotatingplain", - "label": "RotatingPlain" - }, - { - "type": "doc", - "id": "controls/spinkit/spinningcircle", - "label": "SpinningCircle" - }, - { - "type": "doc", - "id": "controls/spinkit/spinninglines", - "label": "SpinningLines" - }, - { - "type": "doc", - "id": "controls/spinkit/squarecircle", - "label": "SquareCircle" - }, - { - "type": "doc", - "id": "controls/spinkit/threebounce", - "label": "ThreeBounce" - }, - { - "type": "doc", - "id": "controls/spinkit/threeinout", - "label": "ThreeInOut" - }, - { - "type": "doc", - "id": "controls/spinkit/wanderingcubes", - "label": "WanderingCubes" - }, - { - "type": "doc", - "id": "controls/spinkit/wave", - "label": "Wave" - }, - { - "type": "doc", - "id": "controls/spinkit/wavespinner", - "label": "WaveSpinner" - }, - { - "type": "doc", - "id": "controls/spinkit/wavetype", - "label": "WaveType" - } - ], - "link": { - "type": "doc", - "id": "controls/spinkit/index" - } - }, - { - "type": "doc", - "id": "controls/slider", - "label": "Slider" - }, - { - "type": "doc", - "id": "controls/snackbar", - "label": "SnackBar" - }, - { - "type": "doc", - "id": "controls/stack", - "label": "Stack" - }, - { - "type": "doc", - "id": "controls/submenubutton", - "label": "SubmenuButton" - }, - { - "type": "doc", - "id": "controls/switch", - "label": "Switch" - }, - { - "type": "category", - "label": "Tabs", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/tab", - "label": "Tab" - }, - { - "type": "doc", - "id": "controls/tabbar", - "label": "TabBar" - }, - { - "type": "doc", - "id": "controls/tabbarview", - "label": "TabBarView" - } - ], - "link": { - "type": "doc", - "id": "controls/tabs/index" - } - }, - { - "type": "doc", - "id": "controls/text", - "label": "Text" - }, - { - "type": "doc", - "id": "controls/textbutton", - "label": "TextButton" - }, - { - "type": "doc", - "id": "controls/textfield", - "label": "TextField" - }, - { - "type": "doc", - "id": "controls/timepicker", - "label": "TimePicker" - }, - { - "type": "doc", - "id": "controls/transparentpointer", - "label": "TransparentPointer" - }, - { - "type": "doc", - "id": "controls/verticaldivider", - "label": "VerticalDivider" - }, - { - "type": "doc", - "id": "controls/video/index", - "label": "Video" - }, - { - "type": "doc", - "id": "controls/view", - "label": "View" - }, - { - "type": "doc", - "id": "controls/webview/index", - "label": "WebView" - }, - { - "type": "doc", - "id": "controls/windowdragarea", - "label": "WindowDragArea" - } - ], - "link": { - "type": "generated-index", - "title": "Controls", - "slug": "/controls", - "description": "Browse the complete catalog of controls available in Flet." - } - }, - { - "type": "category", - "label": "Services", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "services/accelerometer", - "label": "Accelerometer" - }, - { - "type": "doc", - "id": "services/audio/index", - "label": "Audio" - }, - { - "type": "doc", - "id": "services/audiorecorder/index", - "label": "AudioRecorder" - }, - { - "type": "doc", - "id": "services/barometer", - "label": "Barometer" - }, - { - "type": "doc", - "id": "services/battery", - "label": "Battery" - }, - { - "type": "doc", - "id": "services/browsercontextmenu", - "label": "BrowserContextMenu" - }, - { - "type": "doc", - "id": "services/clipboard", - "label": "Clipboard" - }, - { - "type": "doc", - "id": "services/connectivity", - "label": "Connectivity" - }, - { - "type": "doc", - "id": "services/filepicker", - "label": "FilePicker" - }, - { - "type": "doc", - "id": "services/flashlight/index", - "label": "Flashlight" - }, - { - "type": "doc", - "id": "services/geolocator/index", - "label": "Geolocator" - }, - { - "type": "doc", - "id": "services/gyroscope", - "label": "Gyroscope" - }, - { - "type": "doc", - "id": "services/hapticfeedback", - "label": "HapticFeedback" - }, - { - "type": "doc", - "id": "services/magnetometer", - "label": "Magnetometer" - }, - { - "type": "doc", - "id": "services/permissionhandler/index", - "label": "PermissionHandler" - }, - { - "type": "doc", - "id": "services/screenbrightness", - "label": "ScreenBrightness" - }, - { - "type": "doc", - "id": "services/semanticsservice", - "label": "SemanticsService" - }, - { - "type": "doc", - "id": "services/shakedetector", - "label": "ShakeDetector" - }, - { - "type": "doc", - "id": "services/share", - "label": "Share" - }, - { - "type": "doc", - "id": "services/securestorage/index", - "label": "SecureStorage" - }, - { - "type": "doc", - "id": "services/sharedpreferences", - "label": "SharedPreferences" - }, - { - "type": "doc", - "id": "services/storagepaths", - "label": "StoragePaths" - }, - { - "type": "doc", - "id": "services/urllauncher", - "label": "UrlLauncher" - }, - { - "type": "doc", - "id": "services/useraccelerometer", - "label": "UserAccelerometer" - }, - { - "type": "doc", - "id": "services/wakelock", - "label": "Wakelock" - } - ], - "link": { - "type": "generated-index", - "title": "Services", - "slug": "/services", - "description": "Browse the complete catalog of services available in Flet." - } - }, - { - "type": "category", - "label": "Types", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "types/aliases", - "label": "Aliases" - }, - { - "type": "category", - "label": "Authentication", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "types/auth/authorization" - }, - { - "type": "doc", - "id": "types/auth/authorizationservice" - }, - { - "type": "doc", - "id": "types/auth/group" - }, - { - "type": "doc", - "id": "types/auth/oauthtoken" - }, - { - "type": "category", - "label": "OAuthProvider", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "types/auth/auth0oauthprovider", - "label": "Auth0OAuthProvider" - }, - { - "type": "doc", - "id": "types/auth/azureoauthprovider", - "label": "AzureOAuthProvider" - }, - { - "type": "doc", - "id": "types/auth/githuboauthprovider", - "label": "GitHubOAuthProvider" - }, - { - "type": "doc", - "id": "types/auth/googleoauthprovider", - "label": "GoogleOAuthProvider" - } - ], - "link": { - "type": "doc", - "id": "types/auth/oauthprovider/index" - } - }, - { - "type": "doc", - "id": "types/auth/user" - } - ] - }, - { - "type": "category", - "label": "Base Controls", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/adaptivecontrol" - }, - { - "type": "doc", - "id": "controls/basecontrol" - }, - { - "type": "doc", - "id": "controls/basepage" - }, - { - "type": "doc", - "id": "controls/control" - }, - { - "type": "doc", - "id": "controls/dialogcontrol" - }, - { - "type": "doc", - "id": "controls/formfieldcontrol" - }, - { - "type": "doc", - "id": "controls/layoutcontrol" - }, - { - "type": "doc", - "id": "controls/scrollablecontrol" - }, - { - "type": "doc", - "id": "controls/service" - }, - { - "type": "doc", - "id": "types/window" - } - ] - }, - { - "type": "category", - "label": "Classes", - "collapsed": true, - "items": [ - { - "type": "category", - "label": "Ads", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/ads/types/adrequest" - } - ] - }, - { - "type": "doc", - "id": "types/alignment" - }, - { - "type": "doc", - "id": "types/androidbuildversion" - }, - { - "type": "doc", - "id": "types/animation" - }, - { - "type": "doc", - "id": "types/animationstyle" - }, - { - "type": "category", - "label": "Audio", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "services/audio/types/audiodurationchangeevent" - }, - { - "type": "doc", - "id": "services/audio/types/audiopositionchangeevent" - }, - { - "type": "doc", - "id": "services/audio/types/audiostatechangeevent" - }, - { - "type": "doc", - "id": "services/audio/types/audiostate" - }, - { - "type": "doc", - "id": "services/audio/types/releasemode" - } - ] - }, - { - "type": "category", - "label": "AudioRecorder", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "services/audiorecorder/types/androidaudiosource" - }, - { - "type": "doc", - "id": "services/audiorecorder/types/androidrecorderconfiguration" - }, - { - "type": "doc", - "id": "services/audiorecorder/types/audioencoder" - }, - { - "type": "doc", - "id": "services/audiorecorder/types/audiorecorderconfiguration" - }, - { - "type": "doc", - "id": "services/audiorecorder/types/audiorecorderstatechangeevent" - }, - { - "type": "doc", - "id": "services/audiorecorder/types/audiorecorderstreamevent" - }, - { - "type": "doc", - "id": "services/audiorecorder/types/audiorecorderstate" - }, - { - "type": "doc", - "id": "services/audiorecorder/types/audiorecorderuploadevent" - }, - { - "type": "doc", - "id": "services/audiorecorder/types/audiorecorderuploadsettings" - }, - { - "type": "doc", - "id": "services/audiorecorder/types/inputdevice" - }, - { - "type": "doc", - "id": "services/audiorecorder/types/iosaudiocategoryoption" - }, - { - "type": "doc", - "id": "services/audiorecorder/types/iosrecorderconfiguration" - } - ] - }, - { - "type": "doc", - "id": "types/autocompletesuggestion" - }, - { - "type": "doc", - "id": "types/blur" - }, - { - "type": "doc", - "id": "types/border" - }, - { - "type": "doc", - "id": "types/borderradius" - }, - { - "type": "doc", - "id": "types/borderside" - }, - { - "type": "doc", - "id": "types/boxconstraints" - }, - { - "type": "doc", - "id": "types/boxdecoration" - }, - { - "type": "doc", - "id": "types/boxshadow" - }, - { - "type": "doc", - "id": "types/buttonstyle" - }, - { - "type": "category", - "label": "Camera", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/camera/types/cameradescription" - }, - { - "type": "doc", - "id": "controls/camera/types/cameraimageevent" - }, - { - "type": "doc", - "id": "controls/camera/types/cameralensdirection" - }, - { - "type": "doc", - "id": "controls/camera/types/cameralenstype" - }, - { - "type": "doc", - "id": "controls/camera/types/camerapreviewsize" - }, - { - "type": "doc", - "id": "controls/camera/types/camerastateevent" - }, - { - "type": "doc", - "id": "controls/camera/types/exposuremode" - }, - { - "type": "doc", - "id": "controls/camera/types/flashmode" - }, - { - "type": "doc", - "id": "controls/camera/types/focusmode" - }, - { - "type": "doc", - "id": "controls/camera/types/imageformatgroup" - }, - { - "type": "doc", - "id": "controls/camera/types/resolutionpreset" - } - ] - }, - { - "type": "category", - "label": "Charts", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/charts/types/barchartevent" - }, - { - "type": "doc", - "id": "controls/charts/types/barchartgroup" - }, - { - "type": "doc", - "id": "controls/charts/types/barchartrod" - }, - { - "type": "doc", - "id": "controls/charts/types/barchartrodstackitem" - }, - { - "type": "doc", - "id": "controls/charts/types/barchartrodtooltip" - }, - { - "type": "doc", - "id": "controls/charts/types/barcharttooltip" - }, - { - "type": "doc", - "id": "controls/charts/types/barcharttooltipdirection" - }, - { - "type": "doc", - "id": "controls/charts/types/candlestickchartevent" - }, - { - "type": "doc", - "id": "controls/charts/types/candlestickchartspot" - }, - { - "type": "doc", - "id": "controls/charts/types/candlestickchartspottooltip" - }, - { - "type": "doc", - "id": "controls/charts/types/candlestickcharttooltip" - }, - { - "type": "doc", - "id": "controls/charts/types/chartaxis" - }, - { - "type": "doc", - "id": "controls/charts/types/chartaxislabel" - }, - { - "type": "doc", - "id": "controls/charts/types/chartcirclepoint" - }, - { - "type": "doc", - "id": "controls/charts/types/chartcrosspoint" - }, - { - "type": "doc", - "id": "controls/charts/types/chartdatapointtooltip" - }, - { - "type": "doc", - "id": "controls/charts/types/charteventtype" - }, - { - "type": "doc", - "id": "controls/charts/types/chartgridlines" - }, - { - "type": "doc", - "id": "controls/charts/types/chartpointline" - }, - { - "type": "doc", - "id": "controls/charts/types/chartpointshape" - }, - { - "type": "doc", - "id": "controls/charts/types/chartsquarepoint" - }, - { - "type": "doc", - "id": "controls/charts/types/horizontalalignment" - }, - { - "type": "doc", - "id": "controls/charts/types/linechartdata" - }, - { - "type": "doc", - "id": "controls/charts/types/linechartdatapoint" - }, - { - "type": "doc", - "id": "controls/charts/types/linechartdatapointtooltip" - }, - { - "type": "doc", - "id": "controls/charts/types/linechartevent" - }, - { - "type": "doc", - "id": "controls/charts/types/linecharteventspot" - }, - { - "type": "doc", - "id": "controls/charts/types/linecharttooltip" - }, - { - "type": "doc", - "id": "controls/charts/types/piechartevent" - }, - { - "type": "doc", - "id": "controls/charts/types/piechartsection" - }, - { - "type": "doc", - "id": "controls/charts/types/radarchartevent" - }, - { - "type": "doc", - "id": "controls/charts/types/radarcharttitle" - }, - { - "type": "doc", - "id": "controls/charts/types/radardataset" - }, - { - "type": "doc", - "id": "controls/charts/types/radardatasetentry" - }, - { - "type": "doc", - "id": "controls/charts/types/radarshape" - }, - { - "type": "doc", - "id": "controls/charts/types/scatterchartevent" - }, - { - "type": "doc", - "id": "controls/charts/types/scatterchartspot" - }, - { - "type": "doc", - "id": "controls/charts/types/scatterchartspottooltip" - }, - { - "type": "doc", - "id": "controls/charts/types/scattercharttooltip" - } - ] - }, - { - "type": "doc", - "id": "types/colorfilter" - }, - { - "type": "doc", - "id": "types/context" - }, - { - "type": "doc", - "id": "types/controlstate" - }, - { - "type": "doc", - "id": "types/decorationimage" - }, - { - "type": "category", - "label": "DeviceInfo", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "types/androiddeviceinfo", - "label": "AndroidDeviceInfo" - }, - { - "type": "doc", - "id": "types/iosdeviceinfo", - "label": "IosDeviceInfo" - }, - { - "type": "doc", - "id": "types/linuxdeviceinfo", - "label": "LinuxDeviceInfo" - }, - { - "type": "doc", - "id": "types/macosdeviceinfo", - "label": "MacOsDeviceInfo" - }, - { - "type": "doc", - "id": "types/webdeviceinfo", - "label": "WebDeviceInfo" - }, - { - "type": "doc", - "id": "types/windowsdeviceinfo", - "label": "WindowsDeviceInfo" - } - ], - "link": { - "type": "doc", - "id": "types/deviceinfo/index" - } - }, - { - "type": "doc", - "id": "types/duration" - }, - { - "type": "doc", - "id": "types/filepickerfile" - }, - { - "type": "doc", - "id": "types/filepickeruploadfile" - }, - { - "type": "doc", - "id": "types/finder" - }, - { - "type": "doc", - "id": "types/flip" - }, - { - "type": "doc", - "id": "types/flettestapp" - }, - { - "type": "category", - "label": "Geolocator", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "services/geolocator/types/foregroundnotificationconfiguration" - }, - { - "type": "doc", - "id": "services/geolocator/types/geolocatorandroidconfiguration" - }, - { - "type": "doc", - "id": "services/geolocator/types/geolocatorconfiguration" - }, - { - "type": "doc", - "id": "services/geolocator/types/geolocatoriosactivitytype" - }, - { - "type": "doc", - "id": "services/geolocator/types/geolocatoriosconfiguration" - }, - { - "type": "doc", - "id": "services/geolocator/types/geolocatorpermissionstatus" - }, - { - "type": "doc", - "id": "services/geolocator/types/geolocatorposition" - }, - { - "type": "doc", - "id": "services/geolocator/types/geolocatorpositionaccuracy" - }, - { - "type": "doc", - "id": "services/geolocator/types/geolocatorpositionchangeevent" - }, - { - "type": "doc", - "id": "services/geolocator/types/geolocatorwebconfiguration" - } - ] - }, - { - "type": "category", - "label": "Gradient", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "types/lineargradient", - "label": "LinearGradient" - }, - { - "type": "doc", - "id": "types/radialgradient", - "label": "RadialGradient" - }, - { - "type": "doc", - "id": "types/sweepgradient", - "label": "SweepGradient" - } - ], - "link": { - "type": "doc", - "id": "types/gradient/index" - } - }, - { - "type": "doc", - "id": "types/inputborder" - }, - { - "type": "doc", - "id": "types/inputfilter" - }, - { - "type": "doc", - "id": "types/iosutsname" - }, - { - "type": "category", - "label": "Key", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "types/scrollkey", - "label": "ScrollKey" - }, - { - "type": "doc", - "id": "types/valuekey", - "label": "ValueKey" - } - ], - "link": { - "type": "doc", - "id": "types/key/index" - } - }, - { - "type": "doc", - "id": "types/locale" - }, - { - "type": "doc", - "id": "types/localeconfiguration" - }, - { - "type": "doc", - "id": "types/locationinfo" - }, - { - "type": "category", - "label": "Map", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/map/types/attributionalignment" - }, - { - "type": "doc", - "id": "controls/map/types/camera" - }, - { - "type": "doc", - "id": "controls/map/types/camerafit" - }, - { - "type": "doc", - "id": "controls/map/types/cursorkeyboardrotationconfiguration" - }, - { - "type": "doc", - "id": "controls/map/types/cursorrotationbehaviour" - }, - { - "type": "doc", - "id": "controls/map/types/dashedstrokepattern" - }, - { - "type": "doc", - "id": "controls/map/types/dottedstrokepattern" - }, - { - "type": "doc", - "id": "controls/map/types/fadeintiledisplay" - }, - { - "type": "doc", - "id": "controls/map/types/instantaneoustiledisplay" - }, - { - "type": "doc", - "id": "controls/map/types/interactionconfiguration" - }, - { - "type": "doc", - "id": "controls/map/types/interactionflag" - }, - { - "type": "doc", - "id": "controls/map/types/keyboardconfiguration" - }, - { - "type": "doc", - "id": "controls/map/types/mapevent" - }, - { - "type": "doc", - "id": "controls/map/types/mapeventtype" - }, - { - "type": "doc", - "id": "controls/map/types/mapeventsource" - }, - { - "type": "doc", - "id": "controls/map/types/maphoverevent" - }, - { - "type": "doc", - "id": "controls/map/types/maplatitudelongitude" - }, - { - "type": "doc", - "id": "controls/map/types/maplatitudelongitudebounds" - }, - { - "type": "doc", - "id": "controls/map/types/mappointerevent" - }, - { - "type": "doc", - "id": "controls/map/types/mappositionchangeevent" - }, - { - "type": "doc", - "id": "controls/map/types/maptapevent" - }, - { - "type": "doc", - "id": "controls/map/types/multifingergesture" - }, - { - "type": "doc", - "id": "controls/map/types/patternfit" - }, - { - "type": "doc", - "id": "controls/map/types/solidstrokepattern" - }, - { - "type": "doc", - "id": "controls/map/types/strokepattern" - }, - { - "type": "doc", - "id": "controls/map/types/tiledisplay" - }, - { - "type": "doc", - "id": "controls/map/types/tilelayerevicterrortilestrategy" - }, - { - "type": "doc", - "id": "controls/map/types/wmstilelayerconfiguration" - } - ] - }, - { - "type": "doc", - "id": "types/margin" - }, - { - "type": "doc", - "id": "types/matrix4" - }, - { - "type": "doc", - "id": "types/markdowncustomcodetheme" - }, - { - "type": "doc", - "id": "types/markdownstylesheet" - }, - { - "type": "doc", - "id": "types/menustyle" - }, - { - "type": "category", - "label": "NotchShape", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "types/automaticnotchshape", - "label": "AutomaticNotchShape" - }, - { - "type": "doc", - "id": "types/circularrectanglenotchshape", - "label": "CircularRectangleNotchShape" - } - ], - "link": { - "type": "doc", - "id": "types/notchshape/index" - } - }, - { - "type": "doc", - "id": "types/observable" - }, - { - "type": "doc", - "id": "types/offset" - }, - { - "type": "category", - "label": "OutlinedBorder", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "types/beveledrectangleborder", - "label": "BeveledRectangleBorder" - }, - { - "type": "doc", - "id": "types/circleborder", - "label": "CircleBorder" - }, - { - "type": "doc", - "id": "types/continuousrectangleborder", - "label": "ContinuousRectangleBorder" - }, - { - "type": "doc", - "id": "types/roundedrectangleborder", - "label": "RoundedRectangleBorder" - }, - { - "type": "doc", - "id": "types/stadiumborder", - "label": "StadiumBorder" - } - ], - "link": { - "type": "doc", - "id": "types/outlinedborder/index" - } - }, - { - "type": "doc", - "id": "types/padding" - }, - { - "type": "doc", - "id": "types/paint" - }, - { - "type": "category", - "label": "PaintGradient", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "types/paintlineargradient", - "label": "PaintLinearGradient" - }, - { - "type": "doc", - "id": "types/paintradialgradient", - "label": "PaintRadialGradient" - }, - { - "type": "doc", - "id": "types/paintsweepgradient", - "label": "PaintSweepGradient" - } - ], - "link": { - "type": "doc", - "id": "types/paintgradient/index" - } - }, - { - "type": "category", - "label": "PermissionHandler", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "services/permissionhandler/types/permission" - }, - { - "type": "doc", - "id": "services/permissionhandler/types/permissionstatus" - } - ] - }, - { - "type": "doc", - "id": "types/pubsub/pubsubclient" - }, - { - "type": "doc", - "id": "types/pubsub/pubsubhub" - }, - { - "type": "doc", - "id": "types/rect" - }, - { - "type": "doc", - "id": "types/ref" - }, - { - "type": "doc", - "id": "types/responsiverowbreakpoint" - }, - { - "type": "doc", - "id": "types/rotate" - }, - { - "type": "doc", - "id": "types/scale" - }, - { - "type": "category", - "label": "SecureStorage", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "services/securestorage/types/windowsoptions" - }, - { - "type": "doc", - "id": "services/securestorage/types/androidoptions" - }, - { - "type": "doc", - "id": "services/securestorage/types/appleoptions" - }, - { - "type": "doc", - "id": "services/securestorage/types/macosoptions" - }, - { - "type": "doc", - "id": "services/securestorage/types/iosoptions" - }, - { - "type": "doc", - "id": "services/securestorage/types/weboptions" - } - ] - }, - { - "type": "doc", - "id": "types/shapeborder" - }, - { - "type": "doc", - "id": "types/size" - }, - { - "type": "doc", - "id": "types/strutstyle" - }, - { - "type": "doc", - "id": "types/templateroute" - }, - { - "type": "doc", - "id": "types/tester" - }, - { - "type": "doc", - "id": "types/textdecoration" - }, - { - "type": "doc", - "id": "types/textselection" - }, - { - "type": "doc", - "id": "types/textspan" - }, - { - "type": "doc", - "id": "types/textstyle" - }, - { - "type": "doc", - "id": "types/textthemestyle" - }, - { - "type": "doc", - "id": "types/transform" - }, - { - "type": "category", - "label": "Theme", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "types/appbartheme", - "label": "AppBarTheme" - }, - { - "type": "doc", - "id": "types/badgetheme", - "label": "BadgeTheme" - }, - { - "type": "doc", - "id": "types/bannertheme", - "label": "BannerTheme" - }, - { - "type": "doc", - "id": "types/bottomappbartheme", - "label": "BottomAppBarTheme" - }, - { - "type": "doc", - "id": "types/bottomsheettheme", - "label": "BottomSheetTheme" - }, - { - "type": "doc", - "id": "types/buttontheme", - "label": "ButtonTheme" - }, - { - "type": "doc", - "id": "types/cardtheme", - "label": "CardTheme" - }, - { - "type": "doc", - "id": "types/checkboxtheme", - "label": "CheckboxTheme" - }, - { - "type": "doc", - "id": "types/chiptheme", - "label": "ChipTheme" - }, - { - "type": "doc", - "id": "types/colorscheme", - "label": "ColorScheme" - }, - { - "type": "doc", - "id": "types/datatabletheme", - "label": "DataTableTheme" - }, - { - "type": "doc", - "id": "types/datepickertheme", - "label": "DatePickerTheme" - }, - { - "type": "doc", - "id": "types/dialogtheme", - "label": "DialogTheme" - }, - { - "type": "doc", - "id": "types/dividertheme", - "label": "DividerTheme" - }, - { - "type": "doc", - "id": "types/dropdowntheme", - "label": "DropdownTheme" - }, - { - "type": "doc", - "id": "types/expansiontiletheme", - "label": "ExpansionTileTheme" - }, - { - "type": "doc", - "id": "types/filledbuttontheme", - "label": "FilledButtonTheme" - }, - { - "type": "doc", - "id": "types/floatingactionbuttontheme", - "label": "FloatingActionButtonTheme" - }, - { - "type": "doc", - "id": "types/iconbuttontheme", - "label": "IconButtonTheme" - }, - { - "type": "doc", - "id": "types/icontheme", - "label": "IconTheme" - }, - { - "type": "doc", - "id": "types/listtiletheme", - "label": "ListTileTheme" - }, - { - "type": "doc", - "id": "types/navigationbartheme", - "label": "NavigationBarTheme" - }, - { - "type": "doc", - "id": "types/navigationdrawertheme", - "label": "NavigationDrawerTheme" - }, - { - "type": "doc", - "id": "types/navigationrailtheme", - "label": "NavigationRailTheme" - }, - { - "type": "doc", - "id": "types/outlinedbuttontheme", - "label": "OutlinedButtonTheme" - }, - { - "type": "doc", - "id": "types/pagetransitionstheme", - "label": "PageTransitionsTheme" - }, - { - "type": "doc", - "id": "types/pagetransitiontheme", - "label": "PageTransitionTheme" - }, - { - "type": "doc", - "id": "types/popupmenutheme", - "label": "PopupMenuTheme" - }, - { - "type": "doc", - "id": "types/progressindicatortheme", - "label": "ProgressIndicatorTheme" - }, - { - "type": "doc", - "id": "types/radiotheme", - "label": "RadioTheme" - }, - { - "type": "doc", - "id": "types/scrollbartheme", - "label": "ScrollBarTheme" - }, - { - "type": "doc", - "id": "types/searchbartheme", - "label": "SearchBarTheme" - }, - { - "type": "doc", - "id": "types/searchviewtheme", - "label": "SearchViewTheme" - }, - { - "type": "doc", - "id": "types/segmentedbuttontheme", - "label": "SegmentedButtonTheme" - }, - { - "type": "doc", - "id": "types/slidertheme", - "label": "SliderTheme" - }, - { - "type": "doc", - "id": "types/snackbartheme", - "label": "SnackBarTheme" - }, - { - "type": "doc", - "id": "types/switchtheme", - "label": "SwitchTheme" - }, - { - "type": "doc", - "id": "types/systemoverlaystyle", - "label": "SystemOverlayStyle" - }, - { - "type": "doc", - "id": "types/tabbartheme", - "label": "TabBarTheme" - }, - { - "type": "doc", - "id": "types/textbuttontheme", - "label": "TextButtonTheme" - }, - { - "type": "doc", - "id": "types/texttheme", - "label": "TextTheme" - }, - { - "type": "doc", - "id": "types/timepickertheme", - "label": "TimePickerTheme" - }, - { - "type": "doc", - "id": "types/tooltiptheme", - "label": "TooltipTheme" - } - ], - "link": { - "type": "doc", - "id": "types/theme/index" - } - }, - { - "type": "doc", - "id": "types/browserconfiguration" - }, - { - "type": "doc", - "id": "types/tooltip" - }, - { - "type": "doc", - "id": "types/url" - }, - { - "type": "doc", - "id": "types/webviewconfiguration" - }, - { - "type": "doc", - "id": "types/underlinetabindicator" - }, - { - "type": "category", - "label": "CodeEditor", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/codeeditor/types/codelanguage" - }, - { - "type": "doc", - "id": "controls/codeeditor/types/codetheme" - }, - { - "type": "doc", - "id": "controls/codeeditor/types/customcodetheme" - }, - { - "type": "doc", - "id": "controls/codeeditor/types/gutterstyle" - } - ] - }, - { - "type": "category", - "label": "Video", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/video/types/adaptivevideocontrols" - }, - { - "type": "doc", - "id": "controls/video/types/materialdesktopvideocontrols" - }, - { - "type": "doc", - "id": "controls/video/types/materialvideocontrols" - }, - { - "type": "doc", - "id": "controls/video/types/playlistmode" - }, - { - "type": "doc", - "id": "controls/video/types/videobaritem" - }, - { - "type": "doc", - "id": "controls/video/types/videoconfiguration" - }, - { - "type": "doc", - "id": "controls/video/types/videocontrols" - }, - { - "type": "doc", - "id": "controls/video/types/videocontrolsmode" - }, - { - "type": "doc", - "id": "controls/video/types/videofullscreenbutton" - }, - { - "type": "doc", - "id": "controls/video/types/videomedia" - }, - { - "type": "doc", - "id": "controls/video/types/videoplayorpausebutton" - }, - { - "type": "doc", - "id": "controls/video/types/videopositionindicator" - }, - { - "type": "doc", - "id": "controls/video/types/videoskipnextbutton" - }, - { - "type": "doc", - "id": "controls/video/types/videoskippreviousbutton" - }, - { - "type": "doc", - "id": "controls/video/types/videospacer" - }, - { - "type": "doc", - "id": "controls/video/types/videosubtitleconfiguration" - }, - { - "type": "doc", - "id": "controls/video/types/videosubtitletrack" - }, - { - "type": "doc", - "id": "controls/video/types/videovolumebutton" - } - ] - }, - { - "type": "category", - "label": "WebView", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/webview/types/requestmethod" - }, - { - "type": "doc", - "id": "controls/webview/types/loglevelseverity" - }, - { - "type": "doc", - "id": "controls/webview/types/webviewconsolemessageevent" - }, - { - "type": "doc", - "id": "controls/webview/types/webviewjavascriptevent" - }, - { - "type": "doc", - "id": "controls/webview/types/webviewscrollevent" - } - ] - } - ] - }, - { - "type": "category", - "label": "Decorators", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "types/component" - }, - { - "type": "doc", - "id": "types/control" - }, - { - "type": "doc", - "id": "types/observabledecorator" - }, - { - "type": "doc", - "id": "types/value" - } - ] - }, - { - "type": "category", - "label": "Enums", - "collapsed": true, - "items": [ - { - "type": "category", - "label": "Ads", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/ads/types/precisiontype" - } - ] - }, - { - "type": "doc", - "id": "types/animatedswitchertransition" - }, - { - "type": "doc", - "id": "types/animationcurve" - }, - { - "type": "doc", - "id": "types/applifecyclestate" - }, - { - "type": "doc", - "id": "types/appview" - }, - { - "type": "doc", - "id": "types/assertiveness" - }, - { - "type": "doc", - "id": "types/autofillgroupdisposeaction" - }, - { - "type": "doc", - "id": "types/autofillhint" - }, - { - "type": "doc", - "id": "types/axis" - }, - { - "type": "doc", - "id": "types/blendmode" - }, - { - "type": "doc", - "id": "types/blurstyle" - }, - { - "type": "doc", - "id": "types/blurtilemode" - }, - { - "type": "doc", - "id": "types/bordersidestrokealign" - }, - { - "type": "doc", - "id": "types/borderstyle" - }, - { - "type": "doc", - "id": "types/boxfit" - }, - { - "type": "doc", - "id": "types/boxshape" - }, - { - "type": "doc", - "id": "types/brightness" - }, - { - "type": "doc", - "id": "types/cardvariant" - }, - { - "type": "doc", - "id": "types/clipbehavior" - }, - { - "type": "doc", - "id": "types/colors" - }, - { - "type": "doc", - "id": "types/contextmenutrigger" - }, - { - "type": "doc", - "id": "types/crossaxisalignment" - }, - { - "type": "doc", - "id": "types/cupertinobuttonsize" - }, - { - "type": "doc", - "id": "types/cupertinocolors" - }, - { - "type": "doc", - "id": "types/cupertinodatepickerdateorder" - }, - { - "type": "doc", - "id": "types/cupertinodatepickermode" - }, - { - "type": "doc", - "id": "types/cupertinoicons" - }, - { - "type": "doc", - "id": "types/cupertinotimerpickermode" - }, - { - "type": "category", - "label": "DataTable2", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/datatable2/types/datacolumnsize" - } - ] - }, - { - "type": "doc", - "id": "types/datepickerentrymode" - }, - { - "type": "doc", - "id": "types/datepickermode" - }, - { - "type": "doc", - "id": "types/dismissdirection" - }, - { - "type": "doc", - "id": "types/filepickerfiletype" - }, - { - "type": "doc", - "id": "types/filterquality" - }, - { - "type": "doc", - "id": "types/floatingactionbuttonlocation" - }, - { - "type": "doc", - "id": "types/fontweight" - }, - { - "type": "doc", - "id": "types/gradienttilemode" - }, - { - "type": "doc", - "id": "types/icons" - }, - { - "type": "doc", - "id": "types/imagerepeat" - }, - { - "type": "doc", - "id": "types/keyboardtype" - }, - { - "type": "doc", - "id": "types/labelposition" - }, - { - "type": "doc", - "id": "types/listtilestyle" - }, - { - "type": "doc", - "id": "types/listtiletitlealignment" - }, - { - "type": "doc", - "id": "types/mainaxisalignment" - }, - { - "type": "doc", - "id": "types/mousecursor" - }, - { - "type": "doc", - "id": "types/markdowncodetheme" - }, - { - "type": "doc", - "id": "types/markdownextensionset" - }, - { - "type": "doc", - "id": "types/navigationbarlabelbehavior" - }, - { - "type": "doc", - "id": "types/navigationraillabeltype" - }, - { - "type": "doc", - "id": "types/deviceorientation" - }, - { - "type": "doc", - "id": "types/orientation" - }, - { - "type": "doc", - "id": "types/overlayvisibilitymode" - }, - { - "type": "doc", - "id": "types/pageplatform" - }, - { - "type": "doc", - "id": "types/paintingstyle" - }, - { - "type": "doc", - "id": "types/pointerdevicetype" - }, - { - "type": "doc", - "id": "types/pointmode" - }, - { - "type": "doc", - "id": "types/popupmenuposition" - }, - { - "type": "doc", - "id": "types/route" - }, - { - "type": "doc", - "id": "types/routeurlstrategy" - }, - { - "type": "doc", - "id": "types/scrollbar" - }, - { - "type": "doc", - "id": "types/scrollbarorientation" - }, - { - "type": "doc", - "id": "types/scrolldirection" - }, - { - "type": "doc", - "id": "types/scrollmode" - }, - { - "type": "doc", - "id": "types/scrolltype" - }, - { - "type": "doc", - "id": "types/sliderinteraction" - }, - { - "type": "doc", - "id": "types/snackbarbehavior" - }, - { - "type": "doc", - "id": "types/stackfit" - }, - { - "type": "doc", - "id": "types/strokecap" - }, - { - "type": "doc", - "id": "types/strokejoin" - }, - { - "type": "doc", - "id": "types/tabalignment" - }, - { - "type": "doc", - "id": "types/tabbarindicatorsize" - }, - { - "type": "doc", - "id": "types/tabindicatoranimation" - }, - { - "type": "doc", - "id": "types/textaffinity" - }, - { - "type": "doc", - "id": "types/textalign" - }, - { - "type": "doc", - "id": "types/textbaseline" - }, - { - "type": "doc", - "id": "types/textcapitalization" - }, - { - "type": "doc", - "id": "types/textdecorationstyle" - }, - { - "type": "doc", - "id": "types/textoverflow" - }, - { - "type": "doc", - "id": "types/textselectionchangecause" - }, - { - "type": "doc", - "id": "types/thememode" - }, - { - "type": "doc", - "id": "types/tileaffinity" - }, - { - "type": "doc", - "id": "types/timepickerentrymode" - }, - { - "type": "doc", - "id": "types/timepickerhourformat" - }, - { - "type": "doc", - "id": "types/tooltiptriggermode" - }, - { - "type": "doc", - "id": "types/launchmode" - }, - { - "type": "doc", - "id": "types/urltarget" - }, - { - "type": "doc", - "id": "types/verticalalignment" - }, - { - "type": "doc", - "id": "types/visualdensity" - }, - { - "type": "doc", - "id": "types/webbrowsername" - }, - { - "type": "doc", - "id": "types/webrenderer" - }, - { - "type": "doc", - "id": "types/windoweventtype" - }, - { - "type": "doc", - "id": "types/windowresizeedge" - }, - { - "type": "doc", - "id": "services/securestorage/types/accesscontrolflag" - }, - { - "type": "doc", - "id": "services/securestorage/types/keychainaccessibility" - }, - { - "type": "doc", - "id": "services/securestorage/types/keycipheralgorithm" - }, - { - "type": "doc", - "id": "services/securestorage/types/storagecipheralgorithm" - } - ] - }, - { - "type": "category", - "label": "Events", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "types/accelerometerreadingevent" - }, - { - "type": "category", - "label": "Ads", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "controls/ads/types/paidadevent" - } - ] - }, - { - "type": "doc", - "id": "types/applifecyclestatechangeevent" - }, - { - "type": "doc", - "id": "types/autocompleteselectevent" - }, - { - "type": "doc", - "id": "types/barometerreadingevent" - }, - { - "type": "doc", - "id": "types/batterystate" - }, - { - "type": "doc", - "id": "types/batterystatechangeevent" - }, - { - "type": "doc", - "id": "types/connectivitytype" - }, - { - "type": "doc", - "id": "types/connectivitychangeevent" - }, - { - "type": "doc", - "id": "types/canvasresizeevent" - }, - { - "type": "doc", - "id": "types/contextmenudismissevent" - }, - { - "type": "doc", - "id": "types/contextmenuselectevent" - }, - { - "type": "doc", - "id": "types/datacolumnsortevent" - }, - { - "type": "doc", - "id": "types/datepickerentrymodechangeevent" - }, - { - "type": "doc", - "id": "types/dismissibledismissevent" - }, - { - "type": "doc", - "id": "types/dismissibleupdateevent" - }, - { - "type": "doc", - "id": "types/dragendevent" - }, - { - "type": "doc", - "id": "types/dragstartevent" - }, - { - "type": "doc", - "id": "types/dragtargetevent" - }, - { - "type": "doc", - "id": "types/dragtargetleaveevent" - }, - { - "type": "doc", - "id": "types/dragupdateevent" - }, - { - "type": "doc", - "id": "types/dragwillacceptevent" - }, - { - "type": "doc", - "id": "types/event" - }, - { - "type": "doc", - "id": "types/expansionpanellistchangeevent" - }, - { - "type": "doc", - "id": "types/filepickeruploadevent" - }, - { - "type": "doc", - "id": "types/gyroscopereadingevent" - }, - { - "type": "doc", - "id": "types/hoverevent" - }, - { - "type": "doc", - "id": "types/keyboardevent" - }, - { - "type": "doc", - "id": "types/keydownevent" - }, - { - "type": "doc", - "id": "types/keyrepeatevent" - }, - { - "type": "doc", - "id": "types/keyupevent" - }, - { - "type": "doc", - "id": "types/localechangeevent" - }, - { - "type": "doc", - "id": "types/loginevent" - }, - { - "type": "doc", - "id": "types/longpressendevent" - }, - { - "type": "doc", - "id": "types/longpressstartevent" - }, - { - "type": "doc", - "id": "types/magnetometerreadingevent" - }, - { - "type": "doc", - "id": "types/multitapevent" - }, - { - "type": "doc", - "id": "types/multiviewaddevent" - }, - { - "type": "doc", - "id": "types/multiviewremoveevent" - }, - { - "type": "doc", - "id": "types/onreorderevent" - }, - { - "type": "doc", - "id": "types/onscrollevent" - }, - { - "type": "doc", - "id": "types/pagemediadata" - }, - { - "type": "doc", - "id": "types/pageresizeevent" - }, - { - "type": "doc", - "id": "types/platformbrightnesschangeevent" - }, - { - "type": "doc", - "id": "types/pointerevent" - }, - { - "type": "doc", - "id": "types/routechangeevent" - }, - { - "type": "doc", - "id": "types/sensorerrorevent" - }, - { - "type": "doc", - "id": "types/scaleendevent" - }, - { - "type": "doc", - "id": "types/scalestartevent" - }, - { - "type": "doc", - "id": "types/scaleupdateevent" - }, - { - "type": "doc", - "id": "types/screenbrightnesschangeevent" - }, - { - "type": "doc", - "id": "types/shareresult" - }, - { - "type": "doc", - "id": "types/shareresultstatus" - }, - { - "type": "doc", - "id": "types/sharefile" - }, - { - "type": "doc", - "id": "types/sharecupertinoactivitytype" - }, - { - "type": "doc", - "id": "types/scrollevent" - }, - { - "type": "doc", - "id": "services/securestorage/types/securestorageevent" - }, - { - "type": "doc", - "id": "types/tabbarhoverevent" - }, - { - "type": "doc", - "id": "types/tapevent" - }, - { - "type": "doc", - "id": "types/textselectionchangeevent" - }, - { - "type": "doc", - "id": "types/timepickerentrymodechangeevent" - }, - { - "type": "doc", - "id": "types/useraccelerometerreadingevent" - }, - { - "type": "doc", - "id": "types/viewpopevent" - }, - { - "type": "doc", - "id": "types/windowevent" - } - ] - }, - { - "type": "category", - "label": "Exceptions", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "types/fletpagedisconnectedexception", - "label": "FletPageDisconnectedException" - }, - { - "type": "doc", - "id": "types/fletunimplementedplatformexception", - "label": "FletUnimplementedPlatformException" - }, - { - "type": "doc", - "id": "types/fletunsupportedplatformexception", - "label": "FletUnsupportedPlatformException" - } - ], - "link": { - "type": "doc", - "id": "types/fletexception/index" - } - }, - { - "type": "category", - "label": "FastAPI", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "fastapi/app" - }, - { - "type": "doc", - "id": "fastapi/app_manager" - }, - { - "type": "doc", - "id": "fastapi/fastapi" - }, - { - "type": "doc", - "id": "fastapi/fletapp" - }, - { - "type": "doc", - "id": "fastapi/fletoauth" - }, - { - "type": "doc", - "id": "fastapi/fletstaticfiles" - }, - { - "type": "doc", - "id": "fastapi/fletupload" - } - ] - }, - { - "type": "category", - "label": "Methods", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "types/createcontext" - }, - { - "type": "doc", - "id": "types/is_route_active" - }, - { - "type": "doc", - "id": "types/memo" - }, - { - "type": "doc", - "id": "types/onmounted" - }, - { - "type": "doc", - "id": "types/onunmounted" - }, - { - "type": "doc", - "id": "types/onupdated" - }, - { - "type": "doc", - "id": "types/usecallback" - }, - { - "type": "doc", - "id": "types/usecontext" - }, - { - "type": "doc", - "id": "types/useeffect" - }, - { - "type": "doc", - "id": "types/usememo" - }, - { - "type": "doc", - "id": "types/useref" - }, - { - "type": "doc", - "id": "types/use_route_loader_data" - }, - { - "type": "doc", - "id": "types/use_route_location" - }, - { - "type": "doc", - "id": "types/use_route_outlet" - }, - { - "type": "doc", - "id": "types/use_route_params" - }, - { - "type": "doc", - "id": "types/use_view_path" - }, - { - "type": "doc", - "id": "types/usestate" - } - ] - } - ], - "link": { - "type": "doc", - "id": "types/index" - } - }, - { - "type": "category", - "label": "CLI", - "collapsed": true, - "items": [ - { - "type": "doc", - "id": "cli/flet-build", - "label": "flet build" - }, - { - "type": "doc", - "id": "cli/flet-create", - "label": "flet create" - }, - { - "type": "doc", - "id": "cli/flet-debug", - "label": "flet debug" - }, - { - "type": "doc", - "id": "cli/flet-devices", - "label": "flet devices" - }, - { - "type": "doc", - "id": "cli/flet-doctor", - "label": "flet doctor" - }, - { - "type": "doc", - "id": "cli/flet-emulators", - "label": "flet emulators" - }, - { - "type": "doc", - "id": "cli/flet-pack", - "label": "flet pack" - }, - { - "type": "doc", - "id": "cli/flet-publish", - "label": "flet publish" - }, - { - "type": "doc", - "id": "cli/flet-run", - "label": "flet run" - }, - { - "type": "doc", - "id": "cli/flet-serve", - "label": "flet serve" - } - ], - "link": { - "type": "doc", - "id": "cli/index" - } - }, - { - "type": "doc", - "id": "reference/binary-packages-android-ios", - "label": "Python packages built in Flet" - }, - { - "type": "doc", - "id": "reference/environment-variables", - "label": "Environment Variables" - } - ], - "link": { - "type": "doc", - "id": "reference/index" - } - } - ], - "studio": [ - { - "type": "doc", - "id": "studio/index", - "label": "Introduction" - }, - { - "type": "doc", - "id": "studio/whats-new", - "label": "What's new" - }, - { - "type": "doc", - "id": "studio/terms-of-service", - "label": "Terms of Service" - }, - { - "type": "doc", - "id": "studio/privacy-policy", - "label": "Privacy Policy" - } - ] -}; diff --git a/website/sidebars.yml b/website/sidebars.yml index f37ebbfcf0..206c97b79d 100644 --- a/website/sidebars.yml +++ b/website/sidebars.yml @@ -6,6 +6,7 @@ docs: - getting-started/installation.md - getting-started/create-flet-app.md - getting-started/running-app.md + - getting-started/integration-testing.md - getting-started/testing-on-mobile.md Tutorials: - Calculator: tutorials/calculator.md @@ -35,10 +36,12 @@ docs: Session Storage: cookbook/session-storage.md PubSub: cookbook/pub-sub.md Subprocess: cookbook/subprocess.md + Multiprocessing: cookbook/multiprocessing.md Logging: cookbook/logging.md Authentication: cookbook/authentication.md Encrypting sensitive data: cookbook/encrypting-sensitive-data.md Declarative dialogs: cookbook/declarative-dialogs.md + Flet MCP server: cookbook/flet-mcp.md Publishing Flet app: _index: publish/index.md Android: publish/android.md @@ -68,10 +71,19 @@ docs: Release notes: updates/release-notes.md Breaking changes and deprecations: _index: updates/breaking-changes/index.md + v0.86.0: + App files ship unpacked in a read-only bundle; storage dirs reworked: updates/breaking-changes/v0-86-0/app-files-unpacked-read-only-bundle.md + "Android: site-packages ship zipped; some packages need extract_packages": updates/breaking-changes/v0-86-0/android-extract-packages.md + "Android: x86 removed from target architectures": updates/breaking-changes/v0-86-0/android-x86-arch-removed.md + Default bundled Python version is now 3.14: updates/breaking-changes/v0-86-0/default-bundled-python-3-14.md + App and packages are compiled to .pyc by default: updates/breaking-changes/v0-86-0/compile-on-by-default.md + flet.version.pyodide_version and PYODIDE_VERSION removed: updates/breaking-changes/v0-86-0/removed-pyodide-version-export.md + Flet protocol framing upgraded for DataChannel support: updates/breaking-changes/v0-86-0/data-channel-protocol-upgrade.md + flet build --clear-cache flag deprecated: updates/breaking-changes/v0-86-0/deprecated-clear-cache-flag.md v0.85.0: - Deprecated spacing and border helper functions removed: updates/breaking-changes/removed-spacing-border-helpers.md - DragTargetEvent coordinate fields deprecated: updates/breaking-changes/deprecated-drag-target-event-coordinates.md - Video control APIs deprecated: updates/breaking-changes/deprecated-video-apis.md + Deprecated spacing and border helper functions removed: updates/breaking-changes/v0-85-0/removed-spacing-border-helpers.md + DragTargetEvent coordinate fields deprecated: updates/breaking-changes/v0-85-0/deprecated-drag-target-event-coordinates.md + Video control APIs deprecated: updates/breaking-changes/v0-85-0/deprecated-video-apis.md Compatibility policy: updates/compatibility-policy.md Reference: _index: reference/index.md @@ -84,6 +96,7 @@ docs: _index: controls/ads/index.md BannerAd: controls/ads/bannerad.md BaseAd: controls/ads/basead.md + ConsentManager: controls/ads/consentmanager.md InterstitialAd: controls/ads/interstitialad.md AlertDialog: controls/alertdialog.md AnimatedSwitcher: controls/animatedswitcher.md @@ -182,7 +195,7 @@ docs: Dropdown: _index: controls/dropdown/index.md DropdownOption: controls/dropdownoption.md - #DropdownM2: controls/dropdownm2.md + DropdownM2: controls/dropdownm2.md ExpansionPanel: controls/expansionpanel.md ExpansionPanelList: controls/expansionpanellist.md ExpansionTile: controls/expansiontile.md @@ -255,6 +268,7 @@ docs: Radio: controls/radio.md RadioGroup: controls/radiogroup.md RangeSlider: controls/rangeslider.md + RawImage: controls/rawimage.md ReorderableDragHandle: controls/reorderabledraghandle.md ReorderableListView: controls/reorderablelistview.md ResponsiveRow: controls/responsiverow.md @@ -370,6 +384,11 @@ docs: GitHubOAuthProvider: types/auth/githuboauthprovider.md GoogleOAuthProvider: types/auth/googleoauthprovider.md - types/auth/user.md + Testing: + - types/testing/flettestapp.md + - types/testing/tester.md + - types/testing/finder.md + - types/testing/disposalmode.md Base Controls: - controls/adaptivecontrol.md - controls/basecontrol.md @@ -384,6 +403,8 @@ docs: Classes: - Ads: - controls/ads/types/adrequest.md + - controls/ads/types/consentdebugsettings.md + - controls/ads/types/consentrequestparameters.md - types/alignment.md - types/androidbuildversion.md - types/animation.md @@ -471,6 +492,7 @@ docs: - types/colorfilter.md - types/context.md - types/controlstate.md + - types/datachannel.md - types/decorationimage.md - DeviceInfo: _index: types/deviceinfo/index.md @@ -483,9 +505,7 @@ docs: - types/duration.md - types/filepickerfile.md - types/filepickeruploadfile.md - - types/finder.md - types/flip.md - - types/flettestapp.md - Geolocator: - services/geolocator/types/foregroundnotificationconfiguration.md - services/geolocator/types/geolocatorandroidconfiguration.md @@ -587,7 +607,6 @@ docs: - types/size.md - types/strutstyle.md - types/templateroute.md - - types/tester.md - types/textdecoration.md - types/textselection.md - types/textspan.md @@ -681,7 +700,10 @@ docs: - types/value.md Enums: - Ads: + - controls/ads/types/consentstatus.md + - controls/ads/types/debuggeography.md - controls/ads/types/precisiontype.md + - controls/ads/types/privacyoptionsrequirementstatus.md - types/animatedswitchertransition.md - types/animationcurve.md - types/applifecyclestate.md @@ -792,6 +814,7 @@ docs: - types/canvasresizeevent.md - types/contextmenudismissevent.md - types/contextmenuselectevent.md + - types/datachannelopenevent.md - types/datacolumnsortevent.md - types/datepickerentrymodechangeevent.md - types/dismissibledismissevent.md @@ -864,6 +887,8 @@ docs: - types/onmounted.md - types/onunmounted.md - types/onupdated.md + - types/run.md + - types/run_async.md - types/usecallback.md - types/usecontext.md - types/useeffect.md @@ -878,15 +903,18 @@ docs: CLI: _index: cli/index.md flet build: cli/flet-build.md + flet clean: cli/flet-clean.md flet create: cli/flet-create.md flet debug: cli/flet-debug.md flet devices: cli/flet-devices.md flet doctor: cli/flet-doctor.md flet emulators: cli/flet-emulators.md + flet mcp: cli/flet-mcp.md flet pack: cli/flet-pack.md flet publish: cli/flet-publish.md flet run: cli/flet-run.md flet serve: cli/flet-serve.md + flet test: cli/flet-test.md Python packages built in Flet: reference/binary-packages-android-ios.md Environment Variables: reference/environment-variables.md diff --git a/website/src/components/crocodocs/utils.js b/website/src/components/crocodocs/utils.js index 2c0bbe9cc5..909393821c 100644 --- a/website/src/components/crocodocs/utils.js +++ b/website/src/components/crocodocs/utils.js @@ -652,11 +652,17 @@ function preprocessRestCrossReferenceMarkdown(text, context) { } /** - * Escape bare '<' characters (not followed by tag-start or '!') to '<' in non-code text. - * Prevents MDX from treating angle brackets in docstrings as JSX elements. - * Skips fenced code blocks and inline backtick spans. + * Escape MDX-unsafe characters in non-code text so docstring prose can't be + * misparsed as MDX syntax: + * - bare '<' (not followed by tag-start or '!') becomes '<', so it isn't + * treated as the start of a JSX element; + * - '{' and '}' become '{'/'}', so content like + * `boot_screen_options={'spinner_size': 30}` isn't parsed as a (broken) + * JSX expression. + * Skips fenced code blocks and inline backtick spans, where these characters + * are already safe and should be preserved verbatim. */ -function escapeMdxUnsafeAngles(text) { +function escapeMdxUnsafe(text) { if (!text) { return text; } @@ -673,7 +679,10 @@ function escapeMdxUnsafeAngles(text) { if (inlineSegment.startsWith("`") && inlineSegment.endsWith("`")) { return inlineSegment; } - return inlineSegment.replace(/<(?![A-Za-z!/])/g, "<"); + return inlineSegment + .replace(/<(?![A-Za-z!/])/g, "<") + .replace(/\{/g, "{") + .replace(/\}/g, "}"); }) .join(""); }) @@ -1138,7 +1147,7 @@ export function renderInlineMarkdown(text, context) { return null; } const tree = MARKDOWN_PARSER.parse( - escapeMdxUnsafeAngles( + escapeMdxUnsafe( preprocessRestCrossReferenceMarkdown( preprocessCrossReferenceMarkdown(text, context), context @@ -1164,7 +1173,7 @@ export function renderDocstring(docstring, context = {}, keyPrefix = "doc") { return null; } const tree = MARKDOWN_PARSER.parse( - escapeMdxUnsafeAngles( + escapeMdxUnsafe( preprocessRestCrossReferenceMarkdown( preprocessCrossReferenceMarkdown( normalizeDocstringMarkdown(docstring), diff --git a/website/static/img/blog/flet-86/flet-86.png b/website/static/img/blog/flet-86/flet-86.png new file mode 100644 index 0000000000..c936fa1b2b Binary files /dev/null and b/website/static/img/blog/flet-86/flet-86.png differ diff --git a/website/yarn.lock b/website/yarn.lock index 2826c31389..138e853b70 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -2241,9 +2241,9 @@ __metadata: languageName: node linkType: hard -"@docusaurus/babel@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/babel@npm:3.10.0" +"@docusaurus/babel@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/babel@npm:3.10.1" dependencies: "@babel/core": "npm:^7.25.9" "@babel/generator": "npm:^7.25.9" @@ -2254,12 +2254,12 @@ __metadata: "@babel/preset-typescript": "npm:^7.25.9" "@babel/runtime": "npm:^7.25.9" "@babel/traverse": "npm:^7.25.9" - "@docusaurus/logger": "npm:3.10.0" - "@docusaurus/utils": "npm:3.10.0" + "@docusaurus/logger": "npm:3.10.1" + "@docusaurus/utils": "npm:3.10.1" babel-plugin-dynamic-import-node: "npm:^2.3.3" fs-extra: "npm:^11.1.1" tslib: "npm:^2.6.0" - checksum: 10c0/d79bd3e8805036e35b09ec4c7ebbf6060b07c1a375b3d27c727cc3122d25c9fddd98d450a22b70eaa9f7f3be0a7c3c5bd36819a7c1abcde4c7b4d3356248a9e3 + checksum: 10c0/3f6d2fdd6bc9c3a47683c1517e2afc7bca4b95d7b1817d68e91c1c2eaf944971d925ec03f2de8d88d40f97a0d88a1415cb2b9c64ac335c7cb6e37e6258c6f97a languageName: node linkType: hard @@ -2286,16 +2286,16 @@ __metadata: languageName: node linkType: hard -"@docusaurus/bundler@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/bundler@npm:3.10.0" +"@docusaurus/bundler@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/bundler@npm:3.10.1" dependencies: "@babel/core": "npm:^7.25.9" - "@docusaurus/babel": "npm:3.10.0" - "@docusaurus/cssnano-preset": "npm:3.10.0" - "@docusaurus/logger": "npm:3.10.0" - "@docusaurus/types": "npm:3.10.0" - "@docusaurus/utils": "npm:3.10.0" + "@docusaurus/babel": "npm:3.10.1" + "@docusaurus/cssnano-preset": "npm:3.10.1" + "@docusaurus/logger": "npm:3.10.1" + "@docusaurus/types": "npm:3.10.1" + "@docusaurus/utils": "npm:3.10.1" babel-loader: "npm:^9.2.1" clean-css: "npm:^5.3.3" copy-webpack-plugin: "npm:^11.0.0" @@ -2313,13 +2313,13 @@ __metadata: tslib: "npm:^2.6.0" url-loader: "npm:^4.1.1" webpack: "npm:^5.95.0" - webpackbar: "npm:^6.0.1" + webpackbar: "npm:^7.0.0" peerDependencies: "@docusaurus/faster": "*" peerDependenciesMeta: "@docusaurus/faster": optional: true - checksum: 10c0/49af1eba5e45126e972f943148b891c9e167e4510e6f349060ef210c648f28b5ee6344280e1ade0c2e1317bdd165ed3615aa71f95e91bd11e00a7dbb6795a0e3 + checksum: 10c0/20655bd64a5716cc3603d9097e7ca3d2526ccd7265ce3e9d23dfc9679faa08752a5604b98ba2b47eea5e183a3c4f0e383300899ae2f3897513493ec97a6beab2 languageName: node linkType: hard @@ -2360,17 +2360,17 @@ __metadata: languageName: node linkType: hard -"@docusaurus/core@npm:3.10.0, @docusaurus/core@npm:^3.10.0": - version: 3.10.0 - resolution: "@docusaurus/core@npm:3.10.0" - dependencies: - "@docusaurus/babel": "npm:3.10.0" - "@docusaurus/bundler": "npm:3.10.0" - "@docusaurus/logger": "npm:3.10.0" - "@docusaurus/mdx-loader": "npm:3.10.0" - "@docusaurus/utils": "npm:3.10.0" - "@docusaurus/utils-common": "npm:3.10.0" - "@docusaurus/utils-validation": "npm:3.10.0" +"@docusaurus/core@npm:3.10.1, @docusaurus/core@npm:^3.10.1": + version: 3.10.1 + resolution: "@docusaurus/core@npm:3.10.1" + dependencies: + "@docusaurus/babel": "npm:3.10.1" + "@docusaurus/bundler": "npm:3.10.1" + "@docusaurus/logger": "npm:3.10.1" + "@docusaurus/mdx-loader": "npm:3.10.1" + "@docusaurus/utils": "npm:3.10.1" + "@docusaurus/utils-common": "npm:3.10.1" + "@docusaurus/utils-validation": "npm:3.10.1" boxen: "npm:^6.2.1" chalk: "npm:^4.1.2" chokidar: "npm:^3.5.3" @@ -2416,7 +2416,7 @@ __metadata: optional: true bin: docusaurus: bin/docusaurus.mjs - checksum: 10c0/2a00cd5f1a22a737d37d127f5e5e6aee3ed51563884136fc76d2fa97cb71a7d577e28959f25ec2065c0e232efc003def1d6db94fcee0533063de87484bb39c86 + checksum: 10c0/006d9f57357c3196d0c33f7c5d0ce33b9f032358ed070b8ce212186169c356847cf768b3ac95b54433815c0076eda2eb94805a64bf4b2f5e47376556164e5362 languageName: node linkType: hard @@ -2476,15 +2476,15 @@ __metadata: languageName: node linkType: hard -"@docusaurus/cssnano-preset@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/cssnano-preset@npm:3.10.0" +"@docusaurus/cssnano-preset@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/cssnano-preset@npm:3.10.1" dependencies: cssnano-preset-advanced: "npm:^6.1.2" postcss: "npm:^8.5.4" postcss-sort-media-queries: "npm:^5.2.0" tslib: "npm:^2.6.0" - checksum: 10c0/635df6b05241f73b333b3d7d451d37ec56d7982a8c430afc2e8e8cf7c9e506b499b64d6bba14ccdf79b8afe84452d159516897741aa2fa838194964574da8881 + checksum: 10c0/549cf594fd9cfddd2f57bd177896c6bde8cc3821f7f07e7573d55d4c5841d7eb90d38c1b888b81479ffe33f0015b848c031ad4185f54feedf8ae2f1e2269e2ce languageName: node linkType: hard @@ -2500,11 +2500,11 @@ __metadata: languageName: node linkType: hard -"@docusaurus/faster@npm:^3.10.0": - version: 3.10.0 - resolution: "@docusaurus/faster@npm:3.10.0" +"@docusaurus/faster@npm:^3.10.1": + version: 3.10.1 + resolution: "@docusaurus/faster@npm:3.10.1" dependencies: - "@docusaurus/types": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.1" "@rspack/core": "npm:^1.7.10" "@swc/core": "npm:^1.7.39" "@swc/html": "npm:^1.13.5" @@ -2516,17 +2516,17 @@ __metadata: webpack: "npm:^5.95.0" peerDependencies: "@docusaurus/types": "*" - checksum: 10c0/9e2b1b19a67443c23eceda80606a0e305a586addf991724b923f7756cfdced1a0d6d64426a1790fa81bbc0032ab56041823fe4a694d2392b0ef4ad85dc4089e8 + checksum: 10c0/98d8ca36cd4bcd775be37109c8cd3117ff8ba62446ec50b2901bca7653fbbf690ec9aa494524a27c17744a1744a3e520804100aba014e7aa5621ef3df4679359 languageName: node linkType: hard -"@docusaurus/logger@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/logger@npm:3.10.0" +"@docusaurus/logger@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/logger@npm:3.10.1" dependencies: chalk: "npm:^4.1.2" tslib: "npm:^2.6.0" - checksum: 10c0/f9bc2b7037fb7dff8a5aba06807e4f9601e422b91d0bb7e462ecdb33d71e1c9ee3d9dfb5c37af66f6f35c43310e461857af0dda96531928af3c22678fa77ec18 + checksum: 10c0/c78c676de0cf11ba5737abe8d13ebb67c4fdd8019ac8512ee18b34c27fdd5aaf32b703da3596271592be8615094507754791ac16587a24146f3830e1558a24c3 languageName: node linkType: hard @@ -2540,13 +2540,13 @@ __metadata: languageName: node linkType: hard -"@docusaurus/mdx-loader@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/mdx-loader@npm:3.10.0" +"@docusaurus/mdx-loader@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/mdx-loader@npm:3.10.1" dependencies: - "@docusaurus/logger": "npm:3.10.0" - "@docusaurus/utils": "npm:3.10.0" - "@docusaurus/utils-validation": "npm:3.10.0" + "@docusaurus/logger": "npm:3.10.1" + "@docusaurus/utils": "npm:3.10.1" + "@docusaurus/utils-validation": "npm:3.10.1" "@mdx-js/mdx": "npm:^3.0.0" "@slorber/remark-comment": "npm:^1.0.0" escape-html: "npm:^1.0.3" @@ -2571,7 +2571,7 @@ __metadata: peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - checksum: 10c0/0b94f20398a2fd39e54215895d2607d277d0cf3a80728adbbadcbf2443063e8e1082929242ccdc4ebe393c6c4010a5ccdecf6f2a8478d90b20c74d032940d33a + checksum: 10c0/2764e3e1a6fc4856746aacd627d43a403cbad87d6ec7400d30092197f36c028207cc5d267e0af2ce34df31f0a68bb2f082bbd5d308d14bedc0d874bc95a89c7b languageName: node linkType: hard @@ -2610,11 +2610,11 @@ __metadata: languageName: node linkType: hard -"@docusaurus/module-type-aliases@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/module-type-aliases@npm:3.10.0" +"@docusaurus/module-type-aliases@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/module-type-aliases@npm:3.10.1" dependencies: - "@docusaurus/types": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.1" "@types/history": "npm:^4.7.11" "@types/react": "npm:*" "@types/react-router-config": "npm:*" @@ -2624,7 +2624,7 @@ __metadata: peerDependencies: react: "*" react-dom: "*" - checksum: 10c0/61952050bef257a0999db849a328655a4141d31b8d4fa4d54828da7ee8f710d7e592081a150c8b9750640bcaf78f3b7ca7165aefbcc0048c328407d582fe21b8 + checksum: 10c0/837faf66e24b9b0e2d2d276956f00cf5395a752682396013876935b6b0275b573d4cc3e9667a5110f9077c5943ddd1f47b462217a8418a5e6bdd013de8afd918 languageName: node linkType: hard @@ -2646,15 +2646,15 @@ __metadata: languageName: node linkType: hard -"@docusaurus/plugin-client-redirects@npm:^3.10.0": - version: 3.10.0 - resolution: "@docusaurus/plugin-client-redirects@npm:3.10.0" +"@docusaurus/plugin-client-redirects@npm:^3.10.1": + version: 3.10.1 + resolution: "@docusaurus/plugin-client-redirects@npm:3.10.1" dependencies: - "@docusaurus/core": "npm:3.10.0" - "@docusaurus/logger": "npm:3.10.0" - "@docusaurus/utils": "npm:3.10.0" - "@docusaurus/utils-common": "npm:3.10.0" - "@docusaurus/utils-validation": "npm:3.10.0" + "@docusaurus/core": "npm:3.10.1" + "@docusaurus/logger": "npm:3.10.1" + "@docusaurus/utils": "npm:3.10.1" + "@docusaurus/utils-common": "npm:3.10.1" + "@docusaurus/utils-validation": "npm:3.10.1" eta: "npm:^2.2.0" fs-extra: "npm:^11.1.1" lodash: "npm:^4.17.21" @@ -2662,22 +2662,22 @@ __metadata: peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - checksum: 10c0/06dced23c81d0008a9b0856cad74b76d20d93f8191bc6484770f23473e128e46524442f6f7569d2df9d1c745bea6d2c8d18a70834395bc88335b233febb314fe + checksum: 10c0/0bcd7387b6ae3132ab76c7715d440bb6b769ab509fa241720a90575b01541eefe3cd47281da812c546db0e31cffc002c4fb8629430fd1191e5d6f27ef2037483 languageName: node linkType: hard -"@docusaurus/plugin-content-blog@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/plugin-content-blog@npm:3.10.0" - dependencies: - "@docusaurus/core": "npm:3.10.0" - "@docusaurus/logger": "npm:3.10.0" - "@docusaurus/mdx-loader": "npm:3.10.0" - "@docusaurus/theme-common": "npm:3.10.0" - "@docusaurus/types": "npm:3.10.0" - "@docusaurus/utils": "npm:3.10.0" - "@docusaurus/utils-common": "npm:3.10.0" - "@docusaurus/utils-validation": "npm:3.10.0" +"@docusaurus/plugin-content-blog@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/plugin-content-blog@npm:3.10.1" + dependencies: + "@docusaurus/core": "npm:3.10.1" + "@docusaurus/logger": "npm:3.10.1" + "@docusaurus/mdx-loader": "npm:3.10.1" + "@docusaurus/theme-common": "npm:3.10.1" + "@docusaurus/types": "npm:3.10.1" + "@docusaurus/utils": "npm:3.10.1" + "@docusaurus/utils-common": "npm:3.10.1" + "@docusaurus/utils-validation": "npm:3.10.1" cheerio: "npm:1.0.0-rc.12" combine-promises: "npm:^1.1.0" feed: "npm:^4.2.2" @@ -2693,23 +2693,23 @@ __metadata: "@docusaurus/plugin-content-docs": "*" react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - checksum: 10c0/80295c4d217c45d2685d71e3e898e4e67715ce3ecf684063927e0f9c771a2156af2aefb813b61ed33d8a14bc0dbc820da9cd745b32fe4ef5baa03091165b3542 + checksum: 10c0/5c6d912bbcbbc9efa5c81e256f4074e70980c85623f5fd72a344b90bd5f23ed2c03030d8d0cb1ce38bdb2263fdf74ac3e7801a66050184ed11005adc5f49bcb2 languageName: node linkType: hard -"@docusaurus/plugin-content-docs@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/plugin-content-docs@npm:3.10.0" - dependencies: - "@docusaurus/core": "npm:3.10.0" - "@docusaurus/logger": "npm:3.10.0" - "@docusaurus/mdx-loader": "npm:3.10.0" - "@docusaurus/module-type-aliases": "npm:3.10.0" - "@docusaurus/theme-common": "npm:3.10.0" - "@docusaurus/types": "npm:3.10.0" - "@docusaurus/utils": "npm:3.10.0" - "@docusaurus/utils-common": "npm:3.10.0" - "@docusaurus/utils-validation": "npm:3.10.0" +"@docusaurus/plugin-content-docs@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/plugin-content-docs@npm:3.10.1" + dependencies: + "@docusaurus/core": "npm:3.10.1" + "@docusaurus/logger": "npm:3.10.1" + "@docusaurus/mdx-loader": "npm:3.10.1" + "@docusaurus/module-type-aliases": "npm:3.10.1" + "@docusaurus/theme-common": "npm:3.10.1" + "@docusaurus/types": "npm:3.10.1" + "@docusaurus/utils": "npm:3.10.1" + "@docusaurus/utils-common": "npm:3.10.1" + "@docusaurus/utils-validation": "npm:3.10.1" "@types/react-router-config": "npm:^5.0.7" combine-promises: "npm:^1.1.0" fs-extra: "npm:^11.1.1" @@ -2722,7 +2722,7 @@ __metadata: peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - checksum: 10c0/d1d61c85363231216e7f02731806c1519804c14b1a59bab84c386f4dfb45433081ed516cca42d8d891b9855a9ec996d53fe1a7624474a70d64515e7205beb791 + checksum: 10c0/a9d78f6979cc64aef1210f51979f2ed5100ce4a49ba266386e35e9109e4415e66bd9a9448696078f247d204949a29197faa9396bd1f014c88fcdd1aa1e98a3f8 languageName: node linkType: hard @@ -2755,129 +2755,129 @@ __metadata: languageName: node linkType: hard -"@docusaurus/plugin-content-pages@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/plugin-content-pages@npm:3.10.0" +"@docusaurus/plugin-content-pages@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/plugin-content-pages@npm:3.10.1" dependencies: - "@docusaurus/core": "npm:3.10.0" - "@docusaurus/mdx-loader": "npm:3.10.0" - "@docusaurus/types": "npm:3.10.0" - "@docusaurus/utils": "npm:3.10.0" - "@docusaurus/utils-validation": "npm:3.10.0" + "@docusaurus/core": "npm:3.10.1" + "@docusaurus/mdx-loader": "npm:3.10.1" + "@docusaurus/types": "npm:3.10.1" + "@docusaurus/utils": "npm:3.10.1" + "@docusaurus/utils-validation": "npm:3.10.1" fs-extra: "npm:^11.1.1" tslib: "npm:^2.6.0" webpack: "npm:^5.88.1" peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - checksum: 10c0/780bf847a37a2bd7732870f2f8e7395aa82c0f9cba61353225fe6c1abfe48b1403b21f2ad67983db0f0712b01be277796e8d4d51d16e082447c269fe5afadb6c + checksum: 10c0/00dab7af101b0607746d820c399bc3062279165b1b79009f2c6c8439a627818748da52f43eee0a4a874923707c89c9fce17aab72a7c88d298fa36b6efc0bacc7 languageName: node linkType: hard -"@docusaurus/plugin-css-cascade-layers@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/plugin-css-cascade-layers@npm:3.10.0" +"@docusaurus/plugin-css-cascade-layers@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/plugin-css-cascade-layers@npm:3.10.1" dependencies: - "@docusaurus/core": "npm:3.10.0" - "@docusaurus/types": "npm:3.10.0" - "@docusaurus/utils": "npm:3.10.0" - "@docusaurus/utils-validation": "npm:3.10.0" + "@docusaurus/core": "npm:3.10.1" + "@docusaurus/types": "npm:3.10.1" + "@docusaurus/utils": "npm:3.10.1" + "@docusaurus/utils-validation": "npm:3.10.1" tslib: "npm:^2.6.0" - checksum: 10c0/ebbfadc70293ff30878f263a166cd0c1e0bea24067acfc8ccb5d45adb9cc653c753fa9a27d874cd5e7855e2f7e5a35f1d337f07b6b28edabc77524f3533f47ea + checksum: 10c0/fd11a7488029226276bbdbeb1de4035ed425b8d7be0fbad3d5a0aa3a18646064f1930835bfc951837bfc813873548e1a8b23d9f52cb20120e1239a1d93128d79 languageName: node linkType: hard -"@docusaurus/plugin-debug@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/plugin-debug@npm:3.10.0" +"@docusaurus/plugin-debug@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/plugin-debug@npm:3.10.1" dependencies: - "@docusaurus/core": "npm:3.10.0" - "@docusaurus/types": "npm:3.10.0" - "@docusaurus/utils": "npm:3.10.0" + "@docusaurus/core": "npm:3.10.1" + "@docusaurus/types": "npm:3.10.1" + "@docusaurus/utils": "npm:3.10.1" fs-extra: "npm:^11.1.1" react-json-view-lite: "npm:^2.3.0" tslib: "npm:^2.6.0" peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - checksum: 10c0/575c364dcd2595928ebbc8ce6e90113e6bdcc2658ae59f3ddcd0fa2699880a81648765dc7083058bcc957bafd0f7e116c61c62e0cb6b678af97f7e719b5d2db7 + checksum: 10c0/d2978e40e83c1c4fd904dc3bc62ef1b6d52cf28e391e9dacad40712d7b14ce9ad22f0ad710631021066c296d10c364621b2c11a186694d8f5c6e59f35043f99a languageName: node linkType: hard -"@docusaurus/plugin-google-analytics@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/plugin-google-analytics@npm:3.10.0" +"@docusaurus/plugin-google-analytics@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/plugin-google-analytics@npm:3.10.1" dependencies: - "@docusaurus/core": "npm:3.10.0" - "@docusaurus/types": "npm:3.10.0" - "@docusaurus/utils-validation": "npm:3.10.0" + "@docusaurus/core": "npm:3.10.1" + "@docusaurus/types": "npm:3.10.1" + "@docusaurus/utils-validation": "npm:3.10.1" tslib: "npm:^2.6.0" peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - checksum: 10c0/f3814d3ec0c7e2040ac5f3a21a9e1dbb19d58af5a1096fe8376a8661fac92e9e77d3d48742ed7dfb0a1e635360bf1a4e2dd456b5d9d8746e490a250f9b7da097 + checksum: 10c0/c9aff3f3467d3e76a1dd8e1518e8a11b0d488b1761f0302a6cc9fdb94635b6e5673b3d993434205dc65cd6eb9677f795157887d508f01ba175c3f5e411aab2e6 languageName: node linkType: hard -"@docusaurus/plugin-google-gtag@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/plugin-google-gtag@npm:3.10.0" +"@docusaurus/plugin-google-gtag@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/plugin-google-gtag@npm:3.10.1" dependencies: - "@docusaurus/core": "npm:3.10.0" - "@docusaurus/types": "npm:3.10.0" - "@docusaurus/utils-validation": "npm:3.10.0" + "@docusaurus/core": "npm:3.10.1" + "@docusaurus/types": "npm:3.10.1" + "@docusaurus/utils-validation": "npm:3.10.1" "@types/gtag.js": "npm:^0.0.20" tslib: "npm:^2.6.0" peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - checksum: 10c0/31739d936f9ffa4c500d518816b17ac4f2ba2e75e20e5a6708eb2ed5d488465146b5a632899ab894cf8d8233306d212ac79d89c4c6a26c45f6dd15d31638444d + checksum: 10c0/6792713f813cb06dcc54ece92ac81faed01017a71079726f97adade1fa2b6665626369c788e108dee9c02e0cbfc4cc71a2e87db5d3e43f47944e7b0921bb71db languageName: node linkType: hard -"@docusaurus/plugin-google-tag-manager@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/plugin-google-tag-manager@npm:3.10.0" +"@docusaurus/plugin-google-tag-manager@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/plugin-google-tag-manager@npm:3.10.1" dependencies: - "@docusaurus/core": "npm:3.10.0" - "@docusaurus/types": "npm:3.10.0" - "@docusaurus/utils-validation": "npm:3.10.0" + "@docusaurus/core": "npm:3.10.1" + "@docusaurus/types": "npm:3.10.1" + "@docusaurus/utils-validation": "npm:3.10.1" tslib: "npm:^2.6.0" peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - checksum: 10c0/6937bd384653ef938a5b66cf56bce458cc39c33aa35a6ebc43139abb393cfc7cf7865dcf6af60a2dbf65ebb06d40303530430a52e30a119b9c3d7419e53f3a6d + checksum: 10c0/a1a01de5f876d63fec022d312c711525523ee380af3382e35d1953a577450da36039dfcd1ff7f0af0cd189cc14d268c64276def573bdc70d091db2cad56edf9f languageName: node linkType: hard -"@docusaurus/plugin-sitemap@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/plugin-sitemap@npm:3.10.0" - dependencies: - "@docusaurus/core": "npm:3.10.0" - "@docusaurus/logger": "npm:3.10.0" - "@docusaurus/types": "npm:3.10.0" - "@docusaurus/utils": "npm:3.10.0" - "@docusaurus/utils-common": "npm:3.10.0" - "@docusaurus/utils-validation": "npm:3.10.0" +"@docusaurus/plugin-sitemap@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/plugin-sitemap@npm:3.10.1" + dependencies: + "@docusaurus/core": "npm:3.10.1" + "@docusaurus/logger": "npm:3.10.1" + "@docusaurus/types": "npm:3.10.1" + "@docusaurus/utils": "npm:3.10.1" + "@docusaurus/utils-common": "npm:3.10.1" + "@docusaurus/utils-validation": "npm:3.10.1" fs-extra: "npm:^11.1.1" sitemap: "npm:^7.1.1" tslib: "npm:^2.6.0" peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - checksum: 10c0/a0538da02713caaf844cd3b489a360408bb6868ceefbe3e51e7d02223919e8349b219aac1d111e258a29be5eeaea53d712448abf9d7d860f0af89b12d6652a86 + checksum: 10c0/22c04be000a1577f9a0c169fb67ff0d4deaf618aa2a3839336cfaed667558f1db3ada5bed23ee7245596a307bbddbed62ede8e342120aa8efebe0b9d35f4da75 languageName: node linkType: hard -"@docusaurus/plugin-svgr@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/plugin-svgr@npm:3.10.0" +"@docusaurus/plugin-svgr@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/plugin-svgr@npm:3.10.1" dependencies: - "@docusaurus/core": "npm:3.10.0" - "@docusaurus/types": "npm:3.10.0" - "@docusaurus/utils": "npm:3.10.0" - "@docusaurus/utils-validation": "npm:3.10.0" + "@docusaurus/core": "npm:3.10.1" + "@docusaurus/types": "npm:3.10.1" + "@docusaurus/utils": "npm:3.10.1" + "@docusaurus/utils-validation": "npm:3.10.1" "@svgr/core": "npm:8.1.0" "@svgr/webpack": "npm:^8.1.0" tslib: "npm:^2.6.0" @@ -2885,53 +2885,53 @@ __metadata: peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - checksum: 10c0/31a049eaf82c80296b0dc4d7d7bd292bda13dbcf9f07943db4cd2b721276185cb95f6058c406ff4602f4ff408f0fb042f3ade8c8e1d009054ecfa55d99960a88 - languageName: node - linkType: hard - -"@docusaurus/preset-classic@npm:^3.10.0": - version: 3.10.0 - resolution: "@docusaurus/preset-classic@npm:3.10.0" - dependencies: - "@docusaurus/core": "npm:3.10.0" - "@docusaurus/plugin-content-blog": "npm:3.10.0" - "@docusaurus/plugin-content-docs": "npm:3.10.0" - "@docusaurus/plugin-content-pages": "npm:3.10.0" - "@docusaurus/plugin-css-cascade-layers": "npm:3.10.0" - "@docusaurus/plugin-debug": "npm:3.10.0" - "@docusaurus/plugin-google-analytics": "npm:3.10.0" - "@docusaurus/plugin-google-gtag": "npm:3.10.0" - "@docusaurus/plugin-google-tag-manager": "npm:3.10.0" - "@docusaurus/plugin-sitemap": "npm:3.10.0" - "@docusaurus/plugin-svgr": "npm:3.10.0" - "@docusaurus/theme-classic": "npm:3.10.0" - "@docusaurus/theme-common": "npm:3.10.0" - "@docusaurus/theme-search-algolia": "npm:3.10.0" - "@docusaurus/types": "npm:3.10.0" + checksum: 10c0/d866efe42351d1a66febacd6c33753f5ace2056fe86259365408edd354fb67994208a4e2c9939a921c2a20cb11b64fdd3584d34dde8d0329a63a55c9a74c488f + languageName: node + linkType: hard + +"@docusaurus/preset-classic@npm:^3.10.1": + version: 3.10.1 + resolution: "@docusaurus/preset-classic@npm:3.10.1" + dependencies: + "@docusaurus/core": "npm:3.10.1" + "@docusaurus/plugin-content-blog": "npm:3.10.1" + "@docusaurus/plugin-content-docs": "npm:3.10.1" + "@docusaurus/plugin-content-pages": "npm:3.10.1" + "@docusaurus/plugin-css-cascade-layers": "npm:3.10.1" + "@docusaurus/plugin-debug": "npm:3.10.1" + "@docusaurus/plugin-google-analytics": "npm:3.10.1" + "@docusaurus/plugin-google-gtag": "npm:3.10.1" + "@docusaurus/plugin-google-tag-manager": "npm:3.10.1" + "@docusaurus/plugin-sitemap": "npm:3.10.1" + "@docusaurus/plugin-svgr": "npm:3.10.1" + "@docusaurus/theme-classic": "npm:3.10.1" + "@docusaurus/theme-common": "npm:3.10.1" + "@docusaurus/theme-search-algolia": "npm:3.10.1" + "@docusaurus/types": "npm:3.10.1" peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - checksum: 10c0/c7d9ce9b76f309b65a3cdba6702f49adb4c518da3e3c4a4f745c5ad659cab9a9d1bf3841d49817fa4a1e3d226c2f683d6e263bb36d9d9bb6143f9fc4d36add42 - languageName: node - linkType: hard - -"@docusaurus/theme-classic@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/theme-classic@npm:3.10.0" - dependencies: - "@docusaurus/core": "npm:3.10.0" - "@docusaurus/logger": "npm:3.10.0" - "@docusaurus/mdx-loader": "npm:3.10.0" - "@docusaurus/module-type-aliases": "npm:3.10.0" - "@docusaurus/plugin-content-blog": "npm:3.10.0" - "@docusaurus/plugin-content-docs": "npm:3.10.0" - "@docusaurus/plugin-content-pages": "npm:3.10.0" - "@docusaurus/theme-common": "npm:3.10.0" - "@docusaurus/theme-translations": "npm:3.10.0" - "@docusaurus/types": "npm:3.10.0" - "@docusaurus/utils": "npm:3.10.0" - "@docusaurus/utils-common": "npm:3.10.0" - "@docusaurus/utils-validation": "npm:3.10.0" + checksum: 10c0/524675229e33f24f678ca104eab1b6328ca31c2572e5cb2a598a330bd990a8d50eb1929aaef9031c37827a22ddaf6bb19484b75ac2a5b0936f6322d951f33559 + languageName: node + linkType: hard + +"@docusaurus/theme-classic@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/theme-classic@npm:3.10.1" + dependencies: + "@docusaurus/core": "npm:3.10.1" + "@docusaurus/logger": "npm:3.10.1" + "@docusaurus/mdx-loader": "npm:3.10.1" + "@docusaurus/module-type-aliases": "npm:3.10.1" + "@docusaurus/plugin-content-blog": "npm:3.10.1" + "@docusaurus/plugin-content-docs": "npm:3.10.1" + "@docusaurus/plugin-content-pages": "npm:3.10.1" + "@docusaurus/theme-common": "npm:3.10.1" + "@docusaurus/theme-translations": "npm:3.10.1" + "@docusaurus/types": "npm:3.10.1" + "@docusaurus/utils": "npm:3.10.1" + "@docusaurus/utils-common": "npm:3.10.1" + "@docusaurus/utils-validation": "npm:3.10.1" "@mdx-js/react": "npm:^3.0.0" clsx: "npm:^2.0.0" copy-text-to-clipboard: "npm:^3.2.0" @@ -2948,18 +2948,18 @@ __metadata: peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - checksum: 10c0/920df8c75701cd462cc414440b446157b6c831432bb2fe0e506268a5a72ef7fefe58568d8fb12bfc61845e8809f5fe6900314f39e9867a0aedabd184cbaa05b9 + checksum: 10c0/55be80ca9a1880c0a923c519243233bb52025e4a0ae312907c9df52b8ab3594819da164a71377e6ed5b02eef740496eff006da41462603195c0284b977515ceb languageName: node linkType: hard -"@docusaurus/theme-common@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/theme-common@npm:3.10.0" +"@docusaurus/theme-common@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/theme-common@npm:3.10.1" dependencies: - "@docusaurus/mdx-loader": "npm:3.10.0" - "@docusaurus/module-type-aliases": "npm:3.10.0" - "@docusaurus/utils": "npm:3.10.0" - "@docusaurus/utils-common": "npm:3.10.0" + "@docusaurus/mdx-loader": "npm:3.10.1" + "@docusaurus/module-type-aliases": "npm:3.10.1" + "@docusaurus/utils": "npm:3.10.1" + "@docusaurus/utils-common": "npm:3.10.1" "@types/history": "npm:^4.7.11" "@types/react": "npm:*" "@types/react-router-config": "npm:*" @@ -2972,7 +2972,7 @@ __metadata: "@docusaurus/plugin-content-docs": "*" react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - checksum: 10c0/16cda69e916adfc2cfdeea6940264c01d56e8b87e87fca887d7d28933712333b5b60ce60a64d505ddda8da2c6538b50f3aa4e16351e3d05df9f8e590b407be6e + checksum: 10c0/f66e25b6449e03b5c8812be407e80c1c9ffc87b07395273d009a40761302e6230ab357096de95b47f77aef1d7e4d0363220cca07b7fbdeb9679770e20e0ab7a4 languageName: node linkType: hard @@ -3000,15 +3000,15 @@ __metadata: languageName: node linkType: hard -"@docusaurus/theme-mermaid@npm:^3.10.0": - version: 3.10.0 - resolution: "@docusaurus/theme-mermaid@npm:3.10.0" +"@docusaurus/theme-mermaid@npm:^3.10.1": + version: 3.10.1 + resolution: "@docusaurus/theme-mermaid@npm:3.10.1" dependencies: - "@docusaurus/core": "npm:3.10.0" - "@docusaurus/module-type-aliases": "npm:3.10.0" - "@docusaurus/theme-common": "npm:3.10.0" - "@docusaurus/types": "npm:3.10.0" - "@docusaurus/utils-validation": "npm:3.10.0" + "@docusaurus/core": "npm:3.10.1" + "@docusaurus/module-type-aliases": "npm:3.10.1" + "@docusaurus/theme-common": "npm:3.10.1" + "@docusaurus/types": "npm:3.10.1" + "@docusaurus/utils-validation": "npm:3.10.1" mermaid: "npm:>=11.6.0" tslib: "npm:^2.6.0" peerDependencies: @@ -3018,23 +3018,23 @@ __metadata: peerDependenciesMeta: "@mermaid-js/layout-elk": optional: true - checksum: 10c0/2bf6c0b0c7a7a55f7a89e6af7abef5ce2ca8f2e3c4a5e5be5b99cc9d8043135253dd73a588f008d3a5abf4133a3cc631983153e60fa05236398a7a2bac3f3cf7 + checksum: 10c0/73839669eb3e69ec565a16853b6a8fa636f3fd94d6656976835a0304bb6e7402b5dcbd7808b8b158bb0f34e61fee1d835511d88f59f48fa613eb51532614992c languageName: node linkType: hard -"@docusaurus/theme-search-algolia@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/theme-search-algolia@npm:3.10.0" +"@docusaurus/theme-search-algolia@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/theme-search-algolia@npm:3.10.1" dependencies: "@algolia/autocomplete-core": "npm:^1.19.2" "@docsearch/react": "npm:^3.9.0 || ^4.3.2" - "@docusaurus/core": "npm:3.10.0" - "@docusaurus/logger": "npm:3.10.0" - "@docusaurus/plugin-content-docs": "npm:3.10.0" - "@docusaurus/theme-common": "npm:3.10.0" - "@docusaurus/theme-translations": "npm:3.10.0" - "@docusaurus/utils": "npm:3.10.0" - "@docusaurus/utils-validation": "npm:3.10.0" + "@docusaurus/core": "npm:3.10.1" + "@docusaurus/logger": "npm:3.10.1" + "@docusaurus/plugin-content-docs": "npm:3.10.1" + "@docusaurus/theme-common": "npm:3.10.1" + "@docusaurus/theme-translations": "npm:3.10.1" + "@docusaurus/utils": "npm:3.10.1" + "@docusaurus/utils-validation": "npm:3.10.1" algoliasearch: "npm:^5.37.0" algoliasearch-helper: "npm:^3.26.0" clsx: "npm:^2.0.0" @@ -3046,17 +3046,17 @@ __metadata: peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - checksum: 10c0/63dd5f7e99457a71f0eb7916e18fa421e3194018975a52e8d8bd197abfdf5f19d85348a8a7e0713bccac413e9d5b1cb54b9c69c28a868e0473c1cf0b806f3faa + checksum: 10c0/dd558ac0c50f2374b8285f463ec23e1996247f4436cd9147fd313689d02d9113214e0368c64fdc8ca106f10b6ef93589814980ea0121cb3583ca87feae4b19c3 languageName: node linkType: hard -"@docusaurus/theme-translations@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/theme-translations@npm:3.10.0" +"@docusaurus/theme-translations@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/theme-translations@npm:3.10.1" dependencies: fs-extra: "npm:^11.1.1" tslib: "npm:^2.6.0" - checksum: 10c0/62fa157763e2ad4d8c7afea0edebce895f85da5384c48222a1f697932716c550eeda34310d473643d037ae6d41720909174abf409971fcddd0eadb63daafced6 + checksum: 10c0/2a1c871e883a82c4c5071820dcdc3bbeea5a3571978d022c1d1b820ae8b676ea5dd173b9c17542a032b9a5ec7e06f5d8a3b9de31a1e1f474f527baccfb5f9deb languageName: node linkType: hard @@ -3070,9 +3070,9 @@ __metadata: languageName: node linkType: hard -"@docusaurus/types@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/types@npm:3.10.0" +"@docusaurus/types@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/types@npm:3.10.1" dependencies: "@mdx-js/mdx": "npm:^3.0.0" "@types/history": "npm:^4.7.11" @@ -3087,7 +3087,7 @@ __metadata: peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - checksum: 10c0/0d0f5f57bb82f190385a506192d882a5072e833af55a35cb5fb69048bb4258012eebe51448b8ace9d77d05d69a99d7fd2dcae25bb4babfa205abfbca222de8d5 + checksum: 10c0/63cc1d92ec775fb0e58f156b4edc7075612943a94d15d4648b60effcbc34c70a1092569d66d552878779b48d5111abe2fc154ba6a3bca2af0383550c9f9a015b languageName: node linkType: hard @@ -3112,13 +3112,13 @@ __metadata: languageName: node linkType: hard -"@docusaurus/utils-common@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/utils-common@npm:3.10.0" +"@docusaurus/utils-common@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/utils-common@npm:3.10.1" dependencies: - "@docusaurus/types": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.1" tslib: "npm:^2.6.0" - checksum: 10c0/12e54b8e29d1d8d78f85598a154fc122f4d93bdd143b55fd7a474c2d9eab431bbf13ac61e008f1c4f34ffce76578fe95b441f6a6469a752d7396f9d9c000f6e4 + checksum: 10c0/1dde7a5c538a2cbe9eba46c9a3991a773e2d9d5b9c489cb010f9284c33cba7d494c1300557f850fa6a6e857747ca835b91f6036b02a726e13d296d7a65f8d8db languageName: node linkType: hard @@ -3132,19 +3132,19 @@ __metadata: languageName: node linkType: hard -"@docusaurus/utils-validation@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/utils-validation@npm:3.10.0" +"@docusaurus/utils-validation@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/utils-validation@npm:3.10.1" dependencies: - "@docusaurus/logger": "npm:3.10.0" - "@docusaurus/utils": "npm:3.10.0" - "@docusaurus/utils-common": "npm:3.10.0" + "@docusaurus/logger": "npm:3.10.1" + "@docusaurus/utils": "npm:3.10.1" + "@docusaurus/utils-common": "npm:3.10.1" fs-extra: "npm:^11.2.0" joi: "npm:^17.9.2" js-yaml: "npm:^4.1.0" lodash: "npm:^4.17.21" tslib: "npm:^2.6.0" - checksum: 10c0/ab1aee9c9b236d4c5247f33b245c016a2ef501ef154f5f5392a98e706d448ee60c32746b4c58e4954be24393eee6db06cb3192efa8df00343176c558fca33924 + checksum: 10c0/6368eb2a879fc1c4a507873689bd0a08257e2bc72a2ba53b3629d633d97d368168720fc504a54f96a0652982fc098f29675076e1fbcaf0244947645131a3d2f9 languageName: node linkType: hard @@ -3164,13 +3164,13 @@ __metadata: languageName: node linkType: hard -"@docusaurus/utils@npm:3.10.0": - version: 3.10.0 - resolution: "@docusaurus/utils@npm:3.10.0" +"@docusaurus/utils@npm:3.10.1": + version: 3.10.1 + resolution: "@docusaurus/utils@npm:3.10.1" dependencies: - "@docusaurus/logger": "npm:3.10.0" - "@docusaurus/types": "npm:3.10.0" - "@docusaurus/utils-common": "npm:3.10.0" + "@docusaurus/logger": "npm:3.10.1" + "@docusaurus/types": "npm:3.10.1" + "@docusaurus/utils-common": "npm:3.10.1" escape-string-regexp: "npm:^4.0.0" execa: "npm:^5.1.1" file-loader: "npm:^6.2.0" @@ -3189,7 +3189,7 @@ __metadata: url-loader: "npm:^4.1.1" utility-types: "npm:^3.10.0" webpack: "npm:^5.88.1" - checksum: 10c0/0f3488c38fbc985378f93f6573cf080559207ae367b0052df2ad42d667726ec766900db68184ec1746bcf4c38c9a1289d9f54fbd71a857dc592363996295afff + checksum: 10c0/97d51da30035ef34eced1dbc937f829309a8165a07a9c66d87c5deec03fb62150cbc70b2763ffdec0286b21f1be53f4011a036e4265cb971a892f0ab12172e0a languageName: node linkType: hard @@ -5946,6 +5946,13 @@ __metadata: languageName: node linkType: hard +"ansis@npm:^3.2.0": + version: 3.17.0 + resolution: "ansis@npm:3.17.0" + checksum: 10c0/d8fa94ca7bb91e7e5f8a7d323756aa075facce07c5d02ca883673e128b2873d16f93e0dec782f98f1eeb1f2b3b4b7b60dcf0ad98fb442e75054fe857988cc5cb + languageName: node + linkType: hard + "anymatch@npm:~3.1.2": version: 3.1.3 resolution: "anymatch@npm:3.1.3" @@ -8829,11 +8836,11 @@ __metadata: resolution: "flet-dev@workspace:." dependencies: "@docsearch/docusaurus-adapter": "npm:^4.6.2" - "@docusaurus/core": "npm:^3.10.0" - "@docusaurus/faster": "npm:^3.10.0" - "@docusaurus/plugin-client-redirects": "npm:^3.10.0" - "@docusaurus/preset-classic": "npm:^3.10.0" - "@docusaurus/theme-mermaid": "npm:^3.10.0" + "@docusaurus/core": "npm:^3.10.1" + "@docusaurus/faster": "npm:^3.10.1" + "@docusaurus/plugin-client-redirects": "npm:^3.10.1" + "@docusaurus/preset-classic": "npm:^3.10.1" + "@docusaurus/theme-mermaid": "npm:^3.10.1" "@hcaptcha/react-hcaptcha": "npm:^1.0.0" "@mdx-js/react": "npm:^3.0.0" clsx: "npm:^1.1.1" @@ -15543,6 +15550,26 @@ __metadata: languageName: node linkType: hard +"webpackbar@npm:^7.0.0": + version: 7.0.0 + resolution: "webpackbar@npm:7.0.0" + dependencies: + ansis: "npm:^3.2.0" + consola: "npm:^3.2.3" + pretty-time: "npm:^1.1.0" + std-env: "npm:^3.7.0" + peerDependencies: + "@rspack/core": "*" + webpack: 3 || 4 || 5 + peerDependenciesMeta: + "@rspack/core": + optional: true + webpack: + optional: true + checksum: 10c0/03ed85edca12af824319dfcd0fe5c3a90b9e3c86400a604a55589abe0a66a682033e7de027e89aae03652b6fb8ca7fd2831d86829179304ea3121f807808f7c6 + languageName: node + linkType: hard + "websocket-driver@npm:>=0.5.1, websocket-driver@npm:^0.7.4": version: 0.7.4 resolution: "websocket-driver@npm:0.7.4"