diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..ce0d568d --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,5 @@ +# Copilot instructions + +See [`AGENTS.md`](../AGENTS.md) at the repo root — the canonical agent +instructions (repo-specific Python/commit/test/generated-file facts) live +there, not here. diff --git a/.github/workflows/preview-release.yml b/.github/workflows/preview-release.yml new file mode 100644 index 00000000..4b0cca6d --- /dev/null +++ b/.github/workflows/preview-release.yml @@ -0,0 +1,169 @@ +name: Preview Release + +# Fork-only automation: cuts a HACS-installable preview build on every push +# to any branch in a fork (other than the fork's own default branch), so a +# pushed branch is immediately pickable by HACS for manual testing without +# waiting for the real release-please.yml flow (which only fires on `main` +# pushes -- see that workflow's own `on:` block -- and only after a PR +# actually merges upstream). +# +# Generalized (2026-09-03, round 2) from a version hard-gated to one fork's +# `owner/repo` and one branch prefix (`designer-*`) to something every fork +# gets automatically, no per-fork edits: +# +# - `github.event.repository.fork` is the generic "is this a fork, not the +# upstream repo" discriminator -- true for every fork, false for +# upstream, so releases here never collide with upstream's real +# release-please releases or spam its release list. Verified available on +# a real push-event payload for this repository, not assumed: `gh api +# repos// --jq '{fork, default_branch}'` against this very +# repo returns `{"default_branch":"main","fork":true}` -- Actions' +# `github.event.repository` is a deserialization of that same GitHub +# "repository" object (identical shape whether returned by the REST API +# or embedded in a webhook payload; see +# https://docs.github.com/en/webhooks/webhook-events-and-payloads#push), +# so both fields are present on the real event this job runs from. This +# push itself is further, live confirmation: the job only runs at all if +# `github.event.repository.fork` was truthy on the actual payload. +# - `github.event.repository.default_branch` (not a hardcoded `main`) +# excludes the fork's own default branch, which tracks upstream -- +# syncing it must never cut a preview. Both checks are job-level `if:` +# conditions, not `on.push` filters: `branches:` glob patterns are +# static and can't reference `default_branch`, which differs per fork. +# - `branches: ['**']` (any branch, still excludes tag pushes) replaces the +# old `designer-*`-only filter -- every branch in a fork gets a preview +# build, not just ones with a specific prefix; that was this workflow's +# whole reason to be forked-only in the first place. +# +# A branch name is otherwise unconstrained free text (slashes, dots, +# uppercase, leading digits, ...) and gets embedded in a semver prerelease +# identifier below -- scripts/preview_version.py's +# `sanitize_branch_for_version` maps ANY branch name onto something Home +# Assistant's own version check accepts (tested in +# tests/test_preview_version.py against every shape a contributor could +# actually push), rather than narrowing the trigger to branch patterns that +# happen to already be safe. +on: + push: + branches: + - '**' + +jobs: + preview-release: + if: >- + github.event.repository.fork && + github.ref_name != github.event.repository.default_branch + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + + # Compute the preview version/name and stamp manifest.json IN THIS + # CHECKOUT ONLY, never committed/pushed: the runner's checkout is + # thrown away after the job, so these edits never reach git. + # + # `version`: without it, HA's integration card shows the last + # released "Version 3.0.2" for every preview install, indistinguishable + # from the real release (maintainer tier-2 finding) -- patching it + # makes the HA UI and logs identify the exact preview build. + # + # `name`: a fork's build otherwise looks identical to every other + # fork's and to upstream's -- "OpenDisplay" -- everywhere Home + # Assistant shows it (Devices & Services, the integration detail + # page, log lines), because that string comes from THIS SAME + # manifest.json, baked into the installed zip below. Appending + # `(fork: /)` from `github.repository` makes a fork + # self-identifying with no hand-edited GitHub repo description (the + # previous, per-fork-manual approach). This deliberately does NOT + # touch `hacs.json` or `manifest.json`'s `domain`: + # - `domain` must stay `opendisplay` so a fork still replaces the + # stock integration rather than installing alongside it. + # - hacs.json's list-card name/description in the HACS UI are read + # LIVE from the repository's git tree (hacs.json's own "name" key + # if set, else this same manifest's "name" -- both via GitHub's + # API at whatever ref HACS resolves) -- never from a release + # ZIP asset, and hacs.json isn't even packaged into the zip + # (zip step below only touches custom_components/opendisplay/, + # hacs.json lives at repo root). A checkout-only stamp in a job + # that never commits cannot reach either of those, regardless of + # which ref HACS reads -- confirmed against HACS's own source + # (hacs/integration, `repositories/base.py`: `display_name` + # returns `repository_manifest.name` -- i.e. hacs.json's tracked + # "name" -- unconditionally if set, before ever looking at any + # manifest; `description` is a separate field populated from the + # GitHub repository object, not from any file in the repo at + # all). What DOES reach the user unconditionally: Home + # Assistant's own UI, which reads the manifest baked into the + # zip HACS actually downloads and installs -- the same mechanism + # already proven by the version stamp above. + # + # Both compositions live in scripts/preview_version.py (regression- + # tested against Home Assistant's own AwesomeVersion loader check in + # tests/test_preview_version.py) -- not reimplemented here, so the + # tested procedure IS the shipped procedure. DO NOT zero-pad + # run_number, and do NOT embed a raw, unsanitized branch name: a + # leading zero, or a branch containing "/" or a dozen other + # characters, makes the prerelease identifier invalid semver, and + # Home Assistant then refuses to load the integration AT ALL: "The + # custom integration 'opendisplay' does not have a valid version key + # (3.0.2-designer-v2.012) in the manifest file and was blocked from + # loading." Every service the integration provides disappears + # (`opendisplay.drawcustom` not found) and automations break. + # Padding was tried once to fix UI ordering (v2.9 reading as newer + # than v2.10) and reverted for this reason; the ordering cosmetics + # are not worth an unloadable integration. + # + # Fails loudly (`jq -e`, unset -u) if .version/.name are ever + # missing/renamed rather than silently zipping an unpatched manifest. + - name: Compute preview metadata and stamp manifest + run: | + set -euo pipefail + base_version="$(jq -er .version custom_components/opendisplay/manifest.json)" + base_name="$(jq -er .name custom_components/opendisplay/manifest.json)" + branch="${{ github.ref_name }}" + run_number="${{ github.run_number }}" + repository="${{ github.repository }}" + preview_version="$(python3 scripts/preview_version.py version "$base_version" "$branch" "$run_number")" + preview_name="$(python3 scripts/preview_version.py name "$base_name" "$repository")" + echo "PREVIEW_VERSION=${preview_version}" >> "$GITHUB_ENV" + jq --arg v "$preview_version" --arg n "$preview_name" \ + '.version = $v | .name = $n' \ + custom_components/opendisplay/manifest.json > /tmp/manifest.json + mv /tmp/manifest.json custom_components/opendisplay/manifest.json + + # Same zip, same command, same working directory as release-please.yml's + # own "Create zip" step -- this IS what HACS's zip_release install + # path (hacs.json) expects, not a preview-specific format. Zips the + # manifest stamped above, so the shipped preview build self-identifies. + - name: Create zip + run: | + cd custom_components/opendisplay + zip opendisplay.zip -r ./ + + # Tag reuses PREVIEW_VERSION computed above (base manifest version -- + # not bumped, this is a preview of unreleased work, not a + # release-please release -- plus the sanitized branch name and this + # workflow's own run number), so pushes to different branches -- or + # repeated pushes to the same one -- never collide on a tag, and the + # tag itself is always a legal git ref name (sanitize_branch_for_version + # restricts the branch component to `[0-9A-Za-z-]`, a strict subset of + # legal tag characters -- see tests/test_preview_version.py's + # `assert_valid_git_tag`, which checks every test-matrix case with + # `git check-ref-format` itself). Matches the maintainer's own manual + # precedent (v3.0.2-designer.1, cut by hand from 74a8e9d) in shape, + # not literally: that one used a shortened branch label by hand, this + # uses the real (sanitized) branch name so two different branches' + # tags can't collide. + - name: Create preview release + env: + GH_TOKEN: ${{ github.token }} + run: | + branch="${{ github.ref_name }}" + sha="$(git rev-parse --short HEAD)" + tag="v${PREVIEW_VERSION}" + gh release create "$tag" \ + --target "$branch" \ + --title "Preview build: ${branch}@${sha}" \ + --notes "Automated preview build of ${branch}@${sha} for HACS testing — not an upstream release." \ + custom_components/opendisplay/opendisplay.zip diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 05b44357..28be7486 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -41,6 +41,15 @@ jobs: - name: Install run: uv sync --no-default-groups --group ${{ matrix.group }} + # tests/js/ (plain node --test, no npm/package.json anywhere in this + # repo) is the ONLY coverage for the designer panel's keyboard- + # containment fix -- runs nowhere else. Once per matrix run (not + # HA-version-dependent) is enough, same rationale as "Upload + # coverage" below only running on one leg. + - name: Run JS tests + if: matrix.leg == 'latest' + run: scripts/test-js + - name: Run tests run: > uv run --no-default-groups --group ${{ matrix.group }} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..f2dea27f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,56 @@ +# Agent instructions + +This file exists so an automated contributor or reviewer has this repo's +own facts on hand instead of guessing. Concrete example: a review bot +flagged `except AttributeError, IndexError, TypeError, ValueError:` in +`designer/image_entity.py` as invalid Python 2-style syntax — it is legal +Python 3 here, exactly the kind of version-knowledge false positive this +file exists to prevent. + +Start with [`CONTRIBUTING.md`](CONTRIBUTING.md) — setup, the two-leg test +story, HA component requirements, translations, commit/release rules. This +file adds only what a tool with no memory of this repo tends to get wrong. + +## Python + +Floor is 3.14.2 (`pyproject.toml`'s `requires-python`), so 3.14 syntax is +in scope, not a mistake. [PEP 758](https://peps.python.org/pep-0758/) +legalizes unparenthesized `except A, B, C:`, already used in +`custom_components/opendisplay/__init__.py` and +`custom_components/opendisplay/designer/image_entity.py` — do not "fix" it +to `except (A, B, C):` or flag it as Python 2 syntax. + +## Commits + +Every commit on a branch, not just the PR title, must be a [Conventional +Commit](https://www.conventionalcommits.org/) — PRs merge with a merge +commit, and release-please reads each commit's type to decide the release. +A runtime dependency bump (`py-opendisplay`, `odl-renderer`) is +`fix:`/`feat:`, never `chore:`, or it ships silently, unreleased. + +## Tests + +`scripts/test` and `scripts/test --min-ha` both gate (`--min-ha` against +`hacs.json`'s floor HA version, plain `scripts/test` against the newest); a +`--min-ha`-only failure is a bug to fix or a reason to raise the floor, +never one to weaken or skip that leg. `scripts/lint` runs ruff. A missing +module after an HA bump is usually a *component* requirement (invisible to +`uv`, HA installs it at runtime) — pin it by hand; `scripts/ha-component-reqs` +prints the current set. `dev/ha run` brings up a real, disposable, +hardware-free Home Assistant against this checkout. + +## Generated — do not hand-edit + +- `custom_components/opendisplay/designer/frontend/vendor/` — regenerate + only via `scripts/update-designer-vendor.py` (checksum-verified). +- `custom_components/opendisplay/translations/*.json` except `en.json` — + written by `.github/workflows/translate.yml`; manual corrections are + fingerprinted and protected (`.github/translation-state.json`). +- `uv.lock` — regenerate with `uv lock`/`uv sync`. +- `manifest.json`'s `"version"` — written by release-please + (`.release-please-config.json`); the rest of the manifest is hand-edited. + +## CI + +`.github/workflows/preview-release.yml` cuts installable HACS builds from +branches pushed to a **fork** only — inert on this repository itself. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e34e4e72..de2c5796 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,13 +34,55 @@ against `pyproject.toml`. ### Running the integration -To try changes against a real device, symlink the component into a Home -Assistant checkout and start it from there: +Three ways to try changes against a real, running Home Assistant, picked by +what you already have available — the first two put +`custom_components/opendisplay` in front of a real `hass` process, so a +debugger attaches directly either way, same as any other native Python +program. + +**You already have a Home Assistant checkout and real OpenDisplay +hardware**: symlink the component in and start Home Assistant from there: ```bash ln -s "$PWD/custom_components/opendisplay" /path/to/core/config/custom_components/ ``` +**You don't have either** (no live HA, no OpenDisplay hardware): `dev/ha` +is this repo's own disposable-Home-Assistant harness — one entry point, +`dev/ha `, native Python (`uv run hass` under the hood, no +Docker, no container runtime; you never type the `uv run` yourself). +`dev/ha inject` fabricates config entries for a few realistic panels +(small mono / medium BWR / large BWRY) that set up entirely from cache — +no BLE connection, no pairing needed. + +```bash +dev/ha run # bring up HA, onboard +dev/ha stop # stop (storage can't be rewritten under a live process) +dev/ha inject # fabricate 3 devices +dev/ha run # bring HA back up +``` + +See [`dev/README.md`](dev/README.md) for the full workflow (including +`dev/ha`'s other subcommands — `logs`, `token`, `snapshot`/`restore` for +carrying a real device's state between instances), why no BLE discovery +ever happens (the harness's `configuration.yaml` never loads the +`bluetooth` integration — no `default_config`, no explicit `bluetooth:` +key), and the real-hardware snapshot/restore path (`dev/ha snapshot`/ +`dev/ha restore`) if you do have a device but want to capture its state +for a teammate who doesn't. + +**You want someone else (or a fresh, un-instrumented Home Assistant) to try +your change without building anything**: push your branch to your fork. +`.github/workflows/preview-release.yml` cuts an installable HACS build from +it automatically — add your fork as a HACS custom repository once, and +every push after that is a new pickable release, self-identifying as your +fork's build (`OpenDisplay (fork: /)`, visible on Home +Assistant's Devices & Services page) so it's never confused with the real +release or another fork's. See the "Preview releases" section of [`dev/README.md`](dev/README.md) for +exactly what gets stamped, how a branch name is made version-safe, and what +this can't do (it never touches your fork's default branch, and it never +affects HACS's own repository list card). + ## Translations English is written by hand; every other language is filled in by diff --git a/README.md b/README.md index 4bdd4a3a..9d499a2b 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Each device is set up over Bluetooth and appears with: | | | |---|---| -| **Display content** | an image entity showing the last frame sent, or the one queued for a sleeping tag | +| **Display content** | an image entity showing the last frame sent, or the one queued for a sleeping tag — exactly as the panel received it, in the panel's own pixel grid and rotation | | **Sensors** | temperature, humidity (on tags with an SHT40), battery level and voltage, signal strength, last seen | | **Buttons and touch** | event entities for physical buttons and touch controllers | | **Firmware** | an update entity that flashes new firmware over Bluetooth | @@ -64,6 +64,14 @@ announced itself over mDNS, falling back to Bluetooth otherwise. 2. Copy it to your [`custom_components` folder](https://developers.home-assistant.io/docs/creating_integration_file_structure/#where-home-assistant-looks-for-integrations) 3. Restart Home Assistant +Recent Home Assistant releases also ship their own built-in `opendisplay` +integration. A `custom_components/opendisplay` install like this one always +takes precedence over that built-in one for the whole `opendisplay` domain — +this is normal, expected custom-component behavior (not specific to this +integration), and Home Assistant logs a one-time warning about it +("We found a custom integration opendisplay which has not been tested by +Home Assistant...") on every boot as a reminder, not an error. + ## Configuration Devices are discovered automatically once they are in range, over Bluetooth or @@ -139,6 +147,10 @@ data: Every element type and field is documented in [the drawcustom guide](docs/drawcustom/supported_types.md). +**Prefer a visual editor?** The "OpenDisplay Designer" sidebar panel is a +drag-and-drop drawcustom editor with a live, server-rendered preview — see +[`docs/designer.md`](docs/designer.md). + ### Send an existing image ```yaml diff --git a/custom_components/opendisplay/__init__.py b/custom_components/opendisplay/__init__.py index 070df978..82c5da17 100644 --- a/custom_components/opendisplay/__init__.py +++ b/custom_components/opendisplay/__init__.py @@ -37,6 +37,7 @@ from .const import CONF_CACHED_STATE, CONF_ENCRYPTION_KEY, DOMAIN, SETUP_DEADLINE_S from .coordinator import OpenDisplayCoordinator from .delivery import DeliveryManager +from .designer import async_setup_designer from .services import async_setup_services from .sleep import SleepProfile @@ -200,6 +201,7 @@ def _get_encryption_key(entry: OpenDisplayConfigEntry) -> bytes | None: async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the OpenDisplay integration.""" async_setup_services(hass) + await async_setup_designer(hass) return True diff --git a/custom_components/opendisplay/designer/__init__.py b/custom_components/opendisplay/designer/__init__.py new file mode 100644 index 00000000..25d7f46a --- /dev/null +++ b/custom_components/opendisplay/designer/__init__.py @@ -0,0 +1,63 @@ +"""OpenDisplay image designer -- HTTP views and sidebar panel registration.""" + +from __future__ import annotations + +import logging + +from homeassistant.core import HomeAssistant + +from custom_components.opendisplay.const import DOMAIN + +from .asset import OpenDisplayDesignerAssetView +from .panel import ( + DESIGNER_PANEL_PATH, + OpenDisplayDesignerStaticView, + async_get_panel_module_url, +) +from .render import OpenDisplayDesignerRenderView + +_LOGGER = logging.getLogger(__name__) +_DESIGNER_KEY = "designer" + + +async def async_setup_designer(hass: HomeAssistant) -> None: + """Register designer HTTP views and the sidebar panel.""" + hass.data.setdefault(DOMAIN, {}) + designer_data = hass.data[DOMAIN].setdefault(_DESIGNER_KEY, {}) + + if not designer_data.get("views_registered"): + hass.http.register_view(OpenDisplayDesignerRenderView(hass)) + hass.http.register_view(OpenDisplayDesignerAssetView(hass)) + hass.http.register_view(OpenDisplayDesignerStaticView(hass)) + designer_data["views_registered"] = True + + if designer_data.get("panel_registered"): + return + + try: + from homeassistant.components import panel_custom + + await panel_custom.async_register_panel( + hass, + frontend_url_path=DESIGNER_PANEL_PATH, + webcomponent_name="opendisplay-designer-panel", + sidebar_title="OpenDisplay Designer", + sidebar_icon="mdi:monitor-edit", + module_url=await async_get_panel_module_url(hass), + # Deliberate, and deliberately consistent with the views behind + # it: the designer's render endpoint fronts + # `opendisplay.drawcustom`, which any authenticated user can + # already call, and it renders the same templates through the + # same shared helper. Home Assistant templates are read-only, so + # this grants no capability a non-admin does not already have. + # Panel visibility, endpoint authorization and the exposure of + # the service being fronted all match. A deployment that wants + # the designer restricted restricts it at the Home Assistant + # user level -- this integration does not invent its own + # permission model. See docs/designer.md, "Access and exposure". + require_admin=False, + ) + designer_data["panel_registered"] = True + _LOGGER.info("OpenDisplay designer panel registered") + except (AttributeError, ImportError, RuntimeError, ValueError) as err: + _LOGGER.warning("Failed to register OpenDisplay designer panel: %s", err) diff --git a/custom_components/opendisplay/designer/asset.py b/custom_components/opendisplay/designer/asset.py new file mode 100644 index 00000000..739976e4 --- /dev/null +++ b/custom_components/opendisplay/designer/asset.py @@ -0,0 +1,307 @@ +"""Authenticated HTTP view resolving assets for the designer's `resolveAsset` seam. + +Maintainer ruling (tier-2, real hardware): "if the server renderer can use +it, the client must get it mapped" -- the resolveAsset gap `docs/designer.md` +previously only documented is promoted from documented-gap to build item +here. + +Implements the LAST tier of the designer's asset resolution (issue #138, +ADR-002 amendment; `HostAssetResolver` in the vendored `.d.ts`): a payload +may reference a font by bare name (`Tinos-Bold`, `Tinos-Bold.ttf`) the same +way a hand-written `drawcustom` payload does, resolved against this +integration's own font search directories +(`custom_components.opendisplay.services._font_search_dirs` -- +`www/fonts`, `media/fonts`, `/media/fonts`) so a font the SEND/RENDER path +can load is the SAME file the designer's own canvas preview gets, never a +font the server renders with but the designer substitutes or errors on. + +Images (tier-2 round 3, real hardware: a display's payload referenced +`/media/pohl89-480h.png`, the server render resolved it, the designer +preview showed the image missing) work differently, because the renderer +itself treats them differently: `odl_renderer.media_loader.load_image` +takes an ABSOLUTE PATH and opens it directly -- there is no bare-name +search path for images the way `FontManager` has one for fonts. So +`kind=image` resolves the caller's own absolute path, and the reference +that reaches this view is whatever the payload carries. + +That difference is the whole reason the image half needs a path policy the +font half does not. This view returns raw file bytes to ANY authenticated +user, admin or not (`docs/designer.md`, "Access and exposure"), so it is +deliberately STRICTER than the renderer: + +* **Permitted roots** are `hass.config.allowlist_external_dirs` -- Home + Assistant's own canonical answer to "which local directories may be read + on a user's behalf". Core composes that set as `{/www} | + set(hass.config.media_dirs.values()) | ` (`homeassistant/core_config.py`), which on a + Home Assistant OS install is exactly `/config/www` and `/media` -- the + maintainer's own path. Nothing is invented here: an operator widens or + narrows what the designer can read with the same `configuration.yaml` + key that governs every other local-file feature. +* **Containment is re-checked AFTER `resolve()`**, so `..` segments are + collapsed and symlinks followed before the comparison -- a symlink + inside a permitted root pointing outside it is refused, even though its + pre-resolution path is textually contained. +* **`http(s)://` is refused outright.** The render path does fetch remote + sources server-side; that is a pre-existing property of the service and + is deliberately not widened into a designer-side fetch-anything surface. +* **Only files PIL can identify as images are served**, and the response + content type is PIL's own for the identified format. Media directories + hold more than images; without this the endpoint would be a file-read + oracle for everything under a permitted root. + +Net effect for a token-holding non-admin: they can read image files under +the directories Home Assistant already exposes, and nothing else -- no +arbitrary path, no non-image file, no network fetch, and no existence +oracle (everything refused for a path reason answers the same 404 as a +missing file). + +The consequence to be honest about: the renderer accepts absolute paths +this endpoint refuses, so an image outside the permitted roots renders on +send but shows the designer's explicit missing-asset state in preview. +That direction is the safe one, and it is documented in +`docs/designer.md`. +""" + +from __future__ import annotations + +from pathlib import Path + +from aiohttp import web +from homeassistant.components.http import HomeAssistantView +from homeassistant.core import HomeAssistant +from PIL import Image as PILImage + +from custom_components.opendisplay.services import _font_search_dirs + +DESIGNER_ASSET_URL = "/api/opendisplay/designer/asset" + +# `AssetKind` in the vendored `odl-drawcustom-designer.d.ts`, in full. +_ALLOWED_KINDS = ("font", "image") + +# Bounds one request's read into memory. A drawcustom image is destined for +# a panel measured in hundreds of pixels; 32 MiB is far above any real one +# and far below "an authenticated user can make Home Assistant read an +# arbitrarily large file into RAM on demand". A file over the cap is +# refused like any other unresolvable reference -- the renderer would still +# load it on send, same as it loads paths outside the permitted roots. +_MAX_IMAGE_BYTES = 32 * 1024 * 1024 + + +def _permitted_image_roots(hass: HomeAssistant) -> list[str]: + """Return the directories an image may be served from. + + Home Assistant's own allowlist, not a policy this integration invents -- + see the module docstring. + """ + return sorted(hass.config.allowlist_external_dirs) + + +def _resolve_image_path(permitted_roots: list[str], name: str) -> Path | None: + """Return `name` as a real file under one of `permitted_roots`, else None. + + `name` is the payload's own image reference, which for a local file is + an absolute path (`odl_renderer.media_loader.load_image`'s own rule: + HTTP(S) first, then `data:`, then a leading `/`). Anything else -- a + relative name, a `data:` URI, a URL -- has no local file behind it and + is not this function's business. + + Containment is checked after `resolve()` on BOTH sides: the candidate, + so `..` is collapsed and symlinks are followed before comparing, and + each root, so a permitted directory reached through a symlink (a + container bind-mount layout) still matches its own real files. + """ + if not name.startswith("/"): + return None + + try: + candidate = Path(name).resolve() + except OSError: + return None + + for root in permitted_roots: + try: + root_path = Path(root).resolve() + except OSError: + continue + try: + candidate.relative_to(root_path) + except ValueError: + continue + if candidate.is_file(): + return candidate + return None + return None + + +def _read_image_asset( + permitted_roots: list[str], name: str +) -> tuple[bytes, str] | None: + """Return (bytes, content type) for a permitted image file, else None. + + Identification is PIL's, not the file extension's: the endpoint serves + what the renderer could actually decode, and refuses everything else so + it cannot be used to read non-image files out of a media directory. + Runs in an executor -- every file operation here is blocking. + """ + path = _resolve_image_path(permitted_roots, name) + if path is None: + return None + + try: + if path.stat().st_size > _MAX_IMAGE_BYTES: + return None + with PILImage.open(path) as img: + image_format = img.format + except OSError: + return None + except Exception: + return None + + if not image_format: + return None + PILImage.init() # populate PILImage.MIME for every registered plugin + content_type = PILImage.MIME.get(image_format) + if content_type is None: + return None + + try: + return path.read_bytes(), content_type + except OSError: + return None + + +def _resolve_font_path(search_dirs: list[str], name: str) -> Path | None: + """Resolve `name` within `search_dirs`, guarded against path traversal. + + Mirrors `odl_renderer.fonts.FontManager`'s own name -> file resolution + (a bare name gets `.ttf` appended unless it already ends in `.ttf`/ + `.otf`) so a name the designer asks for resolves to the exact same file + the render/send pipeline would load for that same payload reference -- + never a different file behind the same name (issue #138's `(kind, name)` + contract). Guarded exactly like `OpenDisplayDesignerStaticView` + (`panel.py`'s `_resolve_static_path`): resolve the candidate, then + require it stay under the search directory it came from -- a `name` that + escapes via `../` is skipped (falls through to the next search dir, then + to a 404), never a 500 or a path outside the intended tree. + """ + font_name = name if name.endswith((".ttf", ".otf")) else f"{name}.ttf" + for directory in search_dirs: + root = Path(directory).resolve() + candidate = (root / font_name).resolve() + try: + candidate.relative_to(root) + except ValueError: + continue + if candidate.is_file(): + return candidate + return None + + +_CONTENT_TYPES = {".ttf": "font/ttf", ".otf": "font/otf"} + + +# Every refusal that is about a PATH answers the same 404 a genuinely +# missing file does -- "outside the permitted roots", "symlink escapes +# them", "not an image", "too large" and "no such file" are indistinguish- +# able to the caller, so the endpoint is not an existence oracle for the +# filesystem outside what it is willing to serve. +_NOT_FOUND = "Not found" + + +class OpenDisplayDesignerAssetView(HomeAssistantView): + """Resolve a font or image asset for the designer's `resolveAsset` seam.""" + + url = DESIGNER_ASSET_URL + name = "opendisplay:designer_asset" + requires_auth = True + + def __init__(self, hass: HomeAssistant) -> None: + """Initialize the view.""" + self.hass = hass + + async def get(self, request: web.Request) -> web.Response: + """Serve one font or image file by name, or 404/400.""" + kind = request.query.get("kind", "") + name = request.query.get("name", "") + if kind not in _ALLOWED_KINDS: + return web.json_response( + { + "message": f"unsupported kind: {kind!r} " + f"(resolvable: {', '.join(_ALLOWED_KINDS)})" + }, + status=400, + ) + if not name: + return web.Response(status=404, text=_NOT_FOUND) + + if kind == "image": + return await self._get_image(name) + + search_dirs = await self.hass.async_add_executor_job( + _font_search_dirs, self.hass + ) + font_path = await self.hass.async_add_executor_job( + _resolve_font_path, search_dirs, name + ) + if font_path is None: + return web.Response(status=404, text="Not found") + + try: + data = await self.hass.async_add_executor_job(font_path.read_bytes) + except OSError: + return web.Response(status=500, text="Error") + + content_type = _CONTENT_TYPES.get(font_path.suffix, "application/octet-stream") + # Keyed only by name (no cache-busting token like the static view's + # `?v=`) and font files in these directories can change without this + # integration knowing (a user replacing a font on disk) -- no-cache + # rather than immutable/long-cache, so a swapped file is picked up on + # the next request instead of serving stale bytes for up to a year. + # Justified since fonts aren't re-fetched on every render (the + # designer resolves and caches an asset once per session, per + # issue #138's own contract) -- the cost of skipping aggressive + # caching here is low. + return web.Response( + body=data, + content_type=content_type, + headers={"Cache-Control": "no-cache, must-revalidate"}, + ) + + async def _get_image(self, name: str) -> web.Response: + """Serve one image file by absolute path, from a permitted root.""" + if name.startswith(("http://", "https://")): + # Refused, not proxied -- see the module docstring. The render + # path's own server-side fetch of remote sources is a property + # of that service, not something this view extends to the + # browser. + return web.json_response( + {"message": "remote image sources are not resolved by this endpoint"}, + status=400, + ) + if not name.startswith("/"): + return web.json_response( + { + "message": "an image must be referenced by absolute path " + "(there is no bare-name image search path)" + }, + status=400, + ) + + roots = await self.hass.async_add_executor_job( + _permitted_image_roots, self.hass + ) + resolved = await self.hass.async_add_executor_job( + _read_image_asset, roots, name + ) + if resolved is None: + return web.Response(status=404, text=_NOT_FOUND) + + data, content_type = resolved + # Same reasoning as the font branch: keyed only by path, and the + # file behind it can change without this integration knowing. + return web.Response( + body=data, + content_type=content_type, + headers={"Cache-Control": "no-cache, must-revalidate"}, + ) diff --git a/custom_components/opendisplay/designer/capabilities.py b/custom_components/opendisplay/designer/capabilities.py new file mode 100644 index 00000000..c388c3c6 --- /dev/null +++ b/custom_components/opendisplay/designer/capabilities.py @@ -0,0 +1,80 @@ +"""Build designer-facing device capability payloads from runtime config.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +from epaper_dithering import ColorPalette, ColorScheme +from homeassistant.core import HomeAssistant +from homeassistant.helpers import device_registry as dr +from homeassistant.helpers.device_registry import CONNECTION_BLUETOOTH + +from opendisplay import Rotation +from opendisplay.display_palettes import get_palette_for_display + +if TYPE_CHECKING: + from custom_components.opendisplay import OpenDisplayConfigEntry + + +def resolve_device_id_for_entry( + hass: HomeAssistant, entry: OpenDisplayConfigEntry +) -> str | None: + """Resolve HA device registry id for a config entry.""" + device_registry = dr.async_get(hass) + devices = dr.async_entries_for_config_entry(device_registry, entry.entry_id) + if devices: + return devices[0].id + + mac = entry.unique_id + if not mac: + return None + for variant in {mac, mac.upper(), mac.lower()}: + device = device_registry.async_get_device( + connections={(CONNECTION_BLUETOOTH, variant)} + ) + if device is not None: + return device.id + return None + + +def build_capabilities( + entry: OpenDisplayConfigEntry, + device_id: str, + *, + user_rotate_deg: int = 0, +) -> dict[str, Any]: + """Serialize display capabilities for the designer mount API.""" + display = entry.runtime_data.device_config.displays[0] + cs = display.color_scheme_enum + scheme = cs if isinstance(cs, ColorScheme) else ColorScheme.from_value(int(cs)) + palette = get_palette_for_display(display.panel_ic_type, scheme) + colors = ( + palette.colors if isinstance(palette, ColorPalette) else palette.palette.colors + ) + color_map: dict[str, str] = {} + for name, rgb in colors.items(): + if isinstance(rgb, (tuple, list)) and len(rgb) >= 3: + r, g, b = int(rgb[0]), int(rgb[1]), int(rgb[2]) + color_map[str(name)] = f"#{r:02x}{g:02x}{b:02x}" + + rotation = display.rotation_enum + base = int(rotation.value if isinstance(rotation, Rotation) else rotation) % 360 + effective = (base + user_rotate_deg) % 360 + pw, ph = int(display.pixel_width), int(display.pixel_height) + render_w, render_h = (ph, pw) if effective in (90, 270) else (pw, ph) + accent = ( + palette.accent if isinstance(palette, ColorPalette) else scheme.accent_color + ) + return { + "device_id": device_id, + "pixel_width": pw, + "pixel_height": ph, + "rotation_degrees": base, + "render_width": render_w, + "render_height": render_h, + "color_scheme": int(scheme.value), + "accent_color": str(accent), + "available_colors": list(color_map), + "color_map": color_map, + "palette_measured": isinstance(palette, ColorPalette), + } diff --git a/custom_components/opendisplay/designer/frontend/panel/asset-request.js b/custom_components/opendisplay/designer/frontend/panel/asset-request.js new file mode 100644 index 00000000..ecd507aa --- /dev/null +++ b/custom_components/opendisplay/designer/frontend/panel/asset-request.js @@ -0,0 +1,42 @@ +/** + * The `resolveAsset` request the panel makes on the designer's behalf. + * + * Extracted from the panel wrapper for the same reason `rotation.js` and + * `drawcustom-request.js` were: the decision is pure, it is worth unit + * testing (`tests/js/asset-request.test.mjs`), and the panel class itself + * imports the vendored designer bundle and cannot be loaded under + * `node --test`. + * + * WHAT THIS FIXES (tier-2 round 3, real hardware): the panel used to + * short-circuit every `kind !== 'font'` to `null` without calling the + * endpoint at all, because the endpoint served fonts only. A display's + * payload referencing `/media/pohl89-480h.png` therefore rendered fine on + * the server and showed the designer's own missing-asset state in the + * preview. The endpoint now resolves images too (`designer/asset.py`), so + * the short-circuit is gone and both `AssetKind` values are requested. + * + * Note the asymmetry, which is deliberate and lives server-side: fonts are + * resolved by BARE NAME against this integration's font directories, images + * by ABSOLUTE PATH within Home Assistant's own permitted roots. This module + * does not know or care -- the host contract is `name -> asset`, and the + * name is passed through exactly as the designer supplied it. + */ + +export const ASSET_URL = '/api/opendisplay/designer/asset'; + +/** `AssetKind` (vendored `odl-drawcustom-designer.d.ts`), in full. */ +export const RESOLVABLE_ASSET_KINDS = Object.freeze(['font', 'image']); + +/** + * Return the asset-endpoint URL for one `(kind, name)` reference, or `null` + * when there is nothing worth asking for. + * + * @param {string|undefined} kind An `AssetKind`. + * @param {string|undefined} name The designer's own reference, verbatim. + * @returns {string|null} The URL to fetch, or null to answer "not supplied" + * without a round trip. + */ +export function assetRequestUrl(kind, name) { + if (!RESOLVABLE_ASSET_KINDS.includes(kind) || !name) return null; + return `${ASSET_URL}?kind=${encodeURIComponent(kind)}&name=${encodeURIComponent(name)}`; +} diff --git a/custom_components/opendisplay/designer/frontend/panel/drawcustom-request.js b/custom_components/opendisplay/designer/frontend/panel/drawcustom-request.js new file mode 100644 index 00000000..e22cdb19 --- /dev/null +++ b/custom_components/opendisplay/designer/frontend/panel/drawcustom-request.js @@ -0,0 +1,111 @@ +/** + * The two drawcustom-shaped requests this panel builds — the render + * endpoint's preview body and the `opendisplay.drawcustom` service call — + * derived from ONE source: the designer context handed to the callback that + * is asking. + * + * Since designer 3.0.0 (issue #105, the WYSIWYG-send slice) `onAction`'s + * `HostActionContext` carries the same live `display` geometry + * (`HostDisplayGeometry`) and `render` options (`HostRenderOptions`) that + * `renderPreview`'s `HostPreviewContext` always carried, both read at the + * instant the callback fires. That is what lets Send read the designer's + * CURRENT orientation and dither controls directly. Before it, a host + * reaching for WYSIWYG send had no choice but to remember the last preview + * request's values — sticky, invisible, and wrong the moment a control moved + * with preview off or unused. Those remembered fields are gone; nothing in + * this panel stores a dither or a rotate between callbacks any more. + * + * Both builders live here, together, so preview and send provably derive the + * same `dither`/`rotate` from the same context rather than two lookalike + * expressions that can drift (`tests/js/drawcustom-request.test.mjs` pins + * exactly that). + */ +import { rotateDeltaFor } from './rotation.js'; + +/** + * Designer's own numeric dither domain (`HostRenderOptions.dither`: 0 flat/ + * none, 1 reserved, 2 ordered halftone — the vendored `.d.ts`: "the + * designer's preview control produces 0 or 2 today") mapped onto the + * drawcustom service's string `dither` options (services.yaml). + * Deliberately a string lookup, not the raw int: the service's `dither` + * field also accepts an int matching the DitherMode enum's own value order + * (see `_dither_value` in services.py), but that ordering isn't published + * anywhere this panel can read — forwarding the designer's int blind would + * gamble on an enum layout instead of the documented string vocabulary. `1` + * is currently unreachable from the designer's own dither control; mapped + * conservatively to 'ordered' pending upstream clarification (see the PR + * body's open questions). + */ +const DITHER_TO_HA_STRING = { 0: 'none', 1: 'ordered', 2: 'ordered' }; + +/** `HostRenderOptions.dither` -> the drawcustom service's own string vocabulary. */ +export function ditherToHaString(dither) { + return DITHER_TO_HA_STRING[dither] ?? 'ordered'; +} + +/** + * Body for `POST /api/opendisplay/designer/render` (`renderPreview`). + * + * Virtual display (tier-1 round 2, finding 2): `context.targetId` is + * undefined/null for the designer's built-in "Virtual display" pick — there + * is no HA device to send a `device_id` for at all. `context.display` + * (width/height, already the oriented logical drawing surface — see + * `HostDisplayGeometry`'s own doc comment in the vendored `.d.ts`) is ALWAYS + * present regardless of `targetId`, so that geometry alone is enough for the + * endpoint's spec mode; `rotate` is always 0 there because `context.display` + * is already the final oriented surface, with no separate device base + * rotation to recover a delta against. + * + * @param {object[]} elements Parsed drawcustom payload. + * @param {{rotationDegrees?: number}|undefined} displaySpec The selected + * target's own pushed `HostDisplaySpec`, or undefined for Virtual. + * @param {{targetId?: string, display: {width: number, height: number, rotation: number}, render: {dither: number}}} context + */ +export function renderRequestBody(elements, displaySpec, context) { + const common = { + payload: elements, + background: 'white', + dither: ditherToHaString(context.render.dither), + }; + if (!context.targetId) { + return { + display: { width: context.display.width, height: context.display.height }, + ...common, + rotate: 0, + }; + } + return { + device_id: context.targetId, + ...common, + rotate: rotateDeltaFor(displaySpec, context.display.rotation), + }; +} + +/** + * Service data for `opendisplay.drawcustom` (the `send` host action). + * + * `background`/`refresh_type` are still hardcoded (designer issue #105 will + * expose the rest of the option set later); `dither` and `rotate` are read + * LIVE off the action context, so what Send ships is what the designer's own + * controls show at the moment of the click — no preview required, nothing + * remembered from one. + * + * @param {object[]} elements Parsed drawcustom payload. + * @param {{rotationDegrees?: number}|undefined} displaySpec The selected + * target's own pushed `HostDisplaySpec`. + * @param {{targetId?: string, display: {rotation: number}, render: {dither: number}}} context + */ +export function sendCallData(elements, displaySpec, context) { + return { + // device_id here is the service's own required field (services.yaml's + // `device_id` selector) -- not a duplicate of HA's separate service-call + // "target" (which attributes the call to a device in the logbook/trace + // UI, independent of what the service schema itself requires). + device_id: [context.targetId], + payload: elements, + background: 'white', + dither: ditherToHaString(context.render.dither), + rotate: rotateDeltaFor(displaySpec, context.display.rotation), + refresh_type: 'full', + }; +} diff --git a/custom_components/opendisplay/designer/frontend/panel/key-containment.js b/custom_components/opendisplay/designer/frontend/panel/key-containment.js new file mode 100644 index 00000000..9641be30 --- /dev/null +++ b/custom_components/opendisplay/designer/frontend/panel/key-containment.js @@ -0,0 +1,191 @@ +/** + * Keyboard containment (tier-1 round 2, CRITICAL; narrowed from a blanket + * version in a follow-up fix round -- see "Residual tradeoff" below). + * Without this, typing in the designer's YAML editor is largely unusable + * inside the real HA panel -- most keystrokes did nothing, and single + * letters like e/d/c popped HA's own global quick-bar (entity/device/ + * command search) OVER the editor. + * + * Root cause, verified directly against the installed homeassistant-frontend + * package (home-assistant-frontend==20260826.1, matching this venv's pinned + * hass_frontend build -- confirmed via that bundle's own source map, which + * names the exact upstream files below at that exact tag; re-verified + * against 20260729.7, the version installed earlier in the same review + * round, after `uv run`'s own floating resolution drifted the venv forward + * mid-session -- `can-override-input.ts` and `shortcuts.ts` are BYTE- + * IDENTICAL between the two releases; `quick-bar-mixin.ts` only gained + * unrelated TypeScript event-cast typing, not a behavior change, so this + * mechanism is stable across at least those two recent releases, not a + * one-version fluke): + * + * - HA registers its e/c/d/m/a/? shortcuts globally on `window`, in the + * BUBBLE phase, via tinykeys (`src/common/keyboard/shortcuts.ts` + * `registerShortcuts()`, `tinykeys(window, wrappedShortcuts)`, line 46; + * wired up from `src/state/quick-bar-mixin.ts`'s `_registerShortcut()`, + * lines 104-139). A composed, bubbling `keydown` (which is what real + * typing dispatches) reaches this listener regardless of how deep in the + * DOM -- or how many shadow roots -- it started in; shadow-root + * retargeting does NOT protect us here, because... + * - ...the "is the user typing in an editable field" gate, + * `canOverrideAlphanumericInput` (`src/common/dom/can-override-input.ts`, + * the whole file, 36 lines), does not check `Element.isContentEditable` + * at all. It only recognizes a fixed tag-name allowlist: + * `TEXTAREA`/`INPUT` (non-button-like) directly, plus `HA-MENU`/ + * `HA-CODE-EDITOR` anywhere in `composedPath()` (HA special-cased its + * OWN CodeMirror wrapper by tag name rather than checking + * `isContentEditable` generically). The vendored designer's own + * CodeMirror 6 instance renders a plain `contenteditable` div with none + * of those tag names -- so `canOverrideAlphanumericInput` returns `true` + * (shortcuts allowed) even while the cursor is inside our editor, e/c/d + * fire `_showQuickBar()`/`preventDefault()` and steal focus into HA's + * own dialog, and every subsequent keystroke goes into THAT dialog + * instead of back into the designer (matching "most keystrokes don't + * type at all" -- not a separate bug, a consequence of focus having + * already been stolen by the first e/c/d/m/a keystroke). + * + * SELECTIVE, not blanket (fixed in a follow-up round -- a first version + * stopped propagation for every key event unconditionally, which also + * silently killed the vendored designer's OWN window-level keyboard + * shortcuts: undo/redo and Escape/Delete/Backspace/Arrow-nudge are + * registered by the designer itself on `window`, not inside the shadow + * root (`src/ui/lib/canvas-keyboard.ts`'s window keydown listener, and + * `src/ui/lib/undo-keyboard.ts`'s `Z$t`/`Q$t` undo/redo predicates -- + * verified directly against the vendored bundle: search it for + * `canvas-keyboard.ts`/`undo-keyboard.ts` to find the exact minified + * call sites). A blanket stop broke every one of them whenever the event + * happened to pass through this panel's own host element first -- which, + * being the panel's own DOM ancestor, is always). Two conditions, + * mirroring the designer's OWN editable-target guard (`X$t` in + * `canvas-keyboard.ts`, reused here as `isEditableTarget` below -- same + * `.cm-editor`/`INPUT`/`TEXTAREA`/`SELECT`/`isContentEditable` checks, so + * "should this reach the designer's own canvas shortcuts" and "should + * this reach HA's quick-bar" agree on what counts as "the user is + * editing text"): + * + * (a) the event's target is editable (mirrors the designer's own guard) -- + * contained regardless of which key, so ordinary typing (including + * Backspace/Delete/Escape/Arrows used for text editing, and ctrl+z + * used for CodeMirror's own text-undo) never also reaches the + * designer's window-level canvas handler OR HA's window-level + * shortcuts. This matches the designer's own intent: `X$t` returns + * `false` for an editable target specifically so the canvas handler + * bails out before ever checking undo/redo/delete/arrows -- the + * designer itself does not want its OWN shortcuts firing during a + * text edit either. + * (b) the event is an UNMODIFIED alphanumeric key (no ctrl/meta/alt -- + * Shift is not treated as a modifier here, so Shift+letter is still + * contained too; see "Residual tradeoff" below), regardless of + * target -- the designer binds no bare letters/digits anywhere + * (`canvas-keyboard.ts`'s switch only handles Escape/Delete/ + * Backspace/Arrow* by key name; `Z$t`/`Q$t` both require ctrl/meta), + * so nothing of the designer's own breaks, and this is what keeps + * a bare 'e'/'c'/'d' from opening HA's quick-bar even when the + * CANVAS (not the YAML editor) has focus -- (a) alone would not + * catch that case, since the canvas is not an editable target. + * + * Everything else -- Delete, Backspace, Escape, Arrow keys, and every + * ctrl/meta combo (including undo/redo) -- propagates all the way to + * `window` from a non-editable (canvas) target, exactly as before this + * fix existed: the designer's own window listener sees them and its + * undo/redo/delete-element/nudge/deselect all work. + * + * Residual tradeoff, disclosed rather than left implicit: bare-letter HA + * shortcuts (e/c/d/m/a) are suppressed PANEL-WIDE by design (condition (b) + * has no target check) -- not just while text-editing, also while the + * canvas or any other part of the panel has focus. This is deliberate + * (the designer has no bare-letter shortcuts of its own to protect, and + * suppressing HA's quick-bar only while literally inside the CodeMirror + * editor would leave it popping up over the canvas mid-design). If HA + * ever adds a global CTRL/META-modified shortcut the designer also needs + * (today it doesn't: only ctrl/meta+z and ctrl+y/ctrl+shift+z), this file + * would need a third, narrower condition -- revisit then, don't + * pre-emptively guess at one now. Known, same-shape gap in the other + * direction: `?` and other non-alphanumeric printable keys (condition (b) + * only matches `[a-zA-Z0-9]`) still reach `window` from a non-editable + * (canvas) target, so HA's own `?` shortcuts-dialog CAN pop over the + * designer while the canvas -- not the editor -- has focus. Deliberate, + * not an oversight: the designer binds no `?` of its own either, so + * nothing of its own is at risk; add a third condition here if this ever + * actually annoys someone, rather than widening (b) pre-emptively for a + * case nobody's hit yet. + * + * NEVER preventDefault: that would break the browser's own native text + * editing (and the designer's own default-prevented handling for the keys + * it does bind). HA's global shortcuts going quiet while focus is inside + * the designer, or while a bare letter is pressed anywhere in the panel, + * is intentional and acceptable (maintainer ruling) -- the designer owns + * its own surface. + * + * Kept in its own module (imported by the panel wrapper) so it can be unit + * tested with plain `node --test`, without executing the vendored designer + * bundle (which assumes a real browser) just to import one function. + */ + +/** + * Mirrors the designer's own `X$t` (`src/ui/lib/canvas-keyboard.ts`, + * compiled into the vendored bundle): is the event's real origin (the + * innermost node in `composedPath()`, not the possibly-retargeted + * `event.target`) an element a user could reasonably be typing text into. + * + * Duck-typed (`typeof target.closest === 'function'`) rather than `target + * instanceof HTMLElement`, which is what `X$t` itself checks -- deliberate: + * this file has no DOM to `instanceof` against under plain `node --test` + * (no jsdom, no npm package manager in this repo at all), and every real + * target this check ever sees (CodeMirror's own contenteditable div, a + * real `INPUT`/`TEXTAREA`/`SELECT`) is a genuine `HTMLElement` with a real + * `.closest` either way -- the two checks agree for everything this + * function is actually asked about. + * + * @param {Event} event + * @returns {boolean} + */ +function isEditableTarget(event) { + const path = typeof event.composedPath === 'function' ? event.composedPath() : []; + const target = path[0] ?? event.target; + if (!target || typeof target.closest !== 'function') return false; + return !!( + target.closest('.cm-editor') || + target.tagName === 'INPUT' || + target.tagName === 'TEXTAREA' || + target.tagName === 'SELECT' || + target.isContentEditable + ); +} + +/** + * A bare letter/digit key with no ctrl/meta/alt modifier -- the shape of + * every HA quick-bar single-key shortcut (e/c/d/m/a), and of nothing the + * designer itself binds. Shift is deliberately NOT treated as a modifier + * here (see this module's own "Residual tradeoff" doc comment) -- errs + * toward containing more, not less, since the designer has no Shift+letter + * bindings to protect either. + * + * @param {KeyboardEvent} event + * @returns {boolean} + */ +function isUnmodifiedAlphanumeric(event) { + if (event.ctrlKey || event.metaKey || event.altKey) return false; + return typeof event.key === 'string' && event.key.length === 1 && /[a-zA-Z0-9]/.test(event.key); +} + +/** + * @param {EventTarget} host - the panel custom element (`this` from + * connectedCallback), i.e. the shadow root's host. + * @returns {() => void} disposer -- call from disconnectedCallback. + */ +export function containKeyEvents(host) { + const stop = (event) => { + if (isEditableTarget(event) || isUnmodifiedAlphanumeric(event)) { + event.stopPropagation(); + } + }; + const types = ['keydown', 'keyup', 'keypress']; + for (const type of types) { + host.addEventListener(type, stop); + } + return () => { + for (const type of types) { + host.removeEventListener(type, stop); + } + }; +} diff --git a/custom_components/opendisplay/designer/frontend/panel/opendisplay-designer-panel.js b/custom_components/opendisplay/designer/frontend/panel/opendisplay-designer-panel.js new file mode 100644 index 00000000..b332c832 --- /dev/null +++ b/custom_components/opendisplay/designer/frontend/panel/opendisplay-designer-panel.js @@ -0,0 +1,599 @@ +/** + * HA panel host for vendored odl-drawcustom-designer 3.x + * (mount + drawcustom send via the designer's targets/actions/preview seams). + * + * The designer owns ALL chrome now (ADR-018 upstream): no host toolbar, no + * device picker built here, no Copy YAML button, no Save button — those are + * the designer's `targets` picker, built-in Copy YAML, and the `send` host + * action registered below. This file only supplies data in and reacts to + * callbacks out; see ../vendor/README.md for the vendoring procedure and + * https://github.com/schlomo/odl-drawcustom-designer/blob/main/docs/embedding.md + * for the full host contract this panel implements. + * + * Preview isolation (maintainer ruling 2026-08-30): `renderPreview` POSTs to + * this integration's own /api/opendisplay/designer/render endpoint, which + * renders through the exact same generate_image + prepare_image pipeline a + * real send uses but never touches the image entity, never dispatches + * SIGNAL_IMAGE_UPDATED, and never delivers to the device — designer play can + * never show up on a live display's own dashboard. This replaces an earlier + * draft's dry-run/poll/cache-bust approach entirely; there is no dry-run + * involved here at all. + */ +import { mount } from '../vendor/odl-drawcustom-designer.js'; +import yaml from '../vendor/js-yaml.mjs'; +import { containKeyEvents } from './key-containment.js'; +import { installUnsavedWorkWarning } from './unsaved-work.js'; +import { renderRequestBody, sendCallData } from './drawcustom-request.js'; +import { assetRequestUrl } from './asset-request.js'; + +const TAG = 'opendisplay-designer-panel'; +const RENDER_URL = '/api/opendisplay/designer/render'; + +const CSS = ` +:host{display:block!important;position:absolute;inset:0;width:100%;height:100%;max-width:none;overflow:hidden;box-sizing:border-box;font-family:var(--ha-font-family-body,system-ui,sans-serif);color:var(--primary-text-color,#1c1917);background:var(--primary-background-color,#fafaf9)} +.od-host{display:flex;flex-direction:column;width:100%;height:100%;min-height:0;min-width:0;overflow:hidden;box-sizing:border-box} +.od-mount{flex:1 1 0;min-height:0;min-width:0;width:100%;overflow:hidden;position:relative} +.od-mount>*{width:100%!important;height:100%!important;max-width:none!important;box-sizing:border-box} +.od-error{padding:16px;color:var(--error-color,#db4437);background:var(--error-state-color,rgba(219,68,55,0.1));border-bottom:1px solid var(--error-color,#db4437)} +.od-error[hidden]{display:none} +`; + +function errMsg(err) { + if (!err || typeof err !== 'object') return String(err); + const message = Reflect.get(err, 'message'); + const body = Reflect.get(err, 'body'); + const bodyStr = + body && typeof body === 'object' && Reflect.get(body, 'message') + ? String(Reflect.get(body, 'message')) + : ''; + return [typeof message === 'string' ? message : '', bodyStr].filter(Boolean).join(' — ') || 'Error'; +} + +/** Every HA device backed by the opendisplay platform (host devices, not the designer's own "Virtual display" — that stays the designer's built-in picker entry). */ +function listOpenDisplayDevices(hass) { + const devices = hass?.devices; + if (!devices || typeof devices !== 'object') return []; + const out = []; + for (const [id, d] of Object.entries(devices)) { + if (!d || typeof d !== 'object') continue; + const hit = + !!hass?.entities && + Object.values(hass.entities).some( + (e) => e && e.device_id === id && e.platform === 'opendisplay' + ); + if (!hit) continue; + const name = String(d.name_by_user || d.name || d.original_name || id).trim(); + out.push({ id, name }); + } + out.sort((a, b) => a.name.localeCompare(b.name)); + return out; +} + +function imageEntity(hass, deviceId) { + const reg = hass?.entities; + if (!reg) return null; + const imgs = []; + for (const [key, ent] of Object.entries(reg)) { + if (!ent || ent.device_id !== deviceId) continue; + const eid = String(ent.entity_id || key); + if (eid.startsWith('image.')) imgs.push(eid); + } + return ( + imgs.find((eid) => Number(hass.states?.[eid]?.attributes?.pixel_width) > 0) || + imgs[0] || + null + ); +} + +/** + * Translate one image entity's HA attributes into the designer's + * `HostDisplaySpec` (vendored `.d.ts`). + * + * THIS IS THE TRANSLATION LAYER, and the only one. HA entity attributes are + * snake_case because that is HA's own convention, and `capabilities.py` + * keeps emitting them that way; `HostDisplaySpec`'s keys are camelCase + * because that is the designer's published contract (3.0.0 made it the last + * published interface to stop being an exception). The two vocabularies meet + * here and nowhere else — do not "align" either side to the other. + */ +function displaySpecFromAttrs(attrs) { + const pw = Number(attrs.pixel_width) || 296; + const ph = Number(attrs.pixel_height) || 128; + let colorScheme = attrs.color_scheme; + if (typeof colorScheme !== 'number' || Number.isNaN(colorScheme)) colorScheme = 0x01; + return { + pixelWidth: pw, + pixelHeight: ph, + // KNOWN GAP (PR body's open questions): capabilities.py publishes the + // BASE rotation while render_width/render_height are already swapped + // for the EFFECTIVE (base + user_rotate) orientation. The contract + // requires rotationDegrees to describe the orientation render* is + // already in — pass the attribute through as-is; do not silently "fix" + // it here. + rotationDegrees: Number(attrs.rotation_degrees) || 0, + renderWidth: Number(attrs.render_width) || pw, + renderHeight: Number(attrs.render_height) || ph, + colorScheme, + accentColor: String(attrs.accent_color || 'red'), + availableColors: Array.isArray(attrs.available_colors) + ? attrs.available_colors.map(String) + : ['black', 'white', 'red'], + colorMap: + attrs.color_map && typeof attrs.color_map === 'object' + ? attrs.color_map + : { black: '#000000', white: '#ffffff', red: '#c53929' }, + paletteMeasured: Boolean(attrs.palette_measured), + }; +} + +/** Every real OpenDisplay device with published display attributes, as designer `targets`. */ +function buildTargets(hass) { + const targets = []; + for (const d of listOpenDisplayDevices(hass)) { + const eid = imageEntity(hass, d.id); + const attrs = eid ? hass?.states?.[eid]?.attributes : null; + if (!attrs || typeof attrs !== 'object') continue; // capability attrs not published yet + // Gate on a REAL capability key, not just "an attributes dict exists" — + // real HA always gives an image entity an attributes dict (possibly + // `{}`), and image_entity.py itself returns `{}` on a capability-build + // exception. Without this check, a device whose capabilities failed to + // build (or haven't been written yet) becomes a fabricated 296x128 BWR + // target and — because it may be the only device — auto-adopts and + // locks the canvas to a size/palette that isn't real. `pixel_width` is + // the cheapest reliable "capabilities actually published" signal + // (capabilities.py always sets it > 0); the 250ms re-push adds the + // device once real attributes land. + if (!(Number(attrs.pixel_width) > 0)) continue; + targets.push({ id: d.id, label: d.name, display: displaySpecFromAttrs(attrs) }); + } + return targets; +} + +/** Host state catalog (docs/embedding.md `states`) — friendly names from `attributes.friendly_name`. */ +function collectStates(hass) { + const out = {}; + const states = hass?.states; + if (!states) return out; + for (const [eid, st] of Object.entries(states)) { + if (!st || typeof st !== 'object') continue; + const attributes = + st.attributes && typeof st.attributes === 'object' ? { ...st.attributes } : undefined; + const name = + typeof attributes?.friendly_name === 'string' ? attributes.friendly_name.trim() : ''; + out[eid] = { + state: String(st.state ?? ''), + ...(attributes ? { attributes } : {}), + ...(name ? { name } : {}), + }; + } + return out; +} + +function parsePayload(text) { + // YAML 1.2 CORE_SCHEMA keeps key `y` (1.1 would booleanize it). + const doc = yaml.load(String(text || '').trim() || '[]', { schema: yaml.CORE_SCHEMA }); + if (!Array.isArray(doc)) throw new Error('Payload must be a YAML list'); + return doc; +} + +function theme(hass) { + // hass.themes.darkMode is HA's OWN already-resolved effective choice + // (explicit user pick, or its own system-preference fallback when the + // user picked "auto") -- trust it whenever it's a real boolean. Falling + // through to matchMedia() unconditionally on `false` (the previous `||` + // form) would override an explicit LIGHT theme pick with dark whenever + // the OS itself prefers dark, which is backwards: matchMedia is only a + // fallback for the (should not happen) case HA hasn't resolved it at all. + const dm = hass?.themes?.darkMode; + if (typeof dm === 'boolean') return dm ? 'dark' : 'light'; + const dark = typeof matchMedia === 'function' && matchMedia('(prefers-color-scheme: dark)').matches; + return dark ? 'dark' : 'light'; +} + +class OpenDisplayDesignerPanel extends HTMLElement { + constructor() { + super(); + this._hass = null; + this._resetMountState(); + } + + /** + * Everything that describes ONE mount's state, as opposed to the custom + * element's own lifetime (which can outlive several mounts — HA reuses + * the element across a navigate-away-and-back, and disconnectedCallback + * destroys the designer handle without the browser ever discarding this + * object). Called from the constructor and again from + * disconnectedCallback, so a fresh mount always starts clean instead of + * carrying over the previous mount's selection/sending/YAML-validity + * state (a stale `_selectedTargetId` surviving a remount could show Send + * enabled before the fresh designer instance has a selection at all). + */ + _resetMountState() { + this._handle = null; + this._pushTimer = null; + this._pushDebounceStartedAt = 0; + this._selectedTargetId = null; + this._yamlValid = true; + this._yamlErrorSummary = undefined; + // In-flight guard (send): prevents a multi-click Send from firing + // several drawcustom calls at physical hardware. + this._sending = false; + // Stale-selection tracking: the most recent non-null target id the + // designer reported, and the target ids we most recently pushed — + // together these tell `onTargetSelected(null)` apart from a genuine + // "no display chosen yet" (never had a selection, or the user picked + // Virtual display while their device is still available) versus a + // previously-selected display that dropped out of our own targets list + // (the designer's "keep and mark stale" case, docs/embedding.md). + this._lastSelectedTargetId = null; + this._lastTargetIds = new Set(); + // Every currently-pushed target's own HostDisplaySpec, by id -- so both + // _renderPreview and _send can recover the selected target's BASE + // rotation (display.rotationDegrees) to compare against the designer's + // live, possibly user-rotated canvas orientation (context.display). + this._targetDisplaySpecs = new Map(); + this._staleSelection = false; + } + + set hass(value) { + this._hass = value; + if (!this.isConnected) return; + // Debounce with a max-wait (like the designer's own status-change + // debounce, docs/embedding.md HostStatusChangeHandler): a busy HA + // instance can push hass updates faster than every 250ms indefinitely, + // which would otherwise reset this timer forever and starve + // _pushHostData() completely. Cap the total wait since the FIRST + // pending update in a burst at 1s, same cadence the designer itself + // uses for status delivery. + const now = Date.now(); + if (this._pushTimer == null) this._pushDebounceStartedAt = now; + clearTimeout(this._pushTimer); + const elapsedSinceFirstPending = now - this._pushDebounceStartedAt; + const delay = Math.min(250, Math.max(0, 1000 - elapsedSinceFirstPending)); + this._pushTimer = setTimeout(() => { + this._pushTimer = null; + this._pushHostData(); + }, delay); + } + + get hass() { + return this._hass; + } + + connectedCallback() { + if (!this.shadowRoot) this.attachShadow({ mode: 'open' }); + Object.assign(this.style, { + display: 'block', + position: 'absolute', + inset: '0', + width: '100%', + height: '100%', + maxWidth: 'none', + overflow: 'hidden', + boxSizing: 'border-box', + }); + if (this.parentElement) { + const p = this.parentElement; + this._parentStylePatch = { + position: p.style.position && p.style.position !== 'static' ? null : p.style.position, + height: p.style.height || null, + }; + if (this._parentStylePatch.position !== null) p.style.position = 'relative'; + if (this._parentStylePatch.height === null) p.style.height = '100%'; + } + this._renderShell(); + this._mount(); + // See containKeyEvents' own doc comment for the full root-cause writeup + // (tier-1 round 2, CRITICAL) -- registered on `this`, the shadow root's + // host, so it runs after the shadow root's own listeners (CodeMirror's + // included) and before the event would otherwise keep bubbling out to + // HA's window-level quick-bar shortcuts. + this._uncontainKeyEvents = containKeyEvents(this); + // See unsaved-work.js's own doc comment for the full writeup, including + // the honest limit (tier-1 round 2, finding 6, INTERIM until + // designer#167 -- REAL PAGE UNLOAD ONLY, not HA's own in-app sidebar + // navigation, verify with an actual reload/close, not a sidebar + // click). `() => this._handle` (not `this._handle` itself) because the + // handle can be reassigned across a remount after this listener is + // registered. + this._uninstallUnsavedWorkWarning = installUnsavedWorkWarning(window, () => this._handle); + } + + disconnectedCallback() { + clearTimeout(this._pushTimer); + if (this.parentElement && this._parentStylePatch) { + const p = this.parentElement; + if (this._parentStylePatch.position !== null) p.style.position = this._parentStylePatch.position; + if (this._parentStylePatch.height === null) p.style.height = ''; + } + this._parentStylePatch = null; + this._handle?.destroy(); + this._uncontainKeyEvents?.(); + this._uncontainKeyEvents = null; + this._uninstallUnsavedWorkWarning?.(); + this._uninstallUnsavedWorkWarning = null; + this._resetMountState(); + } + + _$(id) { + return this.shadowRoot?.getElementById(id); + } + + _renderShell() { + const root = this.shadowRoot; + if (!root || root.querySelector('.od-host')) return; + root.innerHTML = ` + +
+ +
+
`; + } + + /** A mount failure leaves #od-mount empty forever otherwise -- the toast + * notification fades, and a blank panel with no chrome at all gives the + * user nothing to act on. */ + _showMountError(message) { + const el = this._$('od-error'); + if (!el) return; + el.textContent = `Failed to load the OpenDisplay Designer: ${message}`; + el.hidden = false; + } + + _notify(message) { + this.dispatchEvent( + new CustomEvent('hass-notification', { detail: { message }, bubbles: true, composed: true }) + ); + } + + _actionsList() { + const disabledReason = this._sending + ? 'Sending…' + : !this._yamlValid + ? this._yamlErrorSummary + ? `Fix the YAML errors to send: ${this._yamlErrorSummary}` + : 'Fix the YAML errors to send' + : !this._selectedTargetId + ? this._staleSelection + ? 'Display no longer available' // wording aligned with the designer's own stale-target hint (docs/embedding.md "keep and mark stale") + : 'No display selected' + : undefined; + return [ + { id: 'send', label: 'Send to display', icon: 'send', severity: 'caution', disabledReason }, + ]; + } + + _updateTargetsTracking(targets) { + this._lastTargetIds = new Set(targets.map((t) => t.id)); + this._targetDisplaySpecs = new Map(targets.map((t) => [t.id, t.display])); + } + + _pushActions() { + try { + this._handle?.setActions(this._actionsList()); + } catch (err) { + console.error('opendisplay-designer-panel: setActions failed', err); + } + } + + _mount() { + if (this._handle) return; + const mountEl = this._$('od-mount'); + if (!mountEl) return; + try { + const initialTargets = buildTargets(this._hass); + this._updateTargetsTracking(initialTargets); + this._handle = mount(mountEl, { + payload: '[]\n', + states: collectStates(this._hass), + theme: theme(this._hass), + targets: initialTargets, + onTargetSelected: (targetId) => { + this._selectedTargetId = targetId; + if (targetId) { + this._lastSelectedTargetId = targetId; + this._staleSelection = false; + } else { + // Stale iff we previously had a selection and it has since + // dropped out of the targets we last pushed — not just "there + // is no selection right now" (also true right after mount, or + // after a deliberate Virtual-display pick). + this._staleSelection = Boolean( + this._lastSelectedTargetId && !this._lastTargetIds.has(this._lastSelectedTargetId) + ); + } + this._pushActions(); + }, + actions: this._actionsList(), + onAction: (id, payload, context) => { + if (id === 'send') void this._send(payload, context); + }, + renderPreview: (payload, context) => this._renderPreview(payload, context), + resolveAsset: (kind, name) => this._resolveAsset(kind, name), + // Designer-local uploads land in this ONE browser's IndexedDB and + // never reach Home Assistant -- an uploaded asset renders on the + // canvas here and then fails the moment the design is sent, because + // send/render load assets from this integration's own directories + // (`designer/asset.py`), not from this browser's storage. `true` + // alone would remove the upload affordances silently; the `hint` + // instead points at the directories `resolveAsset` above can + // actually serve from, so the Content tab's read-only explorer says + // where a file needs to live instead of just "you can't upload + // here" (docs/embedding.md `hostOwnsAssets`). + hostOwnsAssets: { + hint: 'Add images anywhere under /config/www or /media, and fonts in a fonts subfolder there (e.g. /media/fonts).', + }, + onStatusChange: (status) => { + this._yamlValid = status.yamlValid; + this._yamlErrorSummary = status.yamlErrorSummary; + this._pushActions(); + }, + }); + } catch (err) { + console.error('opendisplay-designer-panel: mount failed', err); + this._notify(`Failed to mount designer: ${errMsg(err)}`); + this._showMountError(errMsg(err)); + } + } + + _pushHostData() { + if (!this._handle) return; + try { + const targets = buildTargets(this._hass); + // Update tracking alongside the computed push, not after: the + // designer's onTargetSelected(null) for a stale removal fires + // asynchronously (not synchronously from inside setTargets() below), + // so the ordering relative to setTargets() doesn't itself matter for + // correctness today. Keeping this update right next to the push it + // describes is simply the one place it can never drift from what was + // actually last sent, and stays correct even if a future designer + // version ever fires the callback synchronously. + this._updateTargetsTracking(targets); + this._handle.setTheme(theme(this._hass)); + this._handle.setStates(collectStates(this._hass)); + this._handle.setTargets(targets); + } catch (err) { + console.error('opendisplay-designer-panel: host push failed', err); + this._notify(`Update from Home Assistant failed: ${errMsg(err)}`); + } + } + + /** + * `send` host action (docs/embedding.md `actions`/`onAction`) — the only + * save/send channel; the designer has no Save button of its own. + * `background`/`refresh_type` are still hardcoded (designer issue #105 + * will expose the rest of the option set later); `dither` and `rotate` + * are read LIVE off `HostActionContext` at the instant of the click + * (`context.render.dither`, `context.display.rotation` — both frozen, + * both present on every action since designer 3.0.0), so Send ships what + * the designer's own controls show right now. No preview has to have run, + * and nothing is remembered from one: the panel no longer keeps a + * last-preview dither or rotate at all. + */ + async _send(payloadYaml, context) { + const hass = this._hass; + const targetId = context.targetId; + if (!hass?.callService) { + this._notify('Home Assistant connection unavailable'); + return; + } + if (!targetId) { + this._notify('Select a display to send to'); + return; + } + if (this._sending) return; // in-flight guard — one Send at a time + let elements; + try { + elements = parsePayload(payloadYaml); + } catch (err) { + this._notify(`Cannot send invalid YAML: ${errMsg(err)}`); + return; + } + if (!elements.length) { + this._notify('Nothing to send — add elements first'); + return; + } + this._sending = true; + this._pushActions(); + try { + await hass.callService( + 'opendisplay', + 'drawcustom', + sendCallData(elements, this._targetDisplaySpecs.get(targetId), context), + // HA's separate service-call "target" (attributes the call to a + // device in the logbook/trace UI), independent of the `device_id` + // the service schema itself requires inside the data above. + { device_id: targetId } + ); + this._notify(`Sent ${elements.length} element(s) at ${new Date().toLocaleTimeString()}`); + } catch (err) { + this._notify(`Send failed: ${errMsg(err)}`); + } finally { + this._sending = false; + this._pushActions(); + } + } + + /** + * `renderPreview` host seam (docs/embedding.md `renderPreview`) — POSTs to + * this integration's own render endpoint (maintainer ruling 2026-08-30: + * preview must never touch a live display's own state). The endpoint + * renders through the same pipeline a real send uses and returns PNG + * bytes directly; no image-entity write, no signal dispatch, no BLE + * delivery happens on the backend either. The designer itself discards a + * superseded response (docs/embedding.md `renderPreview`: "a slow answer + * that a newer request has already superseded is discarded"), so this + * function does not need its own request-ordering logic. + */ + async _renderPreview(payloadYaml, context) { + const hass = this._hass; + if (!hass?.fetchWithAuth) throw new Error('Home Assistant connection unavailable'); + + let elements; + try { + elements = parsePayload(payloadYaml); + } catch (err) { + throw new Error(`Cannot preview invalid YAML: ${errMsg(err)}`); + } + + // Same builder module the `send` action uses, so preview and send derive + // `dither`/`rotate` from the designer's live context identically instead + // of two lookalike expressions that can drift. + const requestBody = renderRequestBody( + elements, + this._targetDisplaySpecs.get(context.targetId), + context + ); + const res = await hass.fetchWithAuth(RENDER_URL, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(requestBody), + }); + if (!res.ok) { + let message = `HTTP ${res.status}`; + try { + const body = await res.json(); + if (body?.message) message = body.message; + } catch { + // response body wasn't JSON — keep the plain HTTP status message + } + throw new Error(`Render failed: ${message}`); + } + return await res.blob(); + } + + /** + * `resolveAsset` host seam (`HostAssetResolver`, issue #138, ADR-002 + * amendment) -- the LAST tier of asset resolution, asked only for a + * reference the designer could not resolve itself (local content map, + * then bundled assets). BOTH `AssetKind` values are asked for: fonts by + * bare name against this integration's font directories, images by + * absolute path within Home Assistant's own permitted roots (see + * `designer/asset.py`). The earlier `kind !== 'font'` short-circuit is + * gone -- it made a payload's `/media/...` image render on the server + * while showing as missing in the designer (tier-2 round 3, real + * hardware). + * + * Per the contract's own wording, `null`/a rejection/a timeout all settle + * identically as "not supplied" and reach the user as the designer's own + * explicit render-error state -- never a silent skip, never a substituted + * font -- so every failure path here resolves `null` rather than + * throwing: a thrown error is not a documented outcome of this seam. + */ + async _resolveAsset(kind, name) { + const hass = this._hass; + const url = assetRequestUrl(kind, name); + if (url === null || !hass?.fetchWithAuth) return null; + try { + const res = await hass.fetchWithAuth(url); + if (!res.ok) return null; + return await res.blob(); + } catch { + return null; + } + } +} + +if (!customElements.get(TAG)) { + customElements.define(TAG, OpenDisplayDesignerPanel); +} diff --git a/custom_components/opendisplay/designer/frontend/panel/rotation.js b/custom_components/opendisplay/designer/frontend/panel/rotation.js new file mode 100644 index 00000000..4c127eda --- /dev/null +++ b/custom_components/opendisplay/designer/frontend/panel/rotation.js @@ -0,0 +1,75 @@ +/** + * Rotation delta derivation shared by preview (`renderPreview`) and send + * (`onAction`'s `send`). + * + * THE MAPPING, in one sentence: the designer reports an ABSOLUTE on-screen + * orientation (`context.display.rotation`, 0/90/180/270 — the orientation + * `context.display.width`/`height` are already expressed in), while the + * render endpoint and the `opendisplay.drawcustom` service both take a + * `rotate` DELTA the device composes on top of its own stored base rotation, + * so the host converts with `rotate = (context.display.rotation − + * target.display.rotationDegrees) mod 360`. + * + * The render endpoint's `rotate` field (and the `opendisplay.drawcustom` + * service's identical field, from which the endpoint is deliberately not + * allowed to drift -- see `docs/designer.md` and `tests/test_rotation_parity.py` + * in the Python integration) is a DELTA on top of the device's stored BASE + * rotation, not an absolute value. `_drawcustom_for_device`'s own contract + * (services.py): "the payload is authored against the FINAL on-screen + * orientation; the device applies (base + rotate)". Solving that for + * `rotate`: + * + * rotate = target - base (mod 360) + * + * where `target` is the final on-screen orientation the payload assumes. + * The designer's own canvas orientation control (the 0/90/180/270 buttons + * next to Display Config) reports exactly that target, absolutely, as + * `context.display.rotation` -- independent of whatever base rotation the + * target display's own `display.rotationDegrees` carries (issue #139: + * `HostDisplayGeometry` is always already oriented for whatever the + * designer's own control currently shows). Since designer 3.0.0 BOTH + * `HostPreviewContext` and `HostActionContext` carry that geometry, read + * live at the instant of the request/click, so preview and send derive the + * same delta from the same source instead of send reusing a remembered one. + * `base` is the same target's pushed `display.rotationDegrees` -- the + * device's fixed mounting rotation, read-only today (per-device persistent + * orientation is a deferred upstream feature; every base-rotated panel + * currently needs an explicit `rotate` on every call, matching the + * maintainer's own real automation). + * + * This is intentionally NOT "compare dimensions": composing two + * independent quarter-turns (the device's fixed base, then whatever the + * designer's own orientation toggle adds on top) is associative, so the + * LOGICAL SURFACE the SERVER's `generate_image` canvas is built at for + * (base, rotate) and what the DESIGNER'S OWN canvas shows for a chosen + * target orientation agree for every (base, target) combination -- proven + * directly by `tests/js/rotation.test.mjs`'s full matrix and, Python-side, + * by `tests/test_rotation_parity.py`'s dimension/content-orientation + * assertions (NOT "render endpoint bytes == drawcustom send-path bytes" -- + * that was this file's own claim through a tier-2 round-1 investigation + * that missed a real bug; see that test module's docstring for the + * corrected story: preview's `prepare_image` call must target the LOGICAL + * surface with no device-facing rotation, not the send path's own raw + * device grid, even though this delta FORMULA was correct the whole time). + * A bug that swapped the subtraction order (`base - target` instead of + * `target - base`) would still pass a DIMENSION-only check -- quarter/ + * half-turn parity is sign-symmetric, a 90° and a 270° rotation transpose + * width/height identically -- while shipping mirrored/sideways CONTENT. + * The test matrix pins exact delta values, not just parity, specifically + * to catch that class of bug. + * + * @param {{rotationDegrees?: number}|null|undefined} displaySpec The + * target's own pushed display declaration (`HostDisplaySpec`), or + * undefined/null when none have been published for it yet (falls back to + * base=0 -- the same "no rotation known yet" default an untouched, + * never-configured device already has). + * @param {number} targetOrientation The designer's live, absolute canvas + * orientation (`context.display.rotation`): 0, 90, 180, or 270. + * @returns {number} The `rotate` value the render endpoint / drawcustom + * service expects: 0, 90, 180, or 270. + */ +export function rotateDeltaFor(displaySpec, targetOrientation) { + const baseRotation = Number(displaySpec?.rotationDegrees) || 0; + const target = Number(targetOrientation) || 0; + return ((target - baseRotation) % 360 + 360) % 360; +} diff --git a/custom_components/opendisplay/designer/frontend/panel/unsaved-work.js b/custom_components/opendisplay/designer/frontend/panel/unsaved-work.js new file mode 100644 index 00000000..be31b3ab --- /dev/null +++ b/custom_components/opendisplay/designer/frontend/panel/unsaved-work.js @@ -0,0 +1,107 @@ +/** + * Navigate-away warning (tier-1 round 2, finding 6) -- INTERIM until the + * designer's own export-aware dirty flag (designer#167) ships. Every + * committed edit updates `getStatus().lastEditAt` (`null` before any edit + * this mount); a non-null value means there is unsaved work a tab close or + * reload would silently discard (the maintainer lost work this way). + * + * `beforeunload` is the only hook that actually covers this: it fires for a + * tab close, a reload, and a browser-chrome navigation (typed URL, + * back/forward, bookmark) alike. + * + * **************************************************************** + * * IT DOES NOT FIRE FOR HA'S OWN IN-APP SIDEBAR NAVIGATION. * + * * Clicking Overview/Settings/another sidebar item -- the * + * * single most obvious way to "leave the page" while testing -- * + * * is a SPA route swap, not a real page unload, and shows NO * + * * warning even with unsaved work. This is not a bug in the code * + * * below; it is a hard platform limitation (see next paragraph). * + * * Verify THIS fix with an actual reload, tab close, or a typed * + * * URL/bookmark -- NOT a sidebar click. * + * **************************************************************** + * + * Investigated and confirmed there is no equivalent hook for in-app + * navigation: HA's router just disconnects the panel custom element like + * any other DOM removal, and the Custom Elements spec has no cancelable + * "about to be removed" callback (`disconnectedCallback` runs AFTER + * removal, with no way to veto it) -- nor does the designer's own host + * contract (`odl-drawcustom-designer.d.ts`) expose one. + * + * Follow-up investigation (a maintainer report of "couldn't trigger the + * browser-level warning on leaving the page"): live-verified end to end in + * the real harness with a temporary diagnostic log (never committed) that + * `beforeunload` DOES fire while this panel is mounted, `getHandle()` + * DOES return the live, non-destroyed handle (not stale, not null) at + * fire time, `getStatus().lastEditAt` DOES read as the real non-null + * timestamp after an edit, and this code DOES reach the + * `preventDefault()`/`returnValue` branch -- every step of this module's + * own logic executes exactly as designed. The actual native "leave site?" + * dialog itself is what's fundamentally UNTESTABLE from here (browser + * automation harnesses -- this repo's own included -- auto-dismiss + * `beforeunload` prompts so tests don't hang forever waiting for a human; + * a real, unattended Chrome shows the dialog under the exact same + * preventDefault()+returnValue contract this code already satisfies). Most + * likely explanation for the report, given the above: the maintainer's + * first instinct for "leave the page" during manual testing was almost + * certainly clicking another sidebar item -- the in-app-navigation gap + * this doc comment already described, just not loudly enough. Reworded + * for visibility rather than left to be found by reading past the first + * paragraph. + * + * Kept in its own module, like key-containment.js, so the pure predicate is + * unit-testable with plain `node --test` without a real `beforeunload` event. + */ + +/** + * @param {{ getStatus(): { lastEditAt: number | null } } | null | undefined} handle + * @returns {boolean} true if there is a committed edit this mount hasn't + * exported/sent -- the designer itself does not distinguish "sent" from + * "not sent" here (that distinction is exactly what designer#167 adds); + * for now, any edit at all counts. + */ +export function hasUnsavedWork(handle) { + return handle?.getStatus().lastEditAt != null; +} + +/** + * beforeunload handler factory -- call the returned function with the real + * `beforeunload` Event. Never calls anything on `event` unless there is + * actually unsaved work, so a designer with nothing typed never nags. + * + * @param {() => ({ getStatus(): { lastEditAt: number | null } } | null | undefined)} getHandle + * thunk, not a snapshot -- `this._handle` can be reassigned across a + * remount, so the listener must read it fresh on every unload attempt, + * not close over whatever it was when connectedCallback ran. + */ +export function makeBeforeUnloadHandler(getHandle) { + return (event) => { + if (!hasUnsavedWork(getHandle())) return; + event.preventDefault(); + event.returnValue = ''; + }; +} + +/** + * Registration, bundled with its own disposer -- same shape as + * `containKeyEvents` (key-containment.js), and for the same reason: + * `opendisplay-designer-panel.js`'s `connectedCallback`/ + * `disconnectedCallback` call exactly this, one line each, so the actual + * registration timing (does connectedCallback wire this up unconditionally, + * synchronously, regardless of whether mount succeeded?) is unit-testable + * against a fake `window`-shaped object instead of only being verifiable by + * reading the call site and trusting it. `_mount()` in the panel wrapper is + * itself synchronous (no `await` before this runs) and any mount failure is + * caught internally there -- this call always runs. + * + * @param {{ addEventListener: Function, removeEventListener: Function }} win + * real `window` in production; a fake with the same two methods in tests. + * @param {() => ({ getStatus(): { lastEditAt: number | null } } | null | undefined)} getHandle + * @returns {() => void} disposer -- call from disconnectedCallback. + */ +export function installUnsavedWorkWarning(win, getHandle) { + const handler = makeBeforeUnloadHandler(getHandle); + win.addEventListener('beforeunload', handler); + return () => { + win.removeEventListener('beforeunload', handler); + }; +} diff --git a/custom_components/opendisplay/designer/frontend/vendor/LICENSE b/custom_components/opendisplay/designer/frontend/vendor/LICENSE new file mode 100644 index 00000000..8a4ee770 --- /dev/null +++ b/custom_components/opendisplay/designer/frontend/vendor/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2026 Schlomo Schapiro + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/custom_components/opendisplay/designer/frontend/vendor/LICENSE.js-yaml b/custom_components/opendisplay/designer/frontend/vendor/LICENSE.js-yaml new file mode 100644 index 00000000..09d3a29e --- /dev/null +++ b/custom_components/opendisplay/designer/frontend/vendor/LICENSE.js-yaml @@ -0,0 +1,21 @@ +(The MIT License) + +Copyright (C) 2011-2015 by Vitaly Puzrin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/custom_components/opendisplay/designer/frontend/vendor/NOTICE b/custom_components/opendisplay/designer/frontend/vendor/NOTICE new file mode 100644 index 00000000..aac9a360 --- /dev/null +++ b/custom_components/opendisplay/designer/frontend/vendor/NOTICE @@ -0,0 +1,66 @@ +ODL/OEPL Drawcustom Designer (odl-drawcustom-designer) +Copyright 2026 Schlomo Schapiro + +This product includes software developed by Schlomo Schapiro and contributors, +licensed under the Apache License, Version 2.0 (see LICENSE). + +================================================================================ +Vendored documentation +================================================================================ + +docs/spec/supported_types.md + Source: OpenEPaperLink Home Assistant Integration + URL: https://github.com/OpenEPaperLink/Home_Assistant_Integration/blob/main/docs/drawcustom/supported_types.md + License: Apache License 2.0 + Copyright: OpenEPaperLink contributors + +================================================================================ +Bundled fonts +================================================================================ + +public/fonts/ppb.ttf +public/fonts/rbm.ttf + Also emitted at build time as dist-lib/assets/demo-host-font.ttf — a copy of + rbm.ttf the demo host page serves as a host-resolved asset (see + tools/demoHostAssets.ts, docs/embedding.md#resolveasset-issue-138) + Source: OpenEPaperLink Home Assistant Integration (imagegen assets) + URL: https://github.com/OpenEPaperLink/Home_Assistant_Integration/tree/main/custom_components/open_epaper_link/imagegen/assets + License: Apache License 2.0 (same repository as above) + Note: Font files are distributed with the integration; no separate font + license file was found upstream. See docs/THIRD_PARTY.md for details. + +================================================================================ +Bundled icons (runtime) +================================================================================ + +@mdi/js — Material Design Icons path data (Pictogrammers) + URL: https://github.com/Templarian/MaterialDesign-SVG + License: Apache License 2.0 + Copyright: Pictogrammers + +================================================================================ +Referenced upstream projects (not shipped as source) +================================================================================ + +OpenEPaperLink firmware — CC BY-NC-SA 4.0 + URL: https://github.com/OpenEPaperLink/OpenEPaperLink + +OpenDisplay firmware — GPL-3.0 + URL: https://github.com/OpenDisplay/Firmware + +OpenDisplay Language / Basic Standard specifications + URL: https://opendisplay.org/protocol/ + Note: Published specification pages; no explicit license stated on site. + +Home Assistant integrations (drawcustom): + OpenEPaperLink/Home_Assistant_Integration — Apache-2.0 + OpenDisplay/Home_Assistant_Integration — Apache-2.0 + home-assistant/core (opendisplay component) — Apache-2.0 + +================================================================================ +Open-source dependencies +================================================================================ + +This application is built with npm packages. Each dependency is licensed +under its own terms. Run `npx license-checker --summary` in the project +root for a full report, or see docs/THIRD_PARTY.md for key runtime libraries. diff --git a/custom_components/opendisplay/designer/frontend/vendor/README.md b/custom_components/opendisplay/designer/frontend/vendor/README.md new file mode 100644 index 00000000..d5ec69de --- /dev/null +++ b/custom_components/opendisplay/designer/frontend/vendor/README.md @@ -0,0 +1,64 @@ +# Vendored libraries + +This directory vendors two npm packages the panel needs, both pinned and +verified the same way: + +- [`@schlomo/odl-drawcustom-designer`](https://github.com/schlomo/odl-drawcustom-designer) — + the designer library itself. +- [`js-yaml`](https://github.com/nodeca/js-yaml) — the panel needs it to turn + the designer's YAML string payload back into a JS list for the + `drawcustom` service call (`CORE_SCHEMA` specifically, so a bare `y:` key + parses as the string `"y"`, not a YAML-1.1 boolean). + +Home Assistant custom components cannot `npm install` at runtime, so neither +can be a normal `package.json` dependency here. Instead both are vendored +**from** npm — a pinned, verifiable download for each — rather than the old +procedure (pre-2026-08-30) of dropping in an unlabelled release build by +hand for the designer, and an unpinned jsDelivr-rebundled blob (no +integrity record, no `THIRD_PARTY.md` entry) for `js-yaml`. + +## Files + +| File | Source | +|------|--------| +| `odl-drawcustom-designer.js` | the designer library's self-contained ESM build | +| `odl-drawcustom-designer.d.ts` | its bundled TypeScript declarations (reference only — nothing here type-checks against it at build time; useful when editing the panel by hand) | +| `LICENSE`, `NOTICE`, `THIRD_PARTY.md` | the designer library's own licensing files (Apache-2.0) — `THIRD_PARTY.md` covers the designer's *own* transitive dependencies (auto-generated by the designer's own build tooling), not `js-yaml` (a sibling dependency of this panel, not of the designer bundle — never hand-added to that file) | +| `js-yaml.mjs` | `js-yaml`'s own npm-published ESM build (`dist/js-yaml.mjs`) | +| `LICENSE.js-yaml` | `js-yaml`'s own MIT license text (kept separate from the designer's `LICENSE`, which is a different package under a different license) | +| `designer.lock.json` | **both pins** — `{"designer": {"version", "integrity"}, "js_yaml": {"version", "integrity"}}`. This one file is the entire "what version, verified how" record for both packages; every file above is fully derived from it and none are ever hand-edited | + +## Updating + +```bash +# Re-download and re-verify BOTH currently pinned packages (idempotent — +# safe to re-run any time, e.g. to recover a corrupted vendor/ checkout): +scripts/update-designer-vendor.py + +# Bump the designer library to a new released version: +scripts/update-designer-vendor.py --pin 2.7.0 + +# Bump js-yaml to a new released version: +scripts/update-designer-vendor.py --pin-js-yaml 4.1.1 + +git diff custom_components/opendisplay/designer/frontend/vendor/ +``` + +`--pin`/`--pin-js-yaml` fetch that version's metadata from the npm registry +(the registry's own declared `sha512` `dist.integrity`), download the +tarball, and verify the **actual** downloaded bytes against that declared +hash before writing anything — the registry lookup is the one place this +procedure trusts npm (the same trust boundary `npm install` itself has). +Every subsequent run (with or without a `--pin*` flag) re-verifies against +the value now pinned in `designer.lock.json`, not against the registry +again. + +A mismatch (corrupted download, tampered mirror, wrong version) exits +non-zero and writes nothing — the vendored files stay exactly as they were. +There is no silent fallback to an unverified tarball. + +After bumping the designer's pin, review the diff of +`odl-drawcustom-designer.d.ts` against the panel's own API usage in +`../panel/opendisplay-designer-panel.js` — that file is hand-written against +the 2.x host contract (`docs/embedding.md` in the designer's own repo) and is +not regenerated by this script. diff --git a/custom_components/opendisplay/designer/frontend/vendor/THIRD_PARTY.md b/custom_components/opendisplay/designer/frontend/vendor/THIRD_PARTY.md new file mode 100644 index 00000000..b030e249 --- /dev/null +++ b/custom_components/opendisplay/designer/frontend/vendor/THIRD_PARTY.md @@ -0,0 +1,79 @@ +# Third-party notices (bundled dependencies) + +Auto-generated by `tools/thirdPartyNotices.ts` for the odl-drawcustom-designer +library build — every package listed here, direct or transitive, is compiled +into the single `odl-drawcustom-designer.js` ESM. For the repository's +broader attribution (vendored docs, fonts, non-bundled upstream ecosystems) +see [`docs/THIRD_PARTY.md`](https://github.com/schlomo/odl-drawcustom-designer/blob/main/docs/THIRD_PARTY.md). + +| Package | Version | License | Link | +|---|---|---|---| +| @codemirror/autocomplete | 6.20.3 | MIT | git+https://code.haverbeke.berlin/codemirror/autocomplete.git | +| @codemirror/commands | 6.10.4 | MIT | git+https://code.haverbeke.berlin/codemirror/commands.git | +| @codemirror/lang-css | 6.3.1 | MIT | https://github.com/codemirror/lang-css.git | +| @codemirror/lang-html | 6.4.11 | MIT | https://github.com/codemirror/lang-html.git | +| @codemirror/lang-javascript | 6.2.5 | MIT | git+https://github.com/codemirror/lang-javascript.git | +| @codemirror/lang-jinja | 6.0.1 | MIT | git+https://code.haverbeke.berlin/codemirror/lang-jinja.git | +| @codemirror/lang-yaml | 6.1.3 | MIT | git+https://github.com/codemirror/lang-yaml.git | +| @codemirror/language | 6.12.4 | MIT | git+https://code.haverbeke.berlin/codemirror/language.git | +| @codemirror/lint | 6.9.7 | MIT | git+https://code.haverbeke.berlin/codemirror/lint.git | +| @codemirror/search | 6.7.1 | MIT | git+https://code.haverbeke.berlin/codemirror/search.git | +| @codemirror/state | 6.7.1 | MIT | git+https://code.haverbeke.berlin/codemirror/state.git | +| @codemirror/theme-one-dark | 6.1.3 | MIT | https://github.com/codemirror/theme-one-dark.git | +| @codemirror/view | 6.43.8 | MIT | git+https://code.haverbeke.berlin/codemirror/view.git | +| @lezer/common | 1.5.2 | MIT | https://github.com/lezer-parser/common.git | +| @lezer/css | 1.3.3 | MIT | https://github.com/lezer-parser/css.git | +| @lezer/highlight | 1.2.3 | MIT | https://github.com/lezer-parser/highlight.git | +| @lezer/html | 1.3.13 | MIT | https://github.com/lezer-parser/html.git | +| @lezer/javascript | 1.5.4 | MIT | https://github.com/lezer-parser/javascript.git | +| @lezer/lr | 1.4.10 | MIT | git+https://code.haverbeke.berlin/lezer/lr.git | +| @lezer/yaml | 1.0.4 | MIT | https://github.com/lezer-parser/yaml.git | +| @marijn/find-cluster-break | 1.0.2 | MIT | https://github.com/marijnh/find-cluster-break#readme | +| @mdi/js | 7.4.47 | Apache-2.0 | https://github.com/Templarian/MaterialDesign-JS#readme | +| @uiw/codemirror-extensions-basic-setup | 4.25.11 | MIT | https://uiwjs.github.io/react-codemirror/#/extensions/basic-setup | +| a-sync-waterfall | 1.0.1 | MIT | https://github.com/hydiak/a-sync-waterfall | +| ansi-regex | 5.0.1 | MIT | | +| ansi-styles | 4.3.0 | MIT | | +| asap | 2.0.6 | MIT | https://github.com/kriskowal/asap.git | +| bidi-js | 1.0.3 | MIT | https://github.com/lojjic/bidi-js.git | +| camelcase | 5.3.1 | MIT | | +| cliui | 6.0.0 | ISC | http://github.com/yargs/cliui.git | +| color-convert | 2.0.1 | MIT | | +| color-name | 1.1.4 | MIT | https://github.com/colorjs/color-name | +| commander | 5.1.0 | MIT | https://github.com/tj/commander.js.git | +| crelt | 1.0.6 | MIT | https://github.com/marijnh/crelt#readme | +| decamelize | 1.2.0 | MIT | | +| dexie | 4.4.5 | Apache-2.0 | https://dexie.org | +| dijkstrajs | 1.0.3 | MIT | https://github.com/tcort/dijkstrajs | +| emoji-regex | 8.0.0 | MIT | https://mths.be/emoji-regex | +| find-up | 4.1.0 | MIT | | +| get-caller-file | 2.0.5 | ISC | https://github.com/stefanpenner/get-caller-file#readme | +| is-fullwidth-code-point | 3.0.0 | MIT | | +| locate-path | 5.0.0 | MIT | | +| nunjucks | 3.2.4 | BSD-2-Clause | https://github.com/mozilla/nunjucks.git | +| opentype.js | 2.0.0 | MIT | git://github.com/opentypejs/opentype.js.git | +| p-limit | 2.3.0 | MIT | | +| p-locate | 4.1.0 | MIT | | +| p-try | 2.2.0 | MIT | | +| pako | 3.0.1 | (MIT AND Zlib) | | +| path-exists | 4.0.0 | MIT | | +| pngjs | 5.0.0 | MIT | https://github.com/lukeapage/pngjs | +| qrcode | 1.5.4 | MIT | http://github.com/soldair/node-qrcode | +| react | 19.2.8 | MIT | https://react.dev/ | +| react-dom | 19.2.8 | MIT | https://react.dev/ | +| require-directory | 2.1.1 | MIT | https://github.com/troygoode/node-require-directory/ | +| require-from-string | 2.0.2 | MIT | | +| require-main-filename | 2.0.0 | ISC | https://github.com/yargs/require-main-filename#readme | +| scheduler | 0.27.0 | MIT | https://react.dev/ | +| set-blocking | 2.0.0 | ISC | https://github.com/yargs/set-blocking#readme | +| string-width | 4.2.3 | MIT | | +| strip-ansi | 6.0.1 | MIT | | +| style-mod | 4.1.3 | MIT | git+https://github.com/marijnh/style-mod.git | +| w3c-keyname | 2.2.8 | MIT | https://github.com/marijnh/w3c-keyname#readme | +| which-module | 2.0.1 | ISC | https://github.com/nexdrew/which-module#readme | +| wrap-ansi | 6.2.0 | MIT | | +| y18n | 4.0.3 | ISC | https://github.com/yargs/y18n | +| yaml | 2.9.0 | ISC | https://eemeli.org/yaml/ | +| yargs | 15.4.1 | MIT | https://yargs.js.org/ | +| yargs-parser | 18.1.3 | ISC | https://github.com/yargs/yargs-parser.git | +| zod | 4.4.3 | MIT | https://zod.dev | diff --git a/custom_components/opendisplay/designer/frontend/vendor/designer.lock.json b/custom_components/opendisplay/designer/frontend/vendor/designer.lock.json new file mode 100644 index 00000000..1320b737 --- /dev/null +++ b/custom_components/opendisplay/designer/frontend/vendor/designer.lock.json @@ -0,0 +1,10 @@ +{ + "designer": { + "version": "3.4.3", + "integrity": "sha512-j2VVpA3wAAcQH1VxQA3IPDoYRP6nfOh8sCiDsCoYX5JJ8X20uZo1AhqMbOM3a1sTbhVH1OWS+uNC7WwUR1cLvA==" + }, + "js_yaml": { + "version": "4.1.0", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==" + } +} diff --git a/custom_components/opendisplay/designer/frontend/vendor/js-yaml.mjs b/custom_components/opendisplay/designer/frontend/vendor/js-yaml.mjs new file mode 100644 index 00000000..be71cad1 --- /dev/null +++ b/custom_components/opendisplay/designer/frontend/vendor/js-yaml.mjs @@ -0,0 +1,3851 @@ + +/*! js-yaml 4.1.0 https://github.com/nodeca/js-yaml @license MIT */ +function isNothing(subject) { + return (typeof subject === 'undefined') || (subject === null); +} + + +function isObject(subject) { + return (typeof subject === 'object') && (subject !== null); +} + + +function toArray(sequence) { + if (Array.isArray(sequence)) return sequence; + else if (isNothing(sequence)) return []; + + return [ sequence ]; +} + + +function extend(target, source) { + var index, length, key, sourceKeys; + + if (source) { + sourceKeys = Object.keys(source); + + for (index = 0, length = sourceKeys.length; index < length; index += 1) { + key = sourceKeys[index]; + target[key] = source[key]; + } + } + + return target; +} + + +function repeat(string, count) { + var result = '', cycle; + + for (cycle = 0; cycle < count; cycle += 1) { + result += string; + } + + return result; +} + + +function isNegativeZero(number) { + return (number === 0) && (Number.NEGATIVE_INFINITY === 1 / number); +} + + +var isNothing_1 = isNothing; +var isObject_1 = isObject; +var toArray_1 = toArray; +var repeat_1 = repeat; +var isNegativeZero_1 = isNegativeZero; +var extend_1 = extend; + +var common = { + isNothing: isNothing_1, + isObject: isObject_1, + toArray: toArray_1, + repeat: repeat_1, + isNegativeZero: isNegativeZero_1, + extend: extend_1 +}; + +// YAML error class. http://stackoverflow.com/questions/8458984 + + +function formatError(exception, compact) { + var where = '', message = exception.reason || '(unknown reason)'; + + if (!exception.mark) return message; + + if (exception.mark.name) { + where += 'in "' + exception.mark.name + '" '; + } + + where += '(' + (exception.mark.line + 1) + ':' + (exception.mark.column + 1) + ')'; + + if (!compact && exception.mark.snippet) { + where += '\n\n' + exception.mark.snippet; + } + + return message + ' ' + where; +} + + +function YAMLException$1(reason, mark) { + // Super constructor + Error.call(this); + + this.name = 'YAMLException'; + this.reason = reason; + this.mark = mark; + this.message = formatError(this, false); + + // Include stack trace in error object + if (Error.captureStackTrace) { + // Chrome and NodeJS + Error.captureStackTrace(this, this.constructor); + } else { + // FF, IE 10+ and Safari 6+. Fallback for others + this.stack = (new Error()).stack || ''; + } +} + + +// Inherit from Error +YAMLException$1.prototype = Object.create(Error.prototype); +YAMLException$1.prototype.constructor = YAMLException$1; + + +YAMLException$1.prototype.toString = function toString(compact) { + return this.name + ': ' + formatError(this, compact); +}; + + +var exception = YAMLException$1; + +// get snippet for a single line, respecting maxLength +function getLine(buffer, lineStart, lineEnd, position, maxLineLength) { + var head = ''; + var tail = ''; + var maxHalfLength = Math.floor(maxLineLength / 2) - 1; + + if (position - lineStart > maxHalfLength) { + head = ' ... '; + lineStart = position - maxHalfLength + head.length; + } + + if (lineEnd - position > maxHalfLength) { + tail = ' ...'; + lineEnd = position + maxHalfLength - tail.length; + } + + return { + str: head + buffer.slice(lineStart, lineEnd).replace(/\t/g, '→') + tail, + pos: position - lineStart + head.length // relative position + }; +} + + +function padStart(string, max) { + return common.repeat(' ', max - string.length) + string; +} + + +function makeSnippet(mark, options) { + options = Object.create(options || null); + + if (!mark.buffer) return null; + + if (!options.maxLength) options.maxLength = 79; + if (typeof options.indent !== 'number') options.indent = 1; + if (typeof options.linesBefore !== 'number') options.linesBefore = 3; + if (typeof options.linesAfter !== 'number') options.linesAfter = 2; + + var re = /\r?\n|\r|\0/g; + var lineStarts = [ 0 ]; + var lineEnds = []; + var match; + var foundLineNo = -1; + + while ((match = re.exec(mark.buffer))) { + lineEnds.push(match.index); + lineStarts.push(match.index + match[0].length); + + if (mark.position <= match.index && foundLineNo < 0) { + foundLineNo = lineStarts.length - 2; + } + } + + if (foundLineNo < 0) foundLineNo = lineStarts.length - 1; + + var result = '', i, line; + var lineNoLength = Math.min(mark.line + options.linesAfter, lineEnds.length).toString().length; + var maxLineLength = options.maxLength - (options.indent + lineNoLength + 3); + + for (i = 1; i <= options.linesBefore; i++) { + if (foundLineNo - i < 0) break; + line = getLine( + mark.buffer, + lineStarts[foundLineNo - i], + lineEnds[foundLineNo - i], + mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo - i]), + maxLineLength + ); + result = common.repeat(' ', options.indent) + padStart((mark.line - i + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n' + result; + } + + line = getLine(mark.buffer, lineStarts[foundLineNo], lineEnds[foundLineNo], mark.position, maxLineLength); + result += common.repeat(' ', options.indent) + padStart((mark.line + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n'; + result += common.repeat('-', options.indent + lineNoLength + 3 + line.pos) + '^' + '\n'; + + for (i = 1; i <= options.linesAfter; i++) { + if (foundLineNo + i >= lineEnds.length) break; + line = getLine( + mark.buffer, + lineStarts[foundLineNo + i], + lineEnds[foundLineNo + i], + mark.position - (lineStarts[foundLineNo] - lineStarts[foundLineNo + i]), + maxLineLength + ); + result += common.repeat(' ', options.indent) + padStart((mark.line + i + 1).toString(), lineNoLength) + + ' | ' + line.str + '\n'; + } + + return result.replace(/\n$/, ''); +} + + +var snippet = makeSnippet; + +var TYPE_CONSTRUCTOR_OPTIONS = [ + 'kind', + 'multi', + 'resolve', + 'construct', + 'instanceOf', + 'predicate', + 'represent', + 'representName', + 'defaultStyle', + 'styleAliases' +]; + +var YAML_NODE_KINDS = [ + 'scalar', + 'sequence', + 'mapping' +]; + +function compileStyleAliases(map) { + var result = {}; + + if (map !== null) { + Object.keys(map).forEach(function (style) { + map[style].forEach(function (alias) { + result[String(alias)] = style; + }); + }); + } + + return result; +} + +function Type$1(tag, options) { + options = options || {}; + + Object.keys(options).forEach(function (name) { + if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name) === -1) { + throw new exception('Unknown option "' + name + '" is met in definition of "' + tag + '" YAML type.'); + } + }); + + // TODO: Add tag format check. + this.options = options; // keep original options in case user wants to extend this type later + this.tag = tag; + this.kind = options['kind'] || null; + this.resolve = options['resolve'] || function () { return true; }; + this.construct = options['construct'] || function (data) { return data; }; + this.instanceOf = options['instanceOf'] || null; + this.predicate = options['predicate'] || null; + this.represent = options['represent'] || null; + this.representName = options['representName'] || null; + this.defaultStyle = options['defaultStyle'] || null; + this.multi = options['multi'] || false; + this.styleAliases = compileStyleAliases(options['styleAliases'] || null); + + if (YAML_NODE_KINDS.indexOf(this.kind) === -1) { + throw new exception('Unknown kind "' + this.kind + '" is specified for "' + tag + '" YAML type.'); + } +} + +var type = Type$1; + +/*eslint-disable max-len*/ + + + + + +function compileList(schema, name) { + var result = []; + + schema[name].forEach(function (currentType) { + var newIndex = result.length; + + result.forEach(function (previousType, previousIndex) { + if (previousType.tag === currentType.tag && + previousType.kind === currentType.kind && + previousType.multi === currentType.multi) { + + newIndex = previousIndex; + } + }); + + result[newIndex] = currentType; + }); + + return result; +} + + +function compileMap(/* lists... */) { + var result = { + scalar: {}, + sequence: {}, + mapping: {}, + fallback: {}, + multi: { + scalar: [], + sequence: [], + mapping: [], + fallback: [] + } + }, index, length; + + function collectType(type) { + if (type.multi) { + result.multi[type.kind].push(type); + result.multi['fallback'].push(type); + } else { + result[type.kind][type.tag] = result['fallback'][type.tag] = type; + } + } + + for (index = 0, length = arguments.length; index < length; index += 1) { + arguments[index].forEach(collectType); + } + return result; +} + + +function Schema$1(definition) { + return this.extend(definition); +} + + +Schema$1.prototype.extend = function extend(definition) { + var implicit = []; + var explicit = []; + + if (definition instanceof type) { + // Schema.extend(type) + explicit.push(definition); + + } else if (Array.isArray(definition)) { + // Schema.extend([ type1, type2, ... ]) + explicit = explicit.concat(definition); + + } else if (definition && (Array.isArray(definition.implicit) || Array.isArray(definition.explicit))) { + // Schema.extend({ explicit: [ type1, type2, ... ], implicit: [ type1, type2, ... ] }) + if (definition.implicit) implicit = implicit.concat(definition.implicit); + if (definition.explicit) explicit = explicit.concat(definition.explicit); + + } else { + throw new exception('Schema.extend argument should be a Type, [ Type ], ' + + 'or a schema definition ({ implicit: [...], explicit: [...] })'); + } + + implicit.forEach(function (type$1) { + if (!(type$1 instanceof type)) { + throw new exception('Specified list of YAML types (or a single Type object) contains a non-Type object.'); + } + + if (type$1.loadKind && type$1.loadKind !== 'scalar') { + throw new exception('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.'); + } + + if (type$1.multi) { + throw new exception('There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.'); + } + }); + + explicit.forEach(function (type$1) { + if (!(type$1 instanceof type)) { + throw new exception('Specified list of YAML types (or a single Type object) contains a non-Type object.'); + } + }); + + var result = Object.create(Schema$1.prototype); + + result.implicit = (this.implicit || []).concat(implicit); + result.explicit = (this.explicit || []).concat(explicit); + + result.compiledImplicit = compileList(result, 'implicit'); + result.compiledExplicit = compileList(result, 'explicit'); + result.compiledTypeMap = compileMap(result.compiledImplicit, result.compiledExplicit); + + return result; +}; + + +var schema = Schema$1; + +var str = new type('tag:yaml.org,2002:str', { + kind: 'scalar', + construct: function (data) { return data !== null ? data : ''; } +}); + +var seq = new type('tag:yaml.org,2002:seq', { + kind: 'sequence', + construct: function (data) { return data !== null ? data : []; } +}); + +var map = new type('tag:yaml.org,2002:map', { + kind: 'mapping', + construct: function (data) { return data !== null ? data : {}; } +}); + +var failsafe = new schema({ + explicit: [ + str, + seq, + map + ] +}); + +function resolveYamlNull(data) { + if (data === null) return true; + + var max = data.length; + + return (max === 1 && data === '~') || + (max === 4 && (data === 'null' || data === 'Null' || data === 'NULL')); +} + +function constructYamlNull() { + return null; +} + +function isNull(object) { + return object === null; +} + +var _null = new type('tag:yaml.org,2002:null', { + kind: 'scalar', + resolve: resolveYamlNull, + construct: constructYamlNull, + predicate: isNull, + represent: { + canonical: function () { return '~'; }, + lowercase: function () { return 'null'; }, + uppercase: function () { return 'NULL'; }, + camelcase: function () { return 'Null'; }, + empty: function () { return ''; } + }, + defaultStyle: 'lowercase' +}); + +function resolveYamlBoolean(data) { + if (data === null) return false; + + var max = data.length; + + return (max === 4 && (data === 'true' || data === 'True' || data === 'TRUE')) || + (max === 5 && (data === 'false' || data === 'False' || data === 'FALSE')); +} + +function constructYamlBoolean(data) { + return data === 'true' || + data === 'True' || + data === 'TRUE'; +} + +function isBoolean(object) { + return Object.prototype.toString.call(object) === '[object Boolean]'; +} + +var bool = new type('tag:yaml.org,2002:bool', { + kind: 'scalar', + resolve: resolveYamlBoolean, + construct: constructYamlBoolean, + predicate: isBoolean, + represent: { + lowercase: function (object) { return object ? 'true' : 'false'; }, + uppercase: function (object) { return object ? 'TRUE' : 'FALSE'; }, + camelcase: function (object) { return object ? 'True' : 'False'; } + }, + defaultStyle: 'lowercase' +}); + +function isHexCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) || + ((0x41/* A */ <= c) && (c <= 0x46/* F */)) || + ((0x61/* a */ <= c) && (c <= 0x66/* f */)); +} + +function isOctCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x37/* 7 */)); +} + +function isDecCode(c) { + return ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)); +} + +function resolveYamlInteger(data) { + if (data === null) return false; + + var max = data.length, + index = 0, + hasDigits = false, + ch; + + if (!max) return false; + + ch = data[index]; + + // sign + if (ch === '-' || ch === '+') { + ch = data[++index]; + } + + if (ch === '0') { + // 0 + if (index + 1 === max) return true; + ch = data[++index]; + + // base 2, base 8, base 16 + + if (ch === 'b') { + // base 2 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (ch !== '0' && ch !== '1') return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } + + + if (ch === 'x') { + // base 16 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isHexCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } + + + if (ch === 'o') { + // base 8 + index++; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isOctCode(data.charCodeAt(index))) return false; + hasDigits = true; + } + return hasDigits && ch !== '_'; + } + } + + // base 10 (except 0) + + // value should not start with `_`; + if (ch === '_') return false; + + for (; index < max; index++) { + ch = data[index]; + if (ch === '_') continue; + if (!isDecCode(data.charCodeAt(index))) { + return false; + } + hasDigits = true; + } + + // Should have digits and should not end with `_` + if (!hasDigits || ch === '_') return false; + + return true; +} + +function constructYamlInteger(data) { + var value = data, sign = 1, ch; + + if (value.indexOf('_') !== -1) { + value = value.replace(/_/g, ''); + } + + ch = value[0]; + + if (ch === '-' || ch === '+') { + if (ch === '-') sign = -1; + value = value.slice(1); + ch = value[0]; + } + + if (value === '0') return 0; + + if (ch === '0') { + if (value[1] === 'b') return sign * parseInt(value.slice(2), 2); + if (value[1] === 'x') return sign * parseInt(value.slice(2), 16); + if (value[1] === 'o') return sign * parseInt(value.slice(2), 8); + } + + return sign * parseInt(value, 10); +} + +function isInteger(object) { + return (Object.prototype.toString.call(object)) === '[object Number]' && + (object % 1 === 0 && !common.isNegativeZero(object)); +} + +var int = new type('tag:yaml.org,2002:int', { + kind: 'scalar', + resolve: resolveYamlInteger, + construct: constructYamlInteger, + predicate: isInteger, + represent: { + binary: function (obj) { return obj >= 0 ? '0b' + obj.toString(2) : '-0b' + obj.toString(2).slice(1); }, + octal: function (obj) { return obj >= 0 ? '0o' + obj.toString(8) : '-0o' + obj.toString(8).slice(1); }, + decimal: function (obj) { return obj.toString(10); }, + /* eslint-disable max-len */ + hexadecimal: function (obj) { return obj >= 0 ? '0x' + obj.toString(16).toUpperCase() : '-0x' + obj.toString(16).toUpperCase().slice(1); } + }, + defaultStyle: 'decimal', + styleAliases: { + binary: [ 2, 'bin' ], + octal: [ 8, 'oct' ], + decimal: [ 10, 'dec' ], + hexadecimal: [ 16, 'hex' ] + } +}); + +var YAML_FLOAT_PATTERN = new RegExp( + // 2.5e4, 2.5 and integers + '^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?' + + // .2e4, .2 + // special case, seems not from spec + '|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?' + + // .inf + '|[-+]?\\.(?:inf|Inf|INF)' + + // .nan + '|\\.(?:nan|NaN|NAN))$'); + +function resolveYamlFloat(data) { + if (data === null) return false; + + if (!YAML_FLOAT_PATTERN.test(data) || + // Quick hack to not allow integers end with `_` + // Probably should update regexp & check speed + data[data.length - 1] === '_') { + return false; + } + + return true; +} + +function constructYamlFloat(data) { + var value, sign; + + value = data.replace(/_/g, '').toLowerCase(); + sign = value[0] === '-' ? -1 : 1; + + if ('+-'.indexOf(value[0]) >= 0) { + value = value.slice(1); + } + + if (value === '.inf') { + return (sign === 1) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY; + + } else if (value === '.nan') { + return NaN; + } + return sign * parseFloat(value, 10); +} + + +var SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/; + +function representYamlFloat(object, style) { + var res; + + if (isNaN(object)) { + switch (style) { + case 'lowercase': return '.nan'; + case 'uppercase': return '.NAN'; + case 'camelcase': return '.NaN'; + } + } else if (Number.POSITIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '.inf'; + case 'uppercase': return '.INF'; + case 'camelcase': return '.Inf'; + } + } else if (Number.NEGATIVE_INFINITY === object) { + switch (style) { + case 'lowercase': return '-.inf'; + case 'uppercase': return '-.INF'; + case 'camelcase': return '-.Inf'; + } + } else if (common.isNegativeZero(object)) { + return '-0.0'; + } + + res = object.toString(10); + + // JS stringifier can build scientific format without dots: 5e-100, + // while YAML requres dot: 5.e-100. Fix it with simple hack + + return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace('e', '.e') : res; +} + +function isFloat(object) { + return (Object.prototype.toString.call(object) === '[object Number]') && + (object % 1 !== 0 || common.isNegativeZero(object)); +} + +var float = new type('tag:yaml.org,2002:float', { + kind: 'scalar', + resolve: resolveYamlFloat, + construct: constructYamlFloat, + predicate: isFloat, + represent: representYamlFloat, + defaultStyle: 'lowercase' +}); + +var json = failsafe.extend({ + implicit: [ + _null, + bool, + int, + float + ] +}); + +var core = json; + +var YAML_DATE_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9])' + // [2] month + '-([0-9][0-9])$'); // [3] day + +var YAML_TIMESTAMP_REGEXP = new RegExp( + '^([0-9][0-9][0-9][0-9])' + // [1] year + '-([0-9][0-9]?)' + // [2] month + '-([0-9][0-9]?)' + // [3] day + '(?:[Tt]|[ \\t]+)' + // ... + '([0-9][0-9]?)' + // [4] hour + ':([0-9][0-9])' + // [5] minute + ':([0-9][0-9])' + // [6] second + '(?:\\.([0-9]*))?' + // [7] fraction + '(?:[ \\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tz_hour + '(?::([0-9][0-9]))?))?$'); // [11] tz_minute + +function resolveYamlTimestamp(data) { + if (data === null) return false; + if (YAML_DATE_REGEXP.exec(data) !== null) return true; + if (YAML_TIMESTAMP_REGEXP.exec(data) !== null) return true; + return false; +} + +function constructYamlTimestamp(data) { + var match, year, month, day, hour, minute, second, fraction = 0, + delta = null, tz_hour, tz_minute, date; + + match = YAML_DATE_REGEXP.exec(data); + if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(data); + + if (match === null) throw new Error('Date resolve error'); + + // match: [1] year [2] month [3] day + + year = +(match[1]); + month = +(match[2]) - 1; // JS month starts with 0 + day = +(match[3]); + + if (!match[4]) { // no hour + return new Date(Date.UTC(year, month, day)); + } + + // match: [4] hour [5] minute [6] second [7] fraction + + hour = +(match[4]); + minute = +(match[5]); + second = +(match[6]); + + if (match[7]) { + fraction = match[7].slice(0, 3); + while (fraction.length < 3) { // milli-seconds + fraction += '0'; + } + fraction = +fraction; + } + + // match: [8] tz [9] tz_sign [10] tz_hour [11] tz_minute + + if (match[9]) { + tz_hour = +(match[10]); + tz_minute = +(match[11] || 0); + delta = (tz_hour * 60 + tz_minute) * 60000; // delta in mili-seconds + if (match[9] === '-') delta = -delta; + } + + date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction)); + + if (delta) date.setTime(date.getTime() - delta); + + return date; +} + +function representYamlTimestamp(object /*, style*/) { + return object.toISOString(); +} + +var timestamp = new type('tag:yaml.org,2002:timestamp', { + kind: 'scalar', + resolve: resolveYamlTimestamp, + construct: constructYamlTimestamp, + instanceOf: Date, + represent: representYamlTimestamp +}); + +function resolveYamlMerge(data) { + return data === '<<' || data === null; +} + +var merge = new type('tag:yaml.org,2002:merge', { + kind: 'scalar', + resolve: resolveYamlMerge +}); + +/*eslint-disable no-bitwise*/ + + + + + +// [ 64, 65, 66 ] -> [ padding, CR, LF ] +var BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r'; + + +function resolveYamlBinary(data) { + if (data === null) return false; + + var code, idx, bitlen = 0, max = data.length, map = BASE64_MAP; + + // Convert one by one. + for (idx = 0; idx < max; idx++) { + code = map.indexOf(data.charAt(idx)); + + // Skip CR/LF + if (code > 64) continue; + + // Fail on illegal characters + if (code < 0) return false; + + bitlen += 6; + } + + // If there are any bits left, source was corrupted + return (bitlen % 8) === 0; +} + +function constructYamlBinary(data) { + var idx, tailbits, + input = data.replace(/[\r\n=]/g, ''), // remove CR/LF & padding to simplify scan + max = input.length, + map = BASE64_MAP, + bits = 0, + result = []; + + // Collect by 6*4 bits (3 bytes) + + for (idx = 0; idx < max; idx++) { + if ((idx % 4 === 0) && idx) { + result.push((bits >> 16) & 0xFF); + result.push((bits >> 8) & 0xFF); + result.push(bits & 0xFF); + } + + bits = (bits << 6) | map.indexOf(input.charAt(idx)); + } + + // Dump tail + + tailbits = (max % 4) * 6; + + if (tailbits === 0) { + result.push((bits >> 16) & 0xFF); + result.push((bits >> 8) & 0xFF); + result.push(bits & 0xFF); + } else if (tailbits === 18) { + result.push((bits >> 10) & 0xFF); + result.push((bits >> 2) & 0xFF); + } else if (tailbits === 12) { + result.push((bits >> 4) & 0xFF); + } + + return new Uint8Array(result); +} + +function representYamlBinary(object /*, style*/) { + var result = '', bits = 0, idx, tail, + max = object.length, + map = BASE64_MAP; + + // Convert every three bytes to 4 ASCII characters. + + for (idx = 0; idx < max; idx++) { + if ((idx % 3 === 0) && idx) { + result += map[(bits >> 18) & 0x3F]; + result += map[(bits >> 12) & 0x3F]; + result += map[(bits >> 6) & 0x3F]; + result += map[bits & 0x3F]; + } + + bits = (bits << 8) + object[idx]; + } + + // Dump tail + + tail = max % 3; + + if (tail === 0) { + result += map[(bits >> 18) & 0x3F]; + result += map[(bits >> 12) & 0x3F]; + result += map[(bits >> 6) & 0x3F]; + result += map[bits & 0x3F]; + } else if (tail === 2) { + result += map[(bits >> 10) & 0x3F]; + result += map[(bits >> 4) & 0x3F]; + result += map[(bits << 2) & 0x3F]; + result += map[64]; + } else if (tail === 1) { + result += map[(bits >> 2) & 0x3F]; + result += map[(bits << 4) & 0x3F]; + result += map[64]; + result += map[64]; + } + + return result; +} + +function isBinary(obj) { + return Object.prototype.toString.call(obj) === '[object Uint8Array]'; +} + +var binary = new type('tag:yaml.org,2002:binary', { + kind: 'scalar', + resolve: resolveYamlBinary, + construct: constructYamlBinary, + predicate: isBinary, + represent: representYamlBinary +}); + +var _hasOwnProperty$3 = Object.prototype.hasOwnProperty; +var _toString$2 = Object.prototype.toString; + +function resolveYamlOmap(data) { + if (data === null) return true; + + var objectKeys = [], index, length, pair, pairKey, pairHasKey, + object = data; + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + pairHasKey = false; + + if (_toString$2.call(pair) !== '[object Object]') return false; + + for (pairKey in pair) { + if (_hasOwnProperty$3.call(pair, pairKey)) { + if (!pairHasKey) pairHasKey = true; + else return false; + } + } + + if (!pairHasKey) return false; + + if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey); + else return false; + } + + return true; +} + +function constructYamlOmap(data) { + return data !== null ? data : []; +} + +var omap = new type('tag:yaml.org,2002:omap', { + kind: 'sequence', + resolve: resolveYamlOmap, + construct: constructYamlOmap +}); + +var _toString$1 = Object.prototype.toString; + +function resolveYamlPairs(data) { + if (data === null) return true; + + var index, length, pair, keys, result, + object = data; + + result = new Array(object.length); + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + + if (_toString$1.call(pair) !== '[object Object]') return false; + + keys = Object.keys(pair); + + if (keys.length !== 1) return false; + + result[index] = [ keys[0], pair[keys[0]] ]; + } + + return true; +} + +function constructYamlPairs(data) { + if (data === null) return []; + + var index, length, pair, keys, result, + object = data; + + result = new Array(object.length); + + for (index = 0, length = object.length; index < length; index += 1) { + pair = object[index]; + + keys = Object.keys(pair); + + result[index] = [ keys[0], pair[keys[0]] ]; + } + + return result; +} + +var pairs = new type('tag:yaml.org,2002:pairs', { + kind: 'sequence', + resolve: resolveYamlPairs, + construct: constructYamlPairs +}); + +var _hasOwnProperty$2 = Object.prototype.hasOwnProperty; + +function resolveYamlSet(data) { + if (data === null) return true; + + var key, object = data; + + for (key in object) { + if (_hasOwnProperty$2.call(object, key)) { + if (object[key] !== null) return false; + } + } + + return true; +} + +function constructYamlSet(data) { + return data !== null ? data : {}; +} + +var set = new type('tag:yaml.org,2002:set', { + kind: 'mapping', + resolve: resolveYamlSet, + construct: constructYamlSet +}); + +var _default = core.extend({ + implicit: [ + timestamp, + merge + ], + explicit: [ + binary, + omap, + pairs, + set + ] +}); + +/*eslint-disable max-len,no-use-before-define*/ + + + + + + + +var _hasOwnProperty$1 = Object.prototype.hasOwnProperty; + + +var CONTEXT_FLOW_IN = 1; +var CONTEXT_FLOW_OUT = 2; +var CONTEXT_BLOCK_IN = 3; +var CONTEXT_BLOCK_OUT = 4; + + +var CHOMPING_CLIP = 1; +var CHOMPING_STRIP = 2; +var CHOMPING_KEEP = 3; + + +var PATTERN_NON_PRINTABLE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x84\x86-\x9F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; +var PATTERN_NON_ASCII_LINE_BREAKS = /[\x85\u2028\u2029]/; +var PATTERN_FLOW_INDICATORS = /[,\[\]\{\}]/; +var PATTERN_TAG_HANDLE = /^(?:!|!!|![a-z\-]+!)$/i; +var PATTERN_TAG_URI = /^(?:!|[^,\[\]\{\}])(?:%[0-9a-f]{2}|[0-9a-z\-#;\/\?:@&=\+\$,_\.!~\*'\(\)\[\]])*$/i; + + +function _class(obj) { return Object.prototype.toString.call(obj); } + +function is_EOL(c) { + return (c === 0x0A/* LF */) || (c === 0x0D/* CR */); +} + +function is_WHITE_SPACE(c) { + return (c === 0x09/* Tab */) || (c === 0x20/* Space */); +} + +function is_WS_OR_EOL(c) { + return (c === 0x09/* Tab */) || + (c === 0x20/* Space */) || + (c === 0x0A/* LF */) || + (c === 0x0D/* CR */); +} + +function is_FLOW_INDICATOR(c) { + return c === 0x2C/* , */ || + c === 0x5B/* [ */ || + c === 0x5D/* ] */ || + c === 0x7B/* { */ || + c === 0x7D/* } */; +} + +function fromHexCode(c) { + var lc; + + if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { + return c - 0x30; + } + + /*eslint-disable no-bitwise*/ + lc = c | 0x20; + + if ((0x61/* a */ <= lc) && (lc <= 0x66/* f */)) { + return lc - 0x61 + 10; + } + + return -1; +} + +function escapedHexLen(c) { + if (c === 0x78/* x */) { return 2; } + if (c === 0x75/* u */) { return 4; } + if (c === 0x55/* U */) { return 8; } + return 0; +} + +function fromDecimalCode(c) { + if ((0x30/* 0 */ <= c) && (c <= 0x39/* 9 */)) { + return c - 0x30; + } + + return -1; +} + +function simpleEscapeSequence(c) { + /* eslint-disable indent */ + return (c === 0x30/* 0 */) ? '\x00' : + (c === 0x61/* a */) ? '\x07' : + (c === 0x62/* b */) ? '\x08' : + (c === 0x74/* t */) ? '\x09' : + (c === 0x09/* Tab */) ? '\x09' : + (c === 0x6E/* n */) ? '\x0A' : + (c === 0x76/* v */) ? '\x0B' : + (c === 0x66/* f */) ? '\x0C' : + (c === 0x72/* r */) ? '\x0D' : + (c === 0x65/* e */) ? '\x1B' : + (c === 0x20/* Space */) ? ' ' : + (c === 0x22/* " */) ? '\x22' : + (c === 0x2F/* / */) ? '/' : + (c === 0x5C/* \ */) ? '\x5C' : + (c === 0x4E/* N */) ? '\x85' : + (c === 0x5F/* _ */) ? '\xA0' : + (c === 0x4C/* L */) ? '\u2028' : + (c === 0x50/* P */) ? '\u2029' : ''; +} + +function charFromCodepoint(c) { + if (c <= 0xFFFF) { + return String.fromCharCode(c); + } + // Encode UTF-16 surrogate pair + // https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B010000_to_U.2B10FFFF + return String.fromCharCode( + ((c - 0x010000) >> 10) + 0xD800, + ((c - 0x010000) & 0x03FF) + 0xDC00 + ); +} + +var simpleEscapeCheck = new Array(256); // integer, for fast access +var simpleEscapeMap = new Array(256); +for (var i = 0; i < 256; i++) { + simpleEscapeCheck[i] = simpleEscapeSequence(i) ? 1 : 0; + simpleEscapeMap[i] = simpleEscapeSequence(i); +} + + +function State$1(input, options) { + this.input = input; + + this.filename = options['filename'] || null; + this.schema = options['schema'] || _default; + this.onWarning = options['onWarning'] || null; + // (Hidden) Remove? makes the loader to expect YAML 1.1 documents + // if such documents have no explicit %YAML directive + this.legacy = options['legacy'] || false; + + this.json = options['json'] || false; + this.listener = options['listener'] || null; + + this.implicitTypes = this.schema.compiledImplicit; + this.typeMap = this.schema.compiledTypeMap; + + this.length = input.length; + this.position = 0; + this.line = 0; + this.lineStart = 0; + this.lineIndent = 0; + + // position of first leading tab in the current line, + // used to make sure there are no tabs in the indentation + this.firstTabInLine = -1; + + this.documents = []; + + /* + this.version; + this.checkLineBreaks; + this.tagMap; + this.anchorMap; + this.tag; + this.anchor; + this.kind; + this.result;*/ + +} + + +function generateError(state, message) { + var mark = { + name: state.filename, + buffer: state.input.slice(0, -1), // omit trailing \0 + position: state.position, + line: state.line, + column: state.position - state.lineStart + }; + + mark.snippet = snippet(mark); + + return new exception(message, mark); +} + +function throwError(state, message) { + throw generateError(state, message); +} + +function throwWarning(state, message) { + if (state.onWarning) { + state.onWarning.call(null, generateError(state, message)); + } +} + + +var directiveHandlers = { + + YAML: function handleYamlDirective(state, name, args) { + + var match, major, minor; + + if (state.version !== null) { + throwError(state, 'duplication of %YAML directive'); + } + + if (args.length !== 1) { + throwError(state, 'YAML directive accepts exactly one argument'); + } + + match = /^([0-9]+)\.([0-9]+)$/.exec(args[0]); + + if (match === null) { + throwError(state, 'ill-formed argument of the YAML directive'); + } + + major = parseInt(match[1], 10); + minor = parseInt(match[2], 10); + + if (major !== 1) { + throwError(state, 'unacceptable YAML version of the document'); + } + + state.version = args[0]; + state.checkLineBreaks = (minor < 2); + + if (minor !== 1 && minor !== 2) { + throwWarning(state, 'unsupported YAML version of the document'); + } + }, + + TAG: function handleTagDirective(state, name, args) { + + var handle, prefix; + + if (args.length !== 2) { + throwError(state, 'TAG directive accepts exactly two arguments'); + } + + handle = args[0]; + prefix = args[1]; + + if (!PATTERN_TAG_HANDLE.test(handle)) { + throwError(state, 'ill-formed tag handle (first argument) of the TAG directive'); + } + + if (_hasOwnProperty$1.call(state.tagMap, handle)) { + throwError(state, 'there is a previously declared suffix for "' + handle + '" tag handle'); + } + + if (!PATTERN_TAG_URI.test(prefix)) { + throwError(state, 'ill-formed tag prefix (second argument) of the TAG directive'); + } + + try { + prefix = decodeURIComponent(prefix); + } catch (err) { + throwError(state, 'tag prefix is malformed: ' + prefix); + } + + state.tagMap[handle] = prefix; + } +}; + + +function captureSegment(state, start, end, checkJson) { + var _position, _length, _character, _result; + + if (start < end) { + _result = state.input.slice(start, end); + + if (checkJson) { + for (_position = 0, _length = _result.length; _position < _length; _position += 1) { + _character = _result.charCodeAt(_position); + if (!(_character === 0x09 || + (0x20 <= _character && _character <= 0x10FFFF))) { + throwError(state, 'expected valid JSON character'); + } + } + } else if (PATTERN_NON_PRINTABLE.test(_result)) { + throwError(state, 'the stream contains non-printable characters'); + } + + state.result += _result; + } +} + +function mergeMappings(state, destination, source, overridableKeys) { + var sourceKeys, key, index, quantity; + + if (!common.isObject(source)) { + throwError(state, 'cannot merge mappings; the provided source object is unacceptable'); + } + + sourceKeys = Object.keys(source); + + for (index = 0, quantity = sourceKeys.length; index < quantity; index += 1) { + key = sourceKeys[index]; + + if (!_hasOwnProperty$1.call(destination, key)) { + destination[key] = source[key]; + overridableKeys[key] = true; + } + } +} + +function storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, + startLine, startLineStart, startPos) { + + var index, quantity; + + // The output is a plain object here, so keys can only be strings. + // We need to convert keyNode to a string, but doing so can hang the process + // (deeply nested arrays that explode exponentially using aliases). + if (Array.isArray(keyNode)) { + keyNode = Array.prototype.slice.call(keyNode); + + for (index = 0, quantity = keyNode.length; index < quantity; index += 1) { + if (Array.isArray(keyNode[index])) { + throwError(state, 'nested arrays are not supported inside keys'); + } + + if (typeof keyNode === 'object' && _class(keyNode[index]) === '[object Object]') { + keyNode[index] = '[object Object]'; + } + } + } + + // Avoid code execution in load() via toString property + // (still use its own toString for arrays, timestamps, + // and whatever user schema extensions happen to have @@toStringTag) + if (typeof keyNode === 'object' && _class(keyNode) === '[object Object]') { + keyNode = '[object Object]'; + } + + + keyNode = String(keyNode); + + if (_result === null) { + _result = {}; + } + + if (keyTag === 'tag:yaml.org,2002:merge') { + if (Array.isArray(valueNode)) { + for (index = 0, quantity = valueNode.length; index < quantity; index += 1) { + mergeMappings(state, _result, valueNode[index], overridableKeys); + } + } else { + mergeMappings(state, _result, valueNode, overridableKeys); + } + } else { + if (!state.json && + !_hasOwnProperty$1.call(overridableKeys, keyNode) && + _hasOwnProperty$1.call(_result, keyNode)) { + state.line = startLine || state.line; + state.lineStart = startLineStart || state.lineStart; + state.position = startPos || state.position; + throwError(state, 'duplicated mapping key'); + } + + // used for this specific key only because Object.defineProperty is slow + if (keyNode === '__proto__') { + Object.defineProperty(_result, keyNode, { + configurable: true, + enumerable: true, + writable: true, + value: valueNode + }); + } else { + _result[keyNode] = valueNode; + } + delete overridableKeys[keyNode]; + } + + return _result; +} + +function readLineBreak(state) { + var ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x0A/* LF */) { + state.position++; + } else if (ch === 0x0D/* CR */) { + state.position++; + if (state.input.charCodeAt(state.position) === 0x0A/* LF */) { + state.position++; + } + } else { + throwError(state, 'a line break is expected'); + } + + state.line += 1; + state.lineStart = state.position; + state.firstTabInLine = -1; +} + +function skipSeparationSpace(state, allowComments, checkIndent) { + var lineBreaks = 0, + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + while (is_WHITE_SPACE(ch)) { + if (ch === 0x09/* Tab */ && state.firstTabInLine === -1) { + state.firstTabInLine = state.position; + } + ch = state.input.charCodeAt(++state.position); + } + + if (allowComments && ch === 0x23/* # */) { + do { + ch = state.input.charCodeAt(++state.position); + } while (ch !== 0x0A/* LF */ && ch !== 0x0D/* CR */ && ch !== 0); + } + + if (is_EOL(ch)) { + readLineBreak(state); + + ch = state.input.charCodeAt(state.position); + lineBreaks++; + state.lineIndent = 0; + + while (ch === 0x20/* Space */) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + } else { + break; + } + } + + if (checkIndent !== -1 && lineBreaks !== 0 && state.lineIndent < checkIndent) { + throwWarning(state, 'deficient indentation'); + } + + return lineBreaks; +} + +function testDocumentSeparator(state) { + var _position = state.position, + ch; + + ch = state.input.charCodeAt(_position); + + // Condition state.position === state.lineStart is tested + // in parent on each call, for efficiency. No needs to test here again. + if ((ch === 0x2D/* - */ || ch === 0x2E/* . */) && + ch === state.input.charCodeAt(_position + 1) && + ch === state.input.charCodeAt(_position + 2)) { + + _position += 3; + + ch = state.input.charCodeAt(_position); + + if (ch === 0 || is_WS_OR_EOL(ch)) { + return true; + } + } + + return false; +} + +function writeFoldedLines(state, count) { + if (count === 1) { + state.result += ' '; + } else if (count > 1) { + state.result += common.repeat('\n', count - 1); + } +} + + +function readPlainScalar(state, nodeIndent, withinFlowCollection) { + var preceding, + following, + captureStart, + captureEnd, + hasPendingContent, + _line, + _lineStart, + _lineIndent, + _kind = state.kind, + _result = state.result, + ch; + + ch = state.input.charCodeAt(state.position); + + if (is_WS_OR_EOL(ch) || + is_FLOW_INDICATOR(ch) || + ch === 0x23/* # */ || + ch === 0x26/* & */ || + ch === 0x2A/* * */ || + ch === 0x21/* ! */ || + ch === 0x7C/* | */ || + ch === 0x3E/* > */ || + ch === 0x27/* ' */ || + ch === 0x22/* " */ || + ch === 0x25/* % */ || + ch === 0x40/* @ */ || + ch === 0x60/* ` */) { + return false; + } + + if (ch === 0x3F/* ? */ || ch === 0x2D/* - */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following) || + withinFlowCollection && is_FLOW_INDICATOR(following)) { + return false; + } + } + + state.kind = 'scalar'; + state.result = ''; + captureStart = captureEnd = state.position; + hasPendingContent = false; + + while (ch !== 0) { + if (ch === 0x3A/* : */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following) || + withinFlowCollection && is_FLOW_INDICATOR(following)) { + break; + } + + } else if (ch === 0x23/* # */) { + preceding = state.input.charCodeAt(state.position - 1); + + if (is_WS_OR_EOL(preceding)) { + break; + } + + } else if ((state.position === state.lineStart && testDocumentSeparator(state)) || + withinFlowCollection && is_FLOW_INDICATOR(ch)) { + break; + + } else if (is_EOL(ch)) { + _line = state.line; + _lineStart = state.lineStart; + _lineIndent = state.lineIndent; + skipSeparationSpace(state, false, -1); + + if (state.lineIndent >= nodeIndent) { + hasPendingContent = true; + ch = state.input.charCodeAt(state.position); + continue; + } else { + state.position = captureEnd; + state.line = _line; + state.lineStart = _lineStart; + state.lineIndent = _lineIndent; + break; + } + } + + if (hasPendingContent) { + captureSegment(state, captureStart, captureEnd, false); + writeFoldedLines(state, state.line - _line); + captureStart = captureEnd = state.position; + hasPendingContent = false; + } + + if (!is_WHITE_SPACE(ch)) { + captureEnd = state.position + 1; + } + + ch = state.input.charCodeAt(++state.position); + } + + captureSegment(state, captureStart, captureEnd, false); + + if (state.result) { + return true; + } + + state.kind = _kind; + state.result = _result; + return false; +} + +function readSingleQuotedScalar(state, nodeIndent) { + var ch, + captureStart, captureEnd; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x27/* ' */) { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + state.position++; + captureStart = captureEnd = state.position; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x27/* ' */) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x27/* ' */) { + captureStart = state.position; + state.position++; + captureEnd = state.position; + } else { + return true; + } + + } else if (is_EOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a single quoted scalar'); + + } else { + state.position++; + captureEnd = state.position; + } + } + + throwError(state, 'unexpected end of the stream within a single quoted scalar'); +} + +function readDoubleQuotedScalar(state, nodeIndent) { + var captureStart, + captureEnd, + hexLength, + hexResult, + tmp, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x22/* " */) { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + state.position++; + captureStart = captureEnd = state.position; + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + if (ch === 0x22/* " */) { + captureSegment(state, captureStart, state.position, true); + state.position++; + return true; + + } else if (ch === 0x5C/* \ */) { + captureSegment(state, captureStart, state.position, true); + ch = state.input.charCodeAt(++state.position); + + if (is_EOL(ch)) { + skipSeparationSpace(state, false, nodeIndent); + + // TODO: rework to inline fn with no type cast? + } else if (ch < 256 && simpleEscapeCheck[ch]) { + state.result += simpleEscapeMap[ch]; + state.position++; + + } else if ((tmp = escapedHexLen(ch)) > 0) { + hexLength = tmp; + hexResult = 0; + + for (; hexLength > 0; hexLength--) { + ch = state.input.charCodeAt(++state.position); + + if ((tmp = fromHexCode(ch)) >= 0) { + hexResult = (hexResult << 4) + tmp; + + } else { + throwError(state, 'expected hexadecimal character'); + } + } + + state.result += charFromCodepoint(hexResult); + + state.position++; + + } else { + throwError(state, 'unknown escape sequence'); + } + + captureStart = captureEnd = state.position; + + } else if (is_EOL(ch)) { + captureSegment(state, captureStart, captureEnd, true); + writeFoldedLines(state, skipSeparationSpace(state, false, nodeIndent)); + captureStart = captureEnd = state.position; + + } else if (state.position === state.lineStart && testDocumentSeparator(state)) { + throwError(state, 'unexpected end of the document within a double quoted scalar'); + + } else { + state.position++; + captureEnd = state.position; + } + } + + throwError(state, 'unexpected end of the stream within a double quoted scalar'); +} + +function readFlowCollection(state, nodeIndent) { + var readNext = true, + _line, + _lineStart, + _pos, + _tag = state.tag, + _result, + _anchor = state.anchor, + following, + terminator, + isPair, + isExplicitPair, + isMapping, + overridableKeys = Object.create(null), + keyNode, + keyTag, + valueNode, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x5B/* [ */) { + terminator = 0x5D;/* ] */ + isMapping = false; + _result = []; + } else if (ch === 0x7B/* { */) { + terminator = 0x7D;/* } */ + isMapping = true; + _result = {}; + } else { + return false; + } + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(++state.position); + + while (ch !== 0) { + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if (ch === terminator) { + state.position++; + state.tag = _tag; + state.anchor = _anchor; + state.kind = isMapping ? 'mapping' : 'sequence'; + state.result = _result; + return true; + } else if (!readNext) { + throwError(state, 'missed comma between flow collection entries'); + } else if (ch === 0x2C/* , */) { + // "flow collection entries can never be completely empty", as per YAML 1.2, section 7.4 + throwError(state, "expected the node content, but found ','"); + } + + keyTag = keyNode = valueNode = null; + isPair = isExplicitPair = false; + + if (ch === 0x3F/* ? */) { + following = state.input.charCodeAt(state.position + 1); + + if (is_WS_OR_EOL(following)) { + isPair = isExplicitPair = true; + state.position++; + skipSeparationSpace(state, true, nodeIndent); + } + } + + _line = state.line; // Save the current line. + _lineStart = state.lineStart; + _pos = state.position; + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + keyTag = state.tag; + keyNode = state.result; + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if ((isExplicitPair || state.line === _line) && ch === 0x3A/* : */) { + isPair = true; + ch = state.input.charCodeAt(++state.position); + skipSeparationSpace(state, true, nodeIndent); + composeNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true); + valueNode = state.result; + } + + if (isMapping) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos); + } else if (isPair) { + _result.push(storeMappingPair(state, null, overridableKeys, keyTag, keyNode, valueNode, _line, _lineStart, _pos)); + } else { + _result.push(keyNode); + } + + skipSeparationSpace(state, true, nodeIndent); + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x2C/* , */) { + readNext = true; + ch = state.input.charCodeAt(++state.position); + } else { + readNext = false; + } + } + + throwError(state, 'unexpected end of the stream within a flow collection'); +} + +function readBlockScalar(state, nodeIndent) { + var captureStart, + folding, + chomping = CHOMPING_CLIP, + didReadContent = false, + detectedIndent = false, + textIndent = nodeIndent, + emptyLines = 0, + atMoreIndented = false, + tmp, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch === 0x7C/* | */) { + folding = false; + } else if (ch === 0x3E/* > */) { + folding = true; + } else { + return false; + } + + state.kind = 'scalar'; + state.result = ''; + + while (ch !== 0) { + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { + if (CHOMPING_CLIP === chomping) { + chomping = (ch === 0x2B/* + */) ? CHOMPING_KEEP : CHOMPING_STRIP; + } else { + throwError(state, 'repeat of a chomping mode identifier'); + } + + } else if ((tmp = fromDecimalCode(ch)) >= 0) { + if (tmp === 0) { + throwError(state, 'bad explicit indentation width of a block scalar; it cannot be less than one'); + } else if (!detectedIndent) { + textIndent = nodeIndent + tmp - 1; + detectedIndent = true; + } else { + throwError(state, 'repeat of an indentation width identifier'); + } + + } else { + break; + } + } + + if (is_WHITE_SPACE(ch)) { + do { ch = state.input.charCodeAt(++state.position); } + while (is_WHITE_SPACE(ch)); + + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position); } + while (!is_EOL(ch) && (ch !== 0)); + } + } + + while (ch !== 0) { + readLineBreak(state); + state.lineIndent = 0; + + ch = state.input.charCodeAt(state.position); + + while ((!detectedIndent || state.lineIndent < textIndent) && + (ch === 0x20/* Space */)) { + state.lineIndent++; + ch = state.input.charCodeAt(++state.position); + } + + if (!detectedIndent && state.lineIndent > textIndent) { + textIndent = state.lineIndent; + } + + if (is_EOL(ch)) { + emptyLines++; + continue; + } + + // End of the scalar. + if (state.lineIndent < textIndent) { + + // Perform the chomping. + if (chomping === CHOMPING_KEEP) { + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + } else if (chomping === CHOMPING_CLIP) { + if (didReadContent) { // i.e. only if the scalar is not empty. + state.result += '\n'; + } + } + + // Break this `while` cycle and go to the funciton's epilogue. + break; + } + + // Folded style: use fancy rules to handle line breaks. + if (folding) { + + // Lines starting with white space characters (more-indented lines) are not folded. + if (is_WHITE_SPACE(ch)) { + atMoreIndented = true; + // except for the first content line (cf. Example 8.1) + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + + // End of more-indented block. + } else if (atMoreIndented) { + atMoreIndented = false; + state.result += common.repeat('\n', emptyLines + 1); + + // Just one line break - perceive as the same line. + } else if (emptyLines === 0) { + if (didReadContent) { // i.e. only if we have already read some scalar content. + state.result += ' '; + } + + // Several line breaks - perceive as different lines. + } else { + state.result += common.repeat('\n', emptyLines); + } + + // Literal style: just add exact number of line breaks between content lines. + } else { + // Keep all line breaks except the header line break. + state.result += common.repeat('\n', didReadContent ? 1 + emptyLines : emptyLines); + } + + didReadContent = true; + detectedIndent = true; + emptyLines = 0; + captureStart = state.position; + + while (!is_EOL(ch) && (ch !== 0)) { + ch = state.input.charCodeAt(++state.position); + } + + captureSegment(state, captureStart, state.position, false); + } + + return true; +} + +function readBlockSequence(state, nodeIndent) { + var _line, + _tag = state.tag, + _anchor = state.anchor, + _result = [], + following, + detected = false, + ch; + + // there is a leading tab before this token, so it can't be a block sequence/mapping; + // it can still be flow sequence/mapping or a scalar + if (state.firstTabInLine !== -1) return false; + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + if (state.firstTabInLine !== -1) { + state.position = state.firstTabInLine; + throwError(state, 'tab characters must not be used in indentation'); + } + + if (ch !== 0x2D/* - */) { + break; + } + + following = state.input.charCodeAt(state.position + 1); + + if (!is_WS_OR_EOL(following)) { + break; + } + + detected = true; + state.position++; + + if (skipSeparationSpace(state, true, -1)) { + if (state.lineIndent <= nodeIndent) { + _result.push(null); + ch = state.input.charCodeAt(state.position); + continue; + } + } + + _line = state.line; + composeNode(state, nodeIndent, CONTEXT_BLOCK_IN, false, true); + _result.push(state.result); + skipSeparationSpace(state, true, -1); + + ch = state.input.charCodeAt(state.position); + + if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) { + throwError(state, 'bad indentation of a sequence entry'); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = 'sequence'; + state.result = _result; + return true; + } + return false; +} + +function readBlockMapping(state, nodeIndent, flowIndent) { + var following, + allowCompact, + _line, + _keyLine, + _keyLineStart, + _keyPos, + _tag = state.tag, + _anchor = state.anchor, + _result = {}, + overridableKeys = Object.create(null), + keyTag = null, + keyNode = null, + valueNode = null, + atExplicitKey = false, + detected = false, + ch; + + // there is a leading tab before this token, so it can't be a block sequence/mapping; + // it can still be flow sequence/mapping or a scalar + if (state.firstTabInLine !== -1) return false; + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = _result; + } + + ch = state.input.charCodeAt(state.position); + + while (ch !== 0) { + if (!atExplicitKey && state.firstTabInLine !== -1) { + state.position = state.firstTabInLine; + throwError(state, 'tab characters must not be used in indentation'); + } + + following = state.input.charCodeAt(state.position + 1); + _line = state.line; // Save the current line. + + // + // Explicit notation case. There are two separate blocks: + // first for the key (denoted by "?") and second for the value (denoted by ":") + // + if ((ch === 0x3F/* ? */ || ch === 0x3A/* : */) && is_WS_OR_EOL(following)) { + + if (ch === 0x3F/* ? */) { + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + + detected = true; + atExplicitKey = true; + allowCompact = true; + + } else if (atExplicitKey) { + // i.e. 0x3A/* : */ === character after the explicit key. + atExplicitKey = false; + allowCompact = true; + + } else { + throwError(state, 'incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line'); + } + + state.position += 1; + ch = following; + + // + // Implicit notation case. Flow-style node as the key first, then ":", and the value. + // + } else { + _keyLine = state.line; + _keyLineStart = state.lineStart; + _keyPos = state.position; + + if (!composeNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true)) { + // Neither implicit nor explicit notation. + // Reading is done. Go to the epilogue. + break; + } + + if (state.line === _line) { + ch = state.input.charCodeAt(state.position); + + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (ch === 0x3A/* : */) { + ch = state.input.charCodeAt(++state.position); + + if (!is_WS_OR_EOL(ch)) { + throwError(state, 'a whitespace character is expected after the key-value separator within a block mapping'); + } + + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + + detected = true; + atExplicitKey = false; + allowCompact = false; + keyTag = state.tag; + keyNode = state.result; + + } else if (detected) { + throwError(state, 'can not read an implicit mapping pair; a colon is missed'); + + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; // Keep the result of `composeNode`. + } + + } else if (detected) { + throwError(state, 'can not read a block mapping entry; a multiline key may not be an implicit key'); + + } else { + state.tag = _tag; + state.anchor = _anchor; + return true; // Keep the result of `composeNode`. + } + } + + // + // Common reading code for both explicit and implicit notations. + // + if (state.line === _line || state.lineIndent > nodeIndent) { + if (atExplicitKey) { + _keyLine = state.line; + _keyLineStart = state.lineStart; + _keyPos = state.position; + } + + if (composeNode(state, nodeIndent, CONTEXT_BLOCK_OUT, true, allowCompact)) { + if (atExplicitKey) { + keyNode = state.result; + } else { + valueNode = state.result; + } + } + + if (!atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, valueNode, _keyLine, _keyLineStart, _keyPos); + keyTag = keyNode = valueNode = null; + } + + skipSeparationSpace(state, true, -1); + ch = state.input.charCodeAt(state.position); + } + + if ((state.line === _line || state.lineIndent > nodeIndent) && (ch !== 0)) { + throwError(state, 'bad indentation of a mapping entry'); + } else if (state.lineIndent < nodeIndent) { + break; + } + } + + // + // Epilogue. + // + + // Special case: last mapping's node contains only the key in explicit notation. + if (atExplicitKey) { + storeMappingPair(state, _result, overridableKeys, keyTag, keyNode, null, _keyLine, _keyLineStart, _keyPos); + } + + // Expose the resulting mapping. + if (detected) { + state.tag = _tag; + state.anchor = _anchor; + state.kind = 'mapping'; + state.result = _result; + } + + return detected; +} + +function readTagProperty(state) { + var _position, + isVerbatim = false, + isNamed = false, + tagHandle, + tagName, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x21/* ! */) return false; + + if (state.tag !== null) { + throwError(state, 'duplication of a tag property'); + } + + ch = state.input.charCodeAt(++state.position); + + if (ch === 0x3C/* < */) { + isVerbatim = true; + ch = state.input.charCodeAt(++state.position); + + } else if (ch === 0x21/* ! */) { + isNamed = true; + tagHandle = '!!'; + ch = state.input.charCodeAt(++state.position); + + } else { + tagHandle = '!'; + } + + _position = state.position; + + if (isVerbatim) { + do { ch = state.input.charCodeAt(++state.position); } + while (ch !== 0 && ch !== 0x3E/* > */); + + if (state.position < state.length) { + tagName = state.input.slice(_position, state.position); + ch = state.input.charCodeAt(++state.position); + } else { + throwError(state, 'unexpected end of the stream within a verbatim tag'); + } + } else { + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + + if (ch === 0x21/* ! */) { + if (!isNamed) { + tagHandle = state.input.slice(_position - 1, state.position + 1); + + if (!PATTERN_TAG_HANDLE.test(tagHandle)) { + throwError(state, 'named tag handle cannot contain such characters'); + } + + isNamed = true; + _position = state.position + 1; + } else { + throwError(state, 'tag suffix cannot contain exclamation marks'); + } + } + + ch = state.input.charCodeAt(++state.position); + } + + tagName = state.input.slice(_position, state.position); + + if (PATTERN_FLOW_INDICATORS.test(tagName)) { + throwError(state, 'tag suffix cannot contain flow indicator characters'); + } + } + + if (tagName && !PATTERN_TAG_URI.test(tagName)) { + throwError(state, 'tag name cannot contain such characters: ' + tagName); + } + + try { + tagName = decodeURIComponent(tagName); + } catch (err) { + throwError(state, 'tag name is malformed: ' + tagName); + } + + if (isVerbatim) { + state.tag = tagName; + + } else if (_hasOwnProperty$1.call(state.tagMap, tagHandle)) { + state.tag = state.tagMap[tagHandle] + tagName; + + } else if (tagHandle === '!') { + state.tag = '!' + tagName; + + } else if (tagHandle === '!!') { + state.tag = 'tag:yaml.org,2002:' + tagName; + + } else { + throwError(state, 'undeclared tag handle "' + tagHandle + '"'); + } + + return true; +} + +function readAnchorProperty(state) { + var _position, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x26/* & */) return false; + + if (state.anchor !== null) { + throwError(state, 'duplication of an anchor property'); + } + + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (state.position === _position) { + throwError(state, 'name of an anchor node must contain at least one character'); + } + + state.anchor = state.input.slice(_position, state.position); + return true; +} + +function readAlias(state) { + var _position, alias, + ch; + + ch = state.input.charCodeAt(state.position); + + if (ch !== 0x2A/* * */) return false; + + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch) && !is_FLOW_INDICATOR(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (state.position === _position) { + throwError(state, 'name of an alias node must contain at least one character'); + } + + alias = state.input.slice(_position, state.position); + + if (!_hasOwnProperty$1.call(state.anchorMap, alias)) { + throwError(state, 'unidentified alias "' + alias + '"'); + } + + state.result = state.anchorMap[alias]; + skipSeparationSpace(state, true, -1); + return true; +} + +function composeNode(state, parentIndent, nodeContext, allowToSeek, allowCompact) { + var allowBlockStyles, + allowBlockScalars, + allowBlockCollections, + indentStatus = 1, // 1: this>parent, 0: this=parent, -1: this parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } + } + + if (indentStatus === 1) { + while (readTagProperty(state) || readAnchorProperty(state)) { + if (skipSeparationSpace(state, true, -1)) { + atNewLine = true; + allowBlockCollections = allowBlockStyles; + + if (state.lineIndent > parentIndent) { + indentStatus = 1; + } else if (state.lineIndent === parentIndent) { + indentStatus = 0; + } else if (state.lineIndent < parentIndent) { + indentStatus = -1; + } + } else { + allowBlockCollections = false; + } + } + } + + if (allowBlockCollections) { + allowBlockCollections = atNewLine || allowCompact; + } + + if (indentStatus === 1 || CONTEXT_BLOCK_OUT === nodeContext) { + if (CONTEXT_FLOW_IN === nodeContext || CONTEXT_FLOW_OUT === nodeContext) { + flowIndent = parentIndent; + } else { + flowIndent = parentIndent + 1; + } + + blockIndent = state.position - state.lineStart; + + if (indentStatus === 1) { + if (allowBlockCollections && + (readBlockSequence(state, blockIndent) || + readBlockMapping(state, blockIndent, flowIndent)) || + readFlowCollection(state, flowIndent)) { + hasContent = true; + } else { + if ((allowBlockScalars && readBlockScalar(state, flowIndent)) || + readSingleQuotedScalar(state, flowIndent) || + readDoubleQuotedScalar(state, flowIndent)) { + hasContent = true; + + } else if (readAlias(state)) { + hasContent = true; + + if (state.tag !== null || state.anchor !== null) { + throwError(state, 'alias node should not have any properties'); + } + + } else if (readPlainScalar(state, flowIndent, CONTEXT_FLOW_IN === nodeContext)) { + hasContent = true; + + if (state.tag === null) { + state.tag = '?'; + } + } + + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + } + } else if (indentStatus === 0) { + // Special case: block sequences are allowed to have same indentation level as the parent. + // http://www.yaml.org/spec/1.2/spec.html#id2799784 + hasContent = allowBlockCollections && readBlockSequence(state, blockIndent); + } + } + + if (state.tag === null) { + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + + } else if (state.tag === '?') { + // Implicit resolving is not allowed for non-scalar types, and '?' + // non-specific tag is only automatically assigned to plain scalars. + // + // We only need to check kind conformity in case user explicitly assigns '?' + // tag, for example like this: "! [0]" + // + if (state.result !== null && state.kind !== 'scalar') { + throwError(state, 'unacceptable node kind for ! tag; it should be "scalar", not "' + state.kind + '"'); + } + + for (typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) { + type = state.implicitTypes[typeIndex]; + + if (type.resolve(state.result)) { // `state.result` updated in resolver if matched + state.result = type.construct(state.result); + state.tag = type.tag; + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + break; + } + } + } else if (state.tag !== '!') { + if (_hasOwnProperty$1.call(state.typeMap[state.kind || 'fallback'], state.tag)) { + type = state.typeMap[state.kind || 'fallback'][state.tag]; + } else { + // looking for multi type + type = null; + typeList = state.typeMap.multi[state.kind || 'fallback']; + + for (typeIndex = 0, typeQuantity = typeList.length; typeIndex < typeQuantity; typeIndex += 1) { + if (state.tag.slice(0, typeList[typeIndex].tag.length) === typeList[typeIndex].tag) { + type = typeList[typeIndex]; + break; + } + } + } + + if (!type) { + throwError(state, 'unknown tag !<' + state.tag + '>'); + } + + if (state.result !== null && type.kind !== state.kind) { + throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be "' + type.kind + '", not "' + state.kind + '"'); + } + + if (!type.resolve(state.result, state.tag)) { // `state.result` updated in resolver if matched + throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag'); + } else { + state.result = type.construct(state.result, state.tag); + if (state.anchor !== null) { + state.anchorMap[state.anchor] = state.result; + } + } + } + + if (state.listener !== null) { + state.listener('close', state); + } + return state.tag !== null || state.anchor !== null || hasContent; +} + +function readDocument(state) { + var documentStart = state.position, + _position, + directiveName, + directiveArgs, + hasDirectives = false, + ch; + + state.version = null; + state.checkLineBreaks = state.legacy; + state.tagMap = Object.create(null); + state.anchorMap = Object.create(null); + + while ((ch = state.input.charCodeAt(state.position)) !== 0) { + skipSeparationSpace(state, true, -1); + + ch = state.input.charCodeAt(state.position); + + if (state.lineIndent > 0 || ch !== 0x25/* % */) { + break; + } + + hasDirectives = true; + ch = state.input.charCodeAt(++state.position); + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + directiveName = state.input.slice(_position, state.position); + directiveArgs = []; + + if (directiveName.length < 1) { + throwError(state, 'directive name must not be less than one character in length'); + } + + while (ch !== 0) { + while (is_WHITE_SPACE(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + if (ch === 0x23/* # */) { + do { ch = state.input.charCodeAt(++state.position); } + while (ch !== 0 && !is_EOL(ch)); + break; + } + + if (is_EOL(ch)) break; + + _position = state.position; + + while (ch !== 0 && !is_WS_OR_EOL(ch)) { + ch = state.input.charCodeAt(++state.position); + } + + directiveArgs.push(state.input.slice(_position, state.position)); + } + + if (ch !== 0) readLineBreak(state); + + if (_hasOwnProperty$1.call(directiveHandlers, directiveName)) { + directiveHandlers[directiveName](state, directiveName, directiveArgs); + } else { + throwWarning(state, 'unknown document directive "' + directiveName + '"'); + } + } + + skipSeparationSpace(state, true, -1); + + if (state.lineIndent === 0 && + state.input.charCodeAt(state.position) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 1) === 0x2D/* - */ && + state.input.charCodeAt(state.position + 2) === 0x2D/* - */) { + state.position += 3; + skipSeparationSpace(state, true, -1); + + } else if (hasDirectives) { + throwError(state, 'directives end mark is expected'); + } + + composeNode(state, state.lineIndent - 1, CONTEXT_BLOCK_OUT, false, true); + skipSeparationSpace(state, true, -1); + + if (state.checkLineBreaks && + PATTERN_NON_ASCII_LINE_BREAKS.test(state.input.slice(documentStart, state.position))) { + throwWarning(state, 'non-ASCII line breaks are interpreted as content'); + } + + state.documents.push(state.result); + + if (state.position === state.lineStart && testDocumentSeparator(state)) { + + if (state.input.charCodeAt(state.position) === 0x2E/* . */) { + state.position += 3; + skipSeparationSpace(state, true, -1); + } + return; + } + + if (state.position < (state.length - 1)) { + throwError(state, 'end of the stream or a document separator is expected'); + } else { + return; + } +} + + +function loadDocuments(input, options) { + input = String(input); + options = options || {}; + + if (input.length !== 0) { + + // Add tailing `\n` if not exists + if (input.charCodeAt(input.length - 1) !== 0x0A/* LF */ && + input.charCodeAt(input.length - 1) !== 0x0D/* CR */) { + input += '\n'; + } + + // Strip BOM + if (input.charCodeAt(0) === 0xFEFF) { + input = input.slice(1); + } + } + + var state = new State$1(input, options); + + var nullpos = input.indexOf('\0'); + + if (nullpos !== -1) { + state.position = nullpos; + throwError(state, 'null byte is not allowed in input'); + } + + // Use 0 as string terminator. That significantly simplifies bounds check. + state.input += '\0'; + + while (state.input.charCodeAt(state.position) === 0x20/* Space */) { + state.lineIndent += 1; + state.position += 1; + } + + while (state.position < (state.length - 1)) { + readDocument(state); + } + + return state.documents; +} + + +function loadAll$1(input, iterator, options) { + if (iterator !== null && typeof iterator === 'object' && typeof options === 'undefined') { + options = iterator; + iterator = null; + } + + var documents = loadDocuments(input, options); + + if (typeof iterator !== 'function') { + return documents; + } + + for (var index = 0, length = documents.length; index < length; index += 1) { + iterator(documents[index]); + } +} + + +function load$1(input, options) { + var documents = loadDocuments(input, options); + + if (documents.length === 0) { + /*eslint-disable no-undefined*/ + return undefined; + } else if (documents.length === 1) { + return documents[0]; + } + throw new exception('expected a single document in the stream, but found more'); +} + + +var loadAll_1 = loadAll$1; +var load_1 = load$1; + +var loader = { + loadAll: loadAll_1, + load: load_1 +}; + +/*eslint-disable no-use-before-define*/ + + + + + +var _toString = Object.prototype.toString; +var _hasOwnProperty = Object.prototype.hasOwnProperty; + +var CHAR_BOM = 0xFEFF; +var CHAR_TAB = 0x09; /* Tab */ +var CHAR_LINE_FEED = 0x0A; /* LF */ +var CHAR_CARRIAGE_RETURN = 0x0D; /* CR */ +var CHAR_SPACE = 0x20; /* Space */ +var CHAR_EXCLAMATION = 0x21; /* ! */ +var CHAR_DOUBLE_QUOTE = 0x22; /* " */ +var CHAR_SHARP = 0x23; /* # */ +var CHAR_PERCENT = 0x25; /* % */ +var CHAR_AMPERSAND = 0x26; /* & */ +var CHAR_SINGLE_QUOTE = 0x27; /* ' */ +var CHAR_ASTERISK = 0x2A; /* * */ +var CHAR_COMMA = 0x2C; /* , */ +var CHAR_MINUS = 0x2D; /* - */ +var CHAR_COLON = 0x3A; /* : */ +var CHAR_EQUALS = 0x3D; /* = */ +var CHAR_GREATER_THAN = 0x3E; /* > */ +var CHAR_QUESTION = 0x3F; /* ? */ +var CHAR_COMMERCIAL_AT = 0x40; /* @ */ +var CHAR_LEFT_SQUARE_BRACKET = 0x5B; /* [ */ +var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */ +var CHAR_GRAVE_ACCENT = 0x60; /* ` */ +var CHAR_LEFT_CURLY_BRACKET = 0x7B; /* { */ +var CHAR_VERTICAL_LINE = 0x7C; /* | */ +var CHAR_RIGHT_CURLY_BRACKET = 0x7D; /* } */ + +var ESCAPE_SEQUENCES = {}; + +ESCAPE_SEQUENCES[0x00] = '\\0'; +ESCAPE_SEQUENCES[0x07] = '\\a'; +ESCAPE_SEQUENCES[0x08] = '\\b'; +ESCAPE_SEQUENCES[0x09] = '\\t'; +ESCAPE_SEQUENCES[0x0A] = '\\n'; +ESCAPE_SEQUENCES[0x0B] = '\\v'; +ESCAPE_SEQUENCES[0x0C] = '\\f'; +ESCAPE_SEQUENCES[0x0D] = '\\r'; +ESCAPE_SEQUENCES[0x1B] = '\\e'; +ESCAPE_SEQUENCES[0x22] = '\\"'; +ESCAPE_SEQUENCES[0x5C] = '\\\\'; +ESCAPE_SEQUENCES[0x85] = '\\N'; +ESCAPE_SEQUENCES[0xA0] = '\\_'; +ESCAPE_SEQUENCES[0x2028] = '\\L'; +ESCAPE_SEQUENCES[0x2029] = '\\P'; + +var DEPRECATED_BOOLEANS_SYNTAX = [ + 'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON', + 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF' +]; + +var DEPRECATED_BASE60_SYNTAX = /^[-+]?[0-9_]+(?::[0-9_]+)+(?:\.[0-9_]*)?$/; + +function compileStyleMap(schema, map) { + var result, keys, index, length, tag, style, type; + + if (map === null) return {}; + + result = {}; + keys = Object.keys(map); + + for (index = 0, length = keys.length; index < length; index += 1) { + tag = keys[index]; + style = String(map[tag]); + + if (tag.slice(0, 2) === '!!') { + tag = 'tag:yaml.org,2002:' + tag.slice(2); + } + type = schema.compiledTypeMap['fallback'][tag]; + + if (type && _hasOwnProperty.call(type.styleAliases, style)) { + style = type.styleAliases[style]; + } + + result[tag] = style; + } + + return result; +} + +function encodeHex(character) { + var string, handle, length; + + string = character.toString(16).toUpperCase(); + + if (character <= 0xFF) { + handle = 'x'; + length = 2; + } else if (character <= 0xFFFF) { + handle = 'u'; + length = 4; + } else if (character <= 0xFFFFFFFF) { + handle = 'U'; + length = 8; + } else { + throw new exception('code point within a string may not be greater than 0xFFFFFFFF'); + } + + return '\\' + handle + common.repeat('0', length - string.length) + string; +} + + +var QUOTING_TYPE_SINGLE = 1, + QUOTING_TYPE_DOUBLE = 2; + +function State(options) { + this.schema = options['schema'] || _default; + this.indent = Math.max(1, (options['indent'] || 2)); + this.noArrayIndent = options['noArrayIndent'] || false; + this.skipInvalid = options['skipInvalid'] || false; + this.flowLevel = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']); + this.styleMap = compileStyleMap(this.schema, options['styles'] || null); + this.sortKeys = options['sortKeys'] || false; + this.lineWidth = options['lineWidth'] || 80; + this.noRefs = options['noRefs'] || false; + this.noCompatMode = options['noCompatMode'] || false; + this.condenseFlow = options['condenseFlow'] || false; + this.quotingType = options['quotingType'] === '"' ? QUOTING_TYPE_DOUBLE : QUOTING_TYPE_SINGLE; + this.forceQuotes = options['forceQuotes'] || false; + this.replacer = typeof options['replacer'] === 'function' ? options['replacer'] : null; + + this.implicitTypes = this.schema.compiledImplicit; + this.explicitTypes = this.schema.compiledExplicit; + + this.tag = null; + this.result = ''; + + this.duplicates = []; + this.usedDuplicates = null; +} + +// Indents every line in a string. Empty lines (\n only) are not indented. +function indentString(string, spaces) { + var ind = common.repeat(' ', spaces), + position = 0, + next = -1, + result = '', + line, + length = string.length; + + while (position < length) { + next = string.indexOf('\n', position); + if (next === -1) { + line = string.slice(position); + position = length; + } else { + line = string.slice(position, next + 1); + position = next + 1; + } + + if (line.length && line !== '\n') result += ind; + + result += line; + } + + return result; +} + +function generateNextLine(state, level) { + return '\n' + common.repeat(' ', state.indent * level); +} + +function testImplicitResolving(state, str) { + var index, length, type; + + for (index = 0, length = state.implicitTypes.length; index < length; index += 1) { + type = state.implicitTypes[index]; + + if (type.resolve(str)) { + return true; + } + } + + return false; +} + +// [33] s-white ::= s-space | s-tab +function isWhitespace(c) { + return c === CHAR_SPACE || c === CHAR_TAB; +} + +// Returns true if the character can be printed without escaping. +// From YAML 1.2: "any allowed characters known to be non-printable +// should also be escaped. [However,] This isn’t mandatory" +// Derived from nb-char - \t - #x85 - #xA0 - #x2028 - #x2029. +function isPrintable(c) { + return (0x00020 <= c && c <= 0x00007E) + || ((0x000A1 <= c && c <= 0x00D7FF) && c !== 0x2028 && c !== 0x2029) + || ((0x0E000 <= c && c <= 0x00FFFD) && c !== CHAR_BOM) + || (0x10000 <= c && c <= 0x10FFFF); +} + +// [34] ns-char ::= nb-char - s-white +// [27] nb-char ::= c-printable - b-char - c-byte-order-mark +// [26] b-char ::= b-line-feed | b-carriage-return +// Including s-white (for some reason, examples doesn't match specs in this aspect) +// ns-char ::= c-printable - b-line-feed - b-carriage-return - c-byte-order-mark +function isNsCharOrWhitespace(c) { + return isPrintable(c) + && c !== CHAR_BOM + // - b-char + && c !== CHAR_CARRIAGE_RETURN + && c !== CHAR_LINE_FEED; +} + +// [127] ns-plain-safe(c) ::= c = flow-out ⇒ ns-plain-safe-out +// c = flow-in ⇒ ns-plain-safe-in +// c = block-key ⇒ ns-plain-safe-out +// c = flow-key ⇒ ns-plain-safe-in +// [128] ns-plain-safe-out ::= ns-char +// [129] ns-plain-safe-in ::= ns-char - c-flow-indicator +// [130] ns-plain-char(c) ::= ( ns-plain-safe(c) - “:” - “#” ) +// | ( /* An ns-char preceding */ “#” ) +// | ( “:” /* Followed by an ns-plain-safe(c) */ ) +function isPlainSafe(c, prev, inblock) { + var cIsNsCharOrWhitespace = isNsCharOrWhitespace(c); + var cIsNsChar = cIsNsCharOrWhitespace && !isWhitespace(c); + return ( + // ns-plain-safe + inblock ? // c = flow-in + cIsNsCharOrWhitespace + : cIsNsCharOrWhitespace + // - c-flow-indicator + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + ) + // ns-plain-char + && c !== CHAR_SHARP // false on '#' + && !(prev === CHAR_COLON && !cIsNsChar) // false on ': ' + || (isNsCharOrWhitespace(prev) && !isWhitespace(prev) && c === CHAR_SHARP) // change to true on '[^ ]#' + || (prev === CHAR_COLON && cIsNsChar); // change to true on ':[^ ]' +} + +// Simplified test for values allowed as the first character in plain style. +function isPlainSafeFirst(c) { + // Uses a subset of ns-char - c-indicator + // where ns-char = nb-char - s-white. + // No support of ( ( “?” | “:” | “-” ) /* Followed by an ns-plain-safe(c)) */ ) part + return isPrintable(c) && c !== CHAR_BOM + && !isWhitespace(c) // - s-white + // - (c-indicator ::= + // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}” + && c !== CHAR_MINUS + && c !== CHAR_QUESTION + && c !== CHAR_COLON + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + // | “#” | “&” | “*” | “!” | “|” | “=” | “>” | “'” | “"” + && c !== CHAR_SHARP + && c !== CHAR_AMPERSAND + && c !== CHAR_ASTERISK + && c !== CHAR_EXCLAMATION + && c !== CHAR_VERTICAL_LINE + && c !== CHAR_EQUALS + && c !== CHAR_GREATER_THAN + && c !== CHAR_SINGLE_QUOTE + && c !== CHAR_DOUBLE_QUOTE + // | “%” | “@” | “`”) + && c !== CHAR_PERCENT + && c !== CHAR_COMMERCIAL_AT + && c !== CHAR_GRAVE_ACCENT; +} + +// Simplified test for values allowed as the last character in plain style. +function isPlainSafeLast(c) { + // just not whitespace or colon, it will be checked to be plain character later + return !isWhitespace(c) && c !== CHAR_COLON; +} + +// Same as 'string'.codePointAt(pos), but works in older browsers. +function codePointAt(string, pos) { + var first = string.charCodeAt(pos), second; + if (first >= 0xD800 && first <= 0xDBFF && pos + 1 < string.length) { + second = string.charCodeAt(pos + 1); + if (second >= 0xDC00 && second <= 0xDFFF) { + // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; + } + } + return first; +} + +// Determines whether block indentation indicator is required. +function needIndentIndicator(string) { + var leadingSpaceRe = /^\n* /; + return leadingSpaceRe.test(string); +} + +var STYLE_PLAIN = 1, + STYLE_SINGLE = 2, + STYLE_LITERAL = 3, + STYLE_FOLDED = 4, + STYLE_DOUBLE = 5; + +// Determines which scalar styles are possible and returns the preferred style. +// lineWidth = -1 => no limit. +// Pre-conditions: str.length > 0. +// Post-conditions: +// STYLE_PLAIN or STYLE_SINGLE => no \n are in the string. +// STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1). +// STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1). +function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, + testAmbiguousType, quotingType, forceQuotes, inblock) { + + var i; + var char = 0; + var prevChar = null; + var hasLineBreak = false; + var hasFoldableLine = false; // only checked if shouldTrackWidth + var shouldTrackWidth = lineWidth !== -1; + var previousLineBreak = -1; // count the first line correctly + var plain = isPlainSafeFirst(codePointAt(string, 0)) + && isPlainSafeLast(codePointAt(string, string.length - 1)); + + if (singleLineOnly || forceQuotes) { + // Case: no block styles. + // Check for disallowed characters to rule out plain and single. + for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i); + if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char, prevChar, inblock); + prevChar = char; + } + } else { + // Case: block styles permitted. + for (i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i); + if (char === CHAR_LINE_FEED) { + hasLineBreak = true; + // Check if any line can be folded. + if (shouldTrackWidth) { + hasFoldableLine = hasFoldableLine || + // Foldable line = too long, and not more-indented. + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' '); + previousLineBreak = i; + } + } else if (!isPrintable(char)) { + return STYLE_DOUBLE; + } + plain = plain && isPlainSafe(char, prevChar, inblock); + prevChar = char; + } + // in case the end is missing a \n + hasFoldableLine = hasFoldableLine || (shouldTrackWidth && + (i - previousLineBreak - 1 > lineWidth && + string[previousLineBreak + 1] !== ' ')); + } + // Although every style can represent \n without escaping, prefer block styles + // for multiline, since they're more readable and they don't add empty lines. + // Also prefer folding a super-long line. + if (!hasLineBreak && !hasFoldableLine) { + // Strings interpretable as another type have to be quoted; + // e.g. the string 'true' vs. the boolean true. + if (plain && !forceQuotes && !testAmbiguousType(string)) { + return STYLE_PLAIN; + } + return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE; + } + // Edge case: block indentation indicator can only have one digit. + if (indentPerLevel > 9 && needIndentIndicator(string)) { + return STYLE_DOUBLE; + } + // At this point we know block styles are valid. + // Prefer literal style unless we want to fold. + if (!forceQuotes) { + return hasFoldableLine ? STYLE_FOLDED : STYLE_LITERAL; + } + return quotingType === QUOTING_TYPE_DOUBLE ? STYLE_DOUBLE : STYLE_SINGLE; +} + +// Note: line breaking/folding is implemented for only the folded style. +// NB. We drop the last trailing newline (if any) of a returned block scalar +// since the dumper adds its own newline. This always works: +// • No ending newline => unaffected; already using strip "-" chomping. +// • Ending newline => removed then restored. +// Importantly, this keeps the "+" chomp indicator from gaining an extra line. +function writeScalar(state, string, level, iskey, inblock) { + state.dump = (function () { + if (string.length === 0) { + return state.quotingType === QUOTING_TYPE_DOUBLE ? '""' : "''"; + } + if (!state.noCompatMode) { + if (DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1 || DEPRECATED_BASE60_SYNTAX.test(string)) { + return state.quotingType === QUOTING_TYPE_DOUBLE ? ('"' + string + '"') : ("'" + string + "'"); + } + } + + var indent = state.indent * Math.max(1, level); // no 0-indent scalars + // As indentation gets deeper, let the width decrease monotonically + // to the lower bound min(state.lineWidth, 40). + // Note that this implies + // state.lineWidth ≤ 40 + state.indent: width is fixed at the lower bound. + // state.lineWidth > 40 + state.indent: width decreases until the lower bound. + // This behaves better than a constant minimum width which disallows narrower options, + // or an indent threshold which causes the width to suddenly increase. + var lineWidth = state.lineWidth === -1 + ? -1 : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent); + + // Without knowing if keys are implicit/explicit, assume implicit for safety. + var singleLineOnly = iskey + // No block styles in flow mode. + || (state.flowLevel > -1 && level >= state.flowLevel); + function testAmbiguity(string) { + return testImplicitResolving(state, string); + } + + switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth, + testAmbiguity, state.quotingType, state.forceQuotes && !iskey, inblock)) { + + case STYLE_PLAIN: + return string; + case STYLE_SINGLE: + return "'" + string.replace(/'/g, "''") + "'"; + case STYLE_LITERAL: + return '|' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(string, indent)); + case STYLE_FOLDED: + return '>' + blockHeader(string, state.indent) + + dropEndingNewline(indentString(foldString(string, lineWidth), indent)); + case STYLE_DOUBLE: + return '"' + escapeString(string) + '"'; + default: + throw new exception('impossible error: invalid scalar style'); + } + }()); +} + +// Pre-conditions: string is valid for a block scalar, 1 <= indentPerLevel <= 9. +function blockHeader(string, indentPerLevel) { + var indentIndicator = needIndentIndicator(string) ? String(indentPerLevel) : ''; + + // note the special case: the string '\n' counts as a "trailing" empty line. + var clip = string[string.length - 1] === '\n'; + var keep = clip && (string[string.length - 2] === '\n' || string === '\n'); + var chomp = keep ? '+' : (clip ? '' : '-'); + + return indentIndicator + chomp + '\n'; +} + +// (See the note for writeScalar.) +function dropEndingNewline(string) { + return string[string.length - 1] === '\n' ? string.slice(0, -1) : string; +} + +// Note: a long line without a suitable break point will exceed the width limit. +// Pre-conditions: every char in str isPrintable, str.length > 0, width > 0. +function foldString(string, width) { + // In folded style, $k$ consecutive newlines output as $k+1$ newlines— + // unless they're before or after a more-indented line, or at the very + // beginning or end, in which case $k$ maps to $k$. + // Therefore, parse each chunk as newline(s) followed by a content line. + var lineRe = /(\n+)([^\n]*)/g; + + // first line (possibly an empty line) + var result = (function () { + var nextLF = string.indexOf('\n'); + nextLF = nextLF !== -1 ? nextLF : string.length; + lineRe.lastIndex = nextLF; + return foldLine(string.slice(0, nextLF), width); + }()); + // If we haven't reached the first content line yet, don't add an extra \n. + var prevMoreIndented = string[0] === '\n' || string[0] === ' '; + var moreIndented; + + // rest of the lines + var match; + while ((match = lineRe.exec(string))) { + var prefix = match[1], line = match[2]; + moreIndented = (line[0] === ' '); + result += prefix + + (!prevMoreIndented && !moreIndented && line !== '' + ? '\n' : '') + + foldLine(line, width); + prevMoreIndented = moreIndented; + } + + return result; +} + +// Greedy line breaking. +// Picks the longest line under the limit each time, +// otherwise settles for the shortest line over the limit. +// NB. More-indented lines *cannot* be folded, as that would add an extra \n. +function foldLine(line, width) { + if (line === '' || line[0] === ' ') return line; + + // Since a more-indented line adds a \n, breaks can't be followed by a space. + var breakRe = / [^ ]/g; // note: the match index will always be <= length-2. + var match; + // start is an inclusive index. end, curr, and next are exclusive. + var start = 0, end, curr = 0, next = 0; + var result = ''; + + // Invariants: 0 <= start <= length-1. + // 0 <= curr <= next <= max(0, length-2). curr - start <= width. + // Inside the loop: + // A match implies length >= 2, so curr and next are <= length-2. + while ((match = breakRe.exec(line))) { + next = match.index; + // maintain invariant: curr - start <= width + if (next - start > width) { + end = (curr > start) ? curr : next; // derive end <= length-2 + result += '\n' + line.slice(start, end); + // skip the space that was output as \n + start = end + 1; // derive start <= length-1 + } + curr = next; + } + + // By the invariants, start <= length-1, so there is something left over. + // It is either the whole string or a part starting from non-whitespace. + result += '\n'; + // Insert a break if the remainder is too long and there is a break available. + if (line.length - start > width && curr > start) { + result += line.slice(start, curr) + '\n' + line.slice(curr + 1); + } else { + result += line.slice(start); + } + + return result.slice(1); // drop extra \n joiner +} + +// Escapes a double-quoted string. +function escapeString(string) { + var result = ''; + var char = 0; + var escapeSeq; + + for (var i = 0; i < string.length; char >= 0x10000 ? i += 2 : i++) { + char = codePointAt(string, i); + escapeSeq = ESCAPE_SEQUENCES[char]; + + if (!escapeSeq && isPrintable(char)) { + result += string[i]; + if (char >= 0x10000) result += string[i + 1]; + } else { + result += escapeSeq || encodeHex(char); + } + } + + return result; +} + +function writeFlowSequence(state, level, object) { + var _result = '', + _tag = state.tag, + index, + length, + value; + + for (index = 0, length = object.length; index < length; index += 1) { + value = object[index]; + + if (state.replacer) { + value = state.replacer.call(object, String(index), value); + } + + // Write only valid elements, put null instead of invalid elements. + if (writeNode(state, level, value, false, false) || + (typeof value === 'undefined' && + writeNode(state, level, null, false, false))) { + + if (_result !== '') _result += ',' + (!state.condenseFlow ? ' ' : ''); + _result += state.dump; + } + } + + state.tag = _tag; + state.dump = '[' + _result + ']'; +} + +function writeBlockSequence(state, level, object, compact) { + var _result = '', + _tag = state.tag, + index, + length, + value; + + for (index = 0, length = object.length; index < length; index += 1) { + value = object[index]; + + if (state.replacer) { + value = state.replacer.call(object, String(index), value); + } + + // Write only valid elements, put null instead of invalid elements. + if (writeNode(state, level + 1, value, true, true, false, true) || + (typeof value === 'undefined' && + writeNode(state, level + 1, null, true, true, false, true))) { + + if (!compact || _result !== '') { + _result += generateNextLine(state, level); + } + + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + _result += '-'; + } else { + _result += '- '; + } + + _result += state.dump; + } + } + + state.tag = _tag; + state.dump = _result || '[]'; // Empty sequence if no valid values. +} + +function writeFlowMapping(state, level, object) { + var _result = '', + _tag = state.tag, + objectKeyList = Object.keys(object), + index, + length, + objectKey, + objectValue, + pairBuffer; + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + + pairBuffer = ''; + if (_result !== '') pairBuffer += ', '; + + if (state.condenseFlow) pairBuffer += '"'; + + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; + + if (state.replacer) { + objectValue = state.replacer.call(object, objectKey, objectValue); + } + + if (!writeNode(state, level, objectKey, false, false)) { + continue; // Skip this pair because of invalid key; + } + + if (state.dump.length > 1024) pairBuffer += '? '; + + pairBuffer += state.dump + (state.condenseFlow ? '"' : '') + ':' + (state.condenseFlow ? '' : ' '); + + if (!writeNode(state, level, objectValue, false, false)) { + continue; // Skip this pair because of invalid value. + } + + pairBuffer += state.dump; + + // Both key and value are valid. + _result += pairBuffer; + } + + state.tag = _tag; + state.dump = '{' + _result + '}'; +} + +function writeBlockMapping(state, level, object, compact) { + var _result = '', + _tag = state.tag, + objectKeyList = Object.keys(object), + index, + length, + objectKey, + objectValue, + explicitPair, + pairBuffer; + + // Allow sorting keys so that the output file is deterministic + if (state.sortKeys === true) { + // Default sorting + objectKeyList.sort(); + } else if (typeof state.sortKeys === 'function') { + // Custom sort function + objectKeyList.sort(state.sortKeys); + } else if (state.sortKeys) { + // Something is wrong + throw new exception('sortKeys must be a boolean or a function'); + } + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + pairBuffer = ''; + + if (!compact || _result !== '') { + pairBuffer += generateNextLine(state, level); + } + + objectKey = objectKeyList[index]; + objectValue = object[objectKey]; + + if (state.replacer) { + objectValue = state.replacer.call(object, objectKey, objectValue); + } + + if (!writeNode(state, level + 1, objectKey, true, true, true)) { + continue; // Skip this pair because of invalid key. + } + + explicitPair = (state.tag !== null && state.tag !== '?') || + (state.dump && state.dump.length > 1024); + + if (explicitPair) { + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += '?'; + } else { + pairBuffer += '? '; + } + } + + pairBuffer += state.dump; + + if (explicitPair) { + pairBuffer += generateNextLine(state, level); + } + + if (!writeNode(state, level + 1, objectValue, true, explicitPair)) { + continue; // Skip this pair because of invalid value. + } + + if (state.dump && CHAR_LINE_FEED === state.dump.charCodeAt(0)) { + pairBuffer += ':'; + } else { + pairBuffer += ': '; + } + + pairBuffer += state.dump; + + // Both key and value are valid. + _result += pairBuffer; + } + + state.tag = _tag; + state.dump = _result || '{}'; // Empty mapping if no valid pairs. +} + +function detectType(state, object, explicit) { + var _result, typeList, index, length, type, style; + + typeList = explicit ? state.explicitTypes : state.implicitTypes; + + for (index = 0, length = typeList.length; index < length; index += 1) { + type = typeList[index]; + + if ((type.instanceOf || type.predicate) && + (!type.instanceOf || ((typeof object === 'object') && (object instanceof type.instanceOf))) && + (!type.predicate || type.predicate(object))) { + + if (explicit) { + if (type.multi && type.representName) { + state.tag = type.representName(object); + } else { + state.tag = type.tag; + } + } else { + state.tag = '?'; + } + + if (type.represent) { + style = state.styleMap[type.tag] || type.defaultStyle; + + if (_toString.call(type.represent) === '[object Function]') { + _result = type.represent(object, style); + } else if (_hasOwnProperty.call(type.represent, style)) { + _result = type.represent[style](object, style); + } else { + throw new exception('!<' + type.tag + '> tag resolver accepts not "' + style + '" style'); + } + + state.dump = _result; + } + + return true; + } + } + + return false; +} + +// Serializes `object` and writes it to global `result`. +// Returns true on success, or false on invalid object. +// +function writeNode(state, level, object, block, compact, iskey, isblockseq) { + state.tag = null; + state.dump = object; + + if (!detectType(state, object, false)) { + detectType(state, object, true); + } + + var type = _toString.call(state.dump); + var inblock = block; + var tagStr; + + if (block) { + block = (state.flowLevel < 0 || state.flowLevel > level); + } + + var objectOrArray = type === '[object Object]' || type === '[object Array]', + duplicateIndex, + duplicate; + + if (objectOrArray) { + duplicateIndex = state.duplicates.indexOf(object); + duplicate = duplicateIndex !== -1; + } + + if ((state.tag !== null && state.tag !== '?') || duplicate || (state.indent !== 2 && level > 0)) { + compact = false; + } + + if (duplicate && state.usedDuplicates[duplicateIndex]) { + state.dump = '*ref_' + duplicateIndex; + } else { + if (objectOrArray && duplicate && !state.usedDuplicates[duplicateIndex]) { + state.usedDuplicates[duplicateIndex] = true; + } + if (type === '[object Object]') { + if (block && (Object.keys(state.dump).length !== 0)) { + writeBlockMapping(state, level, state.dump, compact); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump; + } + } else { + writeFlowMapping(state, level, state.dump); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; + } + } + } else if (type === '[object Array]') { + if (block && (state.dump.length !== 0)) { + if (state.noArrayIndent && !isblockseq && level > 0) { + writeBlockSequence(state, level - 1, state.dump, compact); + } else { + writeBlockSequence(state, level, state.dump, compact); + } + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + state.dump; + } + } else { + writeFlowSequence(state, level, state.dump); + if (duplicate) { + state.dump = '&ref_' + duplicateIndex + ' ' + state.dump; + } + } + } else if (type === '[object String]') { + if (state.tag !== '?') { + writeScalar(state, state.dump, level, iskey, inblock); + } + } else if (type === '[object Undefined]') { + return false; + } else { + if (state.skipInvalid) return false; + throw new exception('unacceptable kind of an object to dump ' + type); + } + + if (state.tag !== null && state.tag !== '?') { + // Need to encode all characters except those allowed by the spec: + // + // [35] ns-dec-digit ::= [#x30-#x39] /* 0-9 */ + // [36] ns-hex-digit ::= ns-dec-digit + // | [#x41-#x46] /* A-F */ | [#x61-#x66] /* a-f */ + // [37] ns-ascii-letter ::= [#x41-#x5A] /* A-Z */ | [#x61-#x7A] /* a-z */ + // [38] ns-word-char ::= ns-dec-digit | ns-ascii-letter | “-” + // [39] ns-uri-char ::= “%” ns-hex-digit ns-hex-digit | ns-word-char | “#” + // | “;” | “/” | “?” | “:” | “@” | “&” | “=” | “+” | “$” | “,” + // | “_” | “.” | “!” | “~” | “*” | “'” | “(” | “)” | “[” | “]” + // + // Also need to encode '!' because it has special meaning (end of tag prefix). + // + tagStr = encodeURI( + state.tag[0] === '!' ? state.tag.slice(1) : state.tag + ).replace(/!/g, '%21'); + + if (state.tag[0] === '!') { + tagStr = '!' + tagStr; + } else if (tagStr.slice(0, 18) === 'tag:yaml.org,2002:') { + tagStr = '!!' + tagStr.slice(18); + } else { + tagStr = '!<' + tagStr + '>'; + } + + state.dump = tagStr + ' ' + state.dump; + } + } + + return true; +} + +function getDuplicateReferences(object, state) { + var objects = [], + duplicatesIndexes = [], + index, + length; + + inspectNode(object, objects, duplicatesIndexes); + + for (index = 0, length = duplicatesIndexes.length; index < length; index += 1) { + state.duplicates.push(objects[duplicatesIndexes[index]]); + } + state.usedDuplicates = new Array(length); +} + +function inspectNode(object, objects, duplicatesIndexes) { + var objectKeyList, + index, + length; + + if (object !== null && typeof object === 'object') { + index = objects.indexOf(object); + if (index !== -1) { + if (duplicatesIndexes.indexOf(index) === -1) { + duplicatesIndexes.push(index); + } + } else { + objects.push(object); + + if (Array.isArray(object)) { + for (index = 0, length = object.length; index < length; index += 1) { + inspectNode(object[index], objects, duplicatesIndexes); + } + } else { + objectKeyList = Object.keys(object); + + for (index = 0, length = objectKeyList.length; index < length; index += 1) { + inspectNode(object[objectKeyList[index]], objects, duplicatesIndexes); + } + } + } + } +} + +function dump$1(input, options) { + options = options || {}; + + var state = new State(options); + + if (!state.noRefs) getDuplicateReferences(input, state); + + var value = input; + + if (state.replacer) { + value = state.replacer.call({ '': value }, '', value); + } + + if (writeNode(state, 0, value, true, true)) return state.dump + '\n'; + + return ''; +} + +var dump_1 = dump$1; + +var dumper = { + dump: dump_1 +}; + +function renamed(from, to) { + return function () { + throw new Error('Function yaml.' + from + ' is removed in js-yaml 4. ' + + 'Use yaml.' + to + ' instead, which is now safe by default.'); + }; +} + + +var Type = type; +var Schema = schema; +var FAILSAFE_SCHEMA = failsafe; +var JSON_SCHEMA = json; +var CORE_SCHEMA = core; +var DEFAULT_SCHEMA = _default; +var load = loader.load; +var loadAll = loader.loadAll; +var dump = dumper.dump; +var YAMLException = exception; + +// Re-export all types in case user wants to create custom schema +var types = { + binary: binary, + float: float, + map: map, + null: _null, + pairs: pairs, + set: set, + timestamp: timestamp, + bool: bool, + int: int, + merge: merge, + omap: omap, + seq: seq, + str: str +}; + +// Removed functions from JS-YAML 3.0.x +var safeLoad = renamed('safeLoad', 'load'); +var safeLoadAll = renamed('safeLoadAll', 'loadAll'); +var safeDump = renamed('safeDump', 'dump'); + +var jsYaml = { + Type: Type, + Schema: Schema, + FAILSAFE_SCHEMA: FAILSAFE_SCHEMA, + JSON_SCHEMA: JSON_SCHEMA, + CORE_SCHEMA: CORE_SCHEMA, + DEFAULT_SCHEMA: DEFAULT_SCHEMA, + load: load, + loadAll: loadAll, + dump: dump, + YAMLException: YAMLException, + types: types, + safeLoad: safeLoad, + safeLoadAll: safeLoadAll, + safeDump: safeDump +}; + +export default jsYaml; +export { CORE_SCHEMA, DEFAULT_SCHEMA, FAILSAFE_SCHEMA, JSON_SCHEMA, Schema, Type, YAMLException, dump, load, loadAll, safeDump, safeLoad, safeLoadAll, types }; diff --git a/custom_components/opendisplay/designer/frontend/vendor/odl-drawcustom-designer.d.ts b/custom_components/opendisplay/designer/frontend/vendor/odl-drawcustom-designer.d.ts new file mode 100644 index 00000000..6d559c4c --- /dev/null +++ b/custom_components/opendisplay/designer/frontend/vendor/odl-drawcustom-designer.d.ts @@ -0,0 +1,799 @@ +export declare type AssetKind = 'font' | 'image'; + +/** + * Read-only snapshot of designer status (issue #133, ADR-018's observability + * clause: "state flows out via a read handle plus optional change + * notification; status is derived, never authoritative, and carries no + * designer internals"). Answers "is the YAML good, what did the user just do, + * how much has changed" without exposing elements, YAML text or any other + * internal shape. + * + * Deliberately small — grow it by maintainer ruling, not speculation. + * Frozen: a later status is always a new object, never a mutation of one a + * host already holds. + */ +export declare interface DesignerStatus { + /** Whether the current YAML document parses and validates. */ + readonly yamlValid: boolean; + /** + * A one-line description of the first validation problem, truncated to its + * first `\n`-delimited line if the underlying parser error is not (a raw + * YAML syntax error's message can carry a multi-line caret diagram + * pointing at the offending column). Present only while + * {@link DesignerStatus.yamlValid} is `false` — a valid document carries no + * summary rather than an empty or stale one. + */ + readonly yamlErrorSummary?: string; + /** + * Epoch ms, in the **host's** clock domain (`Date.now()` at the moment of + * the edit) — never a designer-internal or build-time value — of the last + * user-originated change: typing committed to the canvas, a canvas drag, a + * property-panel edit, undo/redo. `null` before the user has made any edit + * during this mount. + * + * Never bumped by a host push (`setPayload()`, `setStates()`, …) — a push is + * the host acting on the designer, not the user acting on it. + */ + readonly lastEditAt: number | null; + /** + * Monotonic counter, incremented once per committed payload change — + * whether it came from the user (typing, a drag, undo/redo) or from a host + * `setPayload()` push. A host that only needs "has anything changed since I + * last looked" can diff this number instead of diffing YAML strings. + * + * Granularity, precisely: + * + * - **One drag or property-panel drag gesture is one revision**, not one + * per pointermove — coalesced the same way the gesture's undo-history + * entry is (`beginEditCoalesce`/`endEditCoalesce`), applied once when the + * gesture ends. A gesture that starts and ends without net change bumps + * nothing. + * - **A `setPayload()` push with a structurally equal payload (element-wise) + * is a no-op for the revision** — dedupe before commit, the same + * full-bail pattern the `states`/`actions` channels use for an unchanged + * re-push (issue #110): no revision bump, no reset undo history, no + * cleared selection. Formatting/comment-only YAML differences dedupe too + * (the comparison is over parsed elements, not the YAML text). **Except** + * while a pending, not-yet-committed YAML edit the user was typing before + * this push exists: `setPayload()` is authoritative over an in-flight + * draft regardless of whether the pushed payload turns out to match + * what's already committed, so the draft is **always** discarded, deduped + * or not — and when there was a real draft to discard, the dedupe is + * skipped entirely and the push takes the full apply path instead, + * which **does** bump the revision even though the committed elements + * end up structurally the same as before. This is deliberate, not an + * inconsistency: the push observably changed something (the draft the + * editor was showing is gone, replaced by a fresh sync of the pushed + * payload) — a plain content comparison alone would miss that and leave + * the editor's on-screen text uncorrected. + * - Every other committed change (a single keystroke's debounced commit, a + * click-driven property edit, undo, redo, a genuinely different + * `setPayload()` push) bumps exactly once. + */ + readonly payloadRevision: number; + /** How many elements are currently selected on the canvas. */ + readonly selectedElementCount: number; +} + +/** Theme applied to the mount container (never `document.documentElement`). */ +export declare type EmbedTheme = 'light' | 'dark'; + +/** + * One host-registered toolbar button (issue #108, ADR-018 actions seam). + * + * The host owns what the button means; the designer owns how it looks and + * reports which one fired, with the current payload (`onAction`). This is a + * typed, closed button list — deliberately not a plugin API: no host markup, + * styles or components ever enter the designer's shadow root (ADR-017). + */ +export declare interface HostAction { + /** + * Opaque, host-defined identity, echoed back by `onAction`. Also the list's + * diff key: re-pushing the same id updates that button in place rather than + * replacing it. Must be unique within a push. + */ + id: string; + /** Button text, shown as-is (surrounding whitespace trimmed). Also its accessible name. */ + label: string; + /** + * Optional [Material Design Icon](https://pictogrammer.com/library/mdi/) + * name — the same vocabulary a payload `icon` element accepts, resolved + * the same way (`mdi:` prefix optional, e.g. `send`, `mdi:home-assistant`). + * The designer bundles the full MDI set for the payload's icon element + * anyway, so every one of those names is available to a host at no added + * bundle size and with no icon dependency of its own. An unknown name is + * rejected, not ignored. + */ + icon?: string; + /** Button chrome; defaults to `'normal'`. */ + severity?: HostActionSeverity; + /** + * Whether this action reads the designer's payload; defaults to `true`. + * + * A payload-carrying action is disabled while the YAML editor is blocked by + * a parse/schema error. An action that does *not* need the payload + * (host-side settings, a reconnect, a help link) sets `false` and stays + * clickable throughout; it still receives the last valid payload, exactly + * as {@link MountHandle.getPayload} documents for a blocked document. + */ + needsPayload?: boolean; + /** + * When set, the button renders visibly disabled and this text is what the + * user gets on hover ("Display offline", "No target selected"). Clearing it + * in a later push re-enables the button — this is the field hosts re-push + * as their own state changes. + */ + disabledReason?: string; +} + +/** + * Third argument of `onAction` — the opaque ids and live display/render + * state that accompany the payload. + */ +export declare interface HostActionContext { + /** + * The selected target's opaque host id (issue #106), or `undefined` when + * the design is not pinned to one — no targets pushed, none picked yet, or + * the user switched to the virtual display. Always the same value the last + * {@link MountOptions.onTargetSelected} call reported. + */ + readonly targetId?: string; + /** + * The logical drawing surface the payload is authored against, at the + * instant the action fired — the exact same {@link HostDisplayGeometry} + * shape {@link HostPreviewContext} carries, and equal to it in the same + * instant (issue #105, WYSIWYG-send slice). Always present: a canvas + * re-orientation or resolution pick changes what an action sends exactly as + * it changes what a preview request asks for — there is no separate, + * possibly-stale copy for actions to fall back on. + */ + readonly display: HostDisplayGeometry; + /** + * The rasterization options in effect at the instant the action fired — the + * same {@link HostRenderOptions} shape {@link HostPreviewContext} carries, + * so a host reads one shape for both channels rather than two that happen to + * agree. Always present, for the same reason `display` is (issue #105): + * before this, an `onAction` handler had nowhere to read the designer's own + * dither control from, so a host reaching for WYSIWYG send had no choice but + * to remember the last preview request's `render` — sticky and invisible, + * and wrong the moment the control changes with the preview off or unused. + * `dither` is the only field this slice carries; the rest of the option set + * (background, ttl, …) is the rest of issue #105. + */ + readonly render: HostRenderOptions; +} + +/** + * Fired when the user clicks a host-registered action. Save and send are host + * actions — the designer has no save channel of its own (ADR-018). + * + * `payload` is the current drawcustom YAML — the exact string + * {@link MountHandle.getPayload} returns at that instant (same serializer, + * same pending-edit flush), so a host never has to reconcile two readings of + * the same design. + */ +export declare type HostActionHandler = (id: string, payload: string, context: HostActionContext) => void; + +/** + * How prominently an action's button warns before it is clicked (issue #108, + * ADR-018): + * + * - `'normal'` (default) — regular button chrome. + * - `'caution'` — orange: the action reaches beyond the designer, e.g. the + * OpenDisplay integration's Send-to-display drives physical hardware. + * - `'danger'` — red: the action destroys or overwrites something. + * + * Severity is *presentation only*. The designer never infers meaning from it + * — confirmation, auth and the actual call stay host-side. + */ +export declare type HostActionSeverity = 'normal' | 'caution' | 'danger'; + +/** + * Host asset resolver — the LAST tier of asset resolution (issue #138, + * ADR-002 amendment). + * + * A payload may reference fonts and images by bare name (`Ubuntu-R.ttf`, + * `logo.png`): that is how hand-written drawcustom payloads address the + * integration's own font/media directories. The designer cannot know those + * directories, so an embedding host supplies a resolver and the designer asks + * it for any reference it could not resolve locally: + * + * 1. local content map (uploaded via Content Manager, ADR-002) + * 2. bundled assets (`ppb.ttf`, `rbm.ttf`, the showcase image) + * 3. **this tier** — the host, by name + * + * The contract is deliberately `name -> asset`: search paths, media + * directories and integration layout are the HOST's business, so the designer + * learns no domain vocabulary (ADR-018). A `null` answer, a rejection, a + * silence past {@link HOST_ASSET_TIMEOUT_MS} or an out-of-contract value all + * settle as "not supplied" and reach the user as the existing explicit + * render-error state for the element referencing it — never a silent skip and + * never a plausible-looking wrong render (issue #10). + */ +export declare type HostAssetResolver = (kind: AssetKind, name: string) => Promise; + +/** + * The **logical drawing surface** the payload is authored against — the + * coordinate space its `x`/`y` values live in, and therefore what a host has to + * render at for the image to mean anything beside the design. + * + * Already oriented: {@link HostDisplayGeometry.width}/`height` are + * swapped for a quarter turn (issue #139), exactly as upstream `imagegen` + * creates its canvas before drawing, and `rotation` says which way round the + * panel holds that surface. Never the raw physical panel size, and never a + * transform to apply to the returned image. + */ +export declare interface HostDisplayGeometry { + readonly width: number; + readonly height: number; + /** The orientation `width`/`height` are already expressed in. */ + readonly rotation: 0 | 90 | 180 | 270; +} + +/** + * What a display *is* — the host's declaration of the panel, driving canvas + * setup, carried by every {@link HostTarget}. All fields optional; anything a + * display does not declare comes from the designer's canonical defaults, never + * from the display previously in effect. + * + * The designer owns this contract; a host adapts its own data to it, not the + * other way round — camelCase throughout, like every other published type + * (maintainer ruling 2026-08-31: the PR100 exploration this shape once + * mirrored was never live and is inspiration, not authority; with a major + * bump there is no reason for one published interface to read differently + * from the rest). + */ +export declare interface HostDisplaySpec { + /** Physical panel width in pixels (before rotation). */ + pixelWidth?: number; + /** Physical panel height in pixels (before rotation). */ + pixelHeight?: number; + /** Mounting rotation in degrees; only quarter turns are representable. */ + rotationDegrees?: number; + /** Drawing-surface width after rotation; preferred over pixelWidth. */ + renderWidth?: number; + /** Drawing-surface height after rotation; preferred over pixelHeight. */ + renderHeight?: number; + /** OpenDisplay Basic Standard colour scheme (0x00 BW … 0x04 six-color). */ + colorScheme?: number; + /** Accent color name, e.g. 'red' or 'yellow'. */ + accentColor?: string; + /** Palette color names, e.g. ['black', 'white', 'red']. */ + availableColors?: string[]; + /** Palette name -> hex map, e.g. { black: '#000000', … }. */ + colorMap?: Record; + /** Whether the palette hexes were measured on real hardware. */ + paletteMeasured?: boolean; +} + +/** + * Second argument of {@link HostPreviewRenderer} — the same + * "payload plus opaque ids" shape {@link HostActionContext} carries, extended + * with the geometry and the render options the render depends on. + */ +export declare interface HostPreviewContext { + /** + * The selected target's opaque host id (issue #106), or `undefined` when the + * design is not pinned to one — exactly the value {@link HostActionContext} + * reports at the same instant. + */ + targetId?: string; + /** + * The canvas the payload is authored against. Always present: a payload's + * coordinates are meaningless without the surface they refer to, and the + * designer always knows it — a display-config change (resolution pick, + * re-orientation) re-requests the render, so a provider that renders at its + * own idea of the size answers a changed request with an image of the wrong + * shape, which the designer letterboxes visibly rather than stretching. + */ + display: HostDisplayGeometry; + /** + * The rasterization options this render must honour. Always present — the + * designer always knows its own dither mode, so a host never has to guard + * for it. + */ + render: HostRenderOptions; +} + +/** + * Renders the current payload host-side and hands the finished image back + * (issue #109, ADR-018 preview seam). + * + * When a host supplies one, the designer offers a **Display preview** toggle + * next to its canvas heading; turning it on replaces the designer's own + * client-side preview with this image — a real server-side render, not another + * client approximation, which is what makes it usable as the + * [ADR-007](../../docs/adr/ADR-007-hybrid-rendering.md) pixel-parity + * reference. Every edit affordance is inert while it shows; Copy/Download PNG, + * zoom and the dither control keep working, and dither re-requests. + * + * - Resolve with a `Blob` (`image/png`, `image/*`) or with a URL string + * (`data:`, `blob:`, `http(s):`) the designer can point an `` at. A + * URL must be readable by the host page for Copy/Download PNG to reach the + * bytes. + * - **Reject to report failure.** The designer shows an explicit error in the + * preview area — the rejection's `message` when it has one — and shows no + * image at all: a stated error beats a stale or wrong render. + * - Called again (debounced) whenever anything it was given changes while the + * preview shows: a `setPayload()` push, the display config (resolution, + * orientation), the selected target, the dither option. Responses are matched + * to their request, so a slow answer that a newer request has already + * superseded is discarded rather than painted. + * - Must be a function when supplied — anything else throws out of `mount()`, + * like a malformed action or target list does. + * + * A stable closure fixed at mount: ADR-018 pushes data, never functions. + */ +export declare type HostPreviewRenderer = (payload: string, context: HostPreviewContext) => Promise; + +/** + * The rasterization options a host-side render must honour, carried by every + * {@link HostPreviewContext} and every {@link HostActionContext} (issue #109 / + * issue #105, ADR-018 preview and actions seams). + * + * Deliberately minimal: the designer sends the options it actually owns a + * control for. The full option set is formalized in + * [issue #105](https://github.com/schlomo/odl-drawcustom-designer/issues/105) + * — this object is where it lands, and it grows additively (a host reads the + * fields it knows). + */ +export declare interface HostRenderOptions { + /** + * The dither mode the designer's own dither control currently holds, in the + * drawcustom `dither` service option's own domain (`src/core/schema/service.ts`): + * `0` flat, `1`, `2` ordered halftone. The designer's preview control + * produces `0` or `2` today. + * + * A provider **must** honour it: changing the control re-requests the + * preview, so a provider that ignores the value answers a changed request + * with an unchanged image and the designer shows a preview that contradicts + * its own dither setting. + */ + readonly dither: 0 | 1 | 2; +} + +/** A pushed state value with optional attributes and an optional display name. */ +export declare interface HostState { + state: string | number | boolean; + attributes?: Record; + /** + * Human-readable label for this state key (issue #107, ADR-018 state + * catalog) — what the referenced-states panel shows instead of the raw key + * ("Living-room temperature", not `sensor.demo_temperature`). + * + * Presentation only, and re-pushable like every other field: templates never + * see it (a payload reads `states()`/`state_attr()`, which are unaffected by + * whether the host named the key), and the designer never parses meaning out + * of it. Surrounding whitespace is trimmed; a blank name counts as none, and + * an unnamed key shows as its key. + */ + name?: string; +} + +/** + * Host-pushed states: state key -> state value or {state, attributes, name}. + * The keys are the host's own identifiers, opaque to the designer — they are + * what a payload's templates name (`states('…')`, `state_attr('…', '…')`). + * + * When provided, this **replaces the State Simulator entirely** (issue #107, + * ADR-018 Simulator policy): the designer shows a read-only referenced-states + * panel instead, and the full catalog stays reachable through YAML/template + * autocomplete. + * + * Ownership contract (issue #110): treated as an **immutable snapshot** at + * the moment `setStates()` is called. Repeated pushes are diffed + * structurally against the previously applied object to keep a 4x/s + * full-registry push cheap (no re-render, no template re-evaluation when + * nothing changed) — that diff compares by value against the retained + * reference, not by cloning, so **mutate-and-repush is unsupported**: + * mutating this same object in place and calling `setStates()` again with + * that reference is invisible to the diff and silently treated as + * "unchanged". Construct a fresh object per push instead (see + * docs/embedding.md's `states` section). + */ +export declare type HostStates = Record; + +/** + * Fired on a status transition (issue #133) — a YAML validity flip or a + * {@link DesignerStatus.payloadRevision} change — debounced so a burst of + * keystrokes or drag updates yields one call, not one per commit. Not fired + * for a selection change alone, and not fired for the initial status observed + * at mount (read {@link MountHandle.getStatus} for that). Delivery is capped + * at 1 second after the first pending transition, however many times the + * debounce gets rescheduled in between — something that keeps re-triggering + * it without ever settling cannot postpone delivery indefinitely. + * + * The delivered status is always **live**: read fresh (and flushed, per + * {@link MountHandle.getStatus}) at the moment the debounce settles, never the + * value captured when the debounce was scheduled — a flip that reverts to the + * last-notified truth before the debounce settles delivers no call at all + * (there is nothing new to report), and a flip that settles on a different + * truth delivers exactly that, never an intermediate one from partway through + * the window. A host that reacts to this callback and calls + * {@link MountHandle.getStatus} inside it always sees the identical value. + * + * A stable closure fixed at mount, like `onAction`: ADR-018 pushes data, + * never functions, so there is no update channel for it. + */ +export declare type HostStatusChangeHandler = (status: DesignerStatus) => void; + +/** + * One display the host knows about (issue #106, ADR-018 targets seam) — the + * designer's single display channel. + * + * The host pushes the list, the designer renders a picker inside its own + * display-config area, and selecting an entry adopts that display's + * declared spec behind the existing lock (issue #70). A **one-element list is + * adopted and locked without a pick** (issue #121): that is how a + * single-display host says "this is the display". The id is **opaque**: it + * round-trips through `onTargetSelected` and `onAction`'s context untouched, + * and the designer never learns what it names (ADR-018: domain-neutral + * vocabulary — "target", never "entity"). + */ +export declare interface HostTarget { + /** + * Opaque, host-defined identity, echoed back by `onTargetSelected` and + * `onAction`. Also the list's diff key: re-pushing the same id keeps a + * selection on it. Must be unique within a push. + */ + id: string; + /** Picker entry text, shown as-is (surrounding whitespace trimmed). */ + label: string; + /** + * What this target *is* — the host's own declaration of the panel + * ({@link HostDisplaySpec}): pixel dimensions, mounting rotation, palette. + * The canvas, palette and orientation are set from it when this target is + * adopted. Only the documented fields are retained; the copy the designer + * keeps is frozen, so mutating the pushed object afterwards cannot change + * what the picker applies, and a re-push carrying different values is + * recognised as the host re-defining this display. + * + * Not to be confused with `display` on {@link HostActionContext} / + * {@link HostPreviewContext}, which is the *resolved* drawing surface + * ({@link HostDisplayGeometry}: `width`/`height`/`rotation`) the designer + * ended up with. Same panel, two ends of one pipeline — this is what the + * host declared, that is what the designer resolved it to. + */ + display: HostDisplaySpec; +} + +/** + * Called when the effective display target changes (issue #106). + * + * `null` means "no target": the user picked the virtual display, unlocked the + * display config, or has not picked anything yet. Fires only on a *change* — + * including the one a single-element `targets` push makes by adopting that + * display (issue #121) — and never as a side effect of a `setTargets` push + * that leaves the selection alone: a push that removes the selected display + * keeps it (marked stale) rather than switching. + * + * A stable closure fixed at mount: ADR-018 pushes data, never functions. + */ +export declare type HostTargetSelectedHandler = (targetId: string | null) => void; + +/** + * Mount the designer into an arbitrary host container (issue #20, ADR-010). + * Renders into an open shadow root on the container — created here, or + * reused when the host attached one already (issue #21) — so styles are + * isolated in both directions. + * + * The host pushes data through the returned handle; the designer never + * persists the payload itself — the host reads the current drawcustom YAML + * through `getPayload()`, or receives it with the action the user clicked + * (ADR-018). Invalid `payload` YAML throws synchronously (here and in + * `setPayload`). + * + * This is the embedded host adapter over {@link mountDesigner} (ADR-017); + * the standalone SPA is a sibling adapter over the same lifecycle. + */ +export declare function mount(container: HTMLElement, options?: MountOptions): MountHandle; + +export declare interface MountHandle { + /** + * The designer build's version (issue #23, reworked 2026-07-29: git tags + * are the sole version source, `package.json` stays pinned at `0.0.0`), + * e.g. `'1.0.0'`. A release build bakes in the tag-derived version via the + * `APP_VERSION` env var (the release pipeline sets it, `tools/version.ts` + * resolves it); any other build (local dev, CI `checks`) falls back to + * `'0.0.0-dev'`, and Vitest gets the fixed string `'test'`. Same value as + * the library's `version` export (`src/embed/index.ts`); handy when a host + * only has the handle. + */ + readonly version: string; + /** Unmount the designer and remove everything from the container. */ + destroy(): void; + /** + * Push a full replacement state map for template preview. Treat the passed + * object as an immutable snapshot — see `HostStates`'s ownership contract + * above; mutating it and calling `setStates()` again with the same reference + * is unsupported and gets treated as a no-op push. + * + * Throws on a malformed map (a non-primitive or missing `state`, a + * non-object `attributes`, a non-string `name`, or a `states` argument that + * is not an object) with a message naming the offending key, and **changes + * nothing** when it does: no values, no names, no Simulator-off latch, and + * the rejected map never becomes the last-applied push the diff compares + * against — so the same bad map fails again rather than being deduped, and a + * corrected one applies normally. + */ + setStates(states: HostStates): void; + /** Replace the current payload with new drawcustom YAML (throws on invalid YAML). */ + setPayload(payload: string): void; + /** + * Replace the host action buttons (issue #108). Everything pushed at mount + * is re-pushable (ADR-018), and this is the channel hosts use to keep + * labels and `disabledReason`s live: push the full list again whenever host + * state changes (connection lost, target deselected). The designer diffs — + * an unchanged list costs no re-render — and an empty list removes all + * action chrome. + * + * Throws on a malformed list (unknown `icon` or `severity`, missing or + * duplicate `id`, missing `label`) without changing what is on screen, and + * on any non-empty list when `mount()` was given no `onAction` — the + * handler is fixed at mount, so those buttons could never fire. + */ + setActions(actions: readonly HostAction[]): void; + /** + * Replace the display targets the picker offers (issue #106). Everything + * pushed at mount is re-pushable (ADR-018), and targets are the channel a + * host uses as its own display inventory changes: a display that appears + * shows up in the picker without a reload, and the designer diffs the list + * so an unchanged re-push costs no re-render. + * + * A **one-element** push is adopted and locked straight away (issue #121) — + * a single display is not a choice — but only while the user has made no + * display choice of their own; after that, nothing but a pick moves the + * canvas. + * + * Otherwise a push never moves the canvas on its own, and never overrides + * the user: if it **removes the currently selected target**, the designer keeps that + * display's last-known spec and lock state and marks the selection + * stale ("display no longer available") instead of silently switching or + * unlocking. Pushing the target back clears the stale marker. + * + * Throws on a malformed list (missing or duplicate `id`, missing `label`, + * missing `display`) without changing what is on screen. + */ + setTargets(targets: readonly HostTarget[]): void; + /** Switch the container-scoped theme. */ + setTheme(theme: EmbedTheme): void; + /** + * The designer's current drawcustom YAML payload (issue #104) — exactly the + * string an `onAction` callback receives at this instant. Same serializer, + * same underlying elements state; there is no second source of truth. + * + * - **Never returns `undefined`, and throws only after `destroy()`** — like + * every other method on this handle, it rejects a destroyed mount + * (`MountHandle used after destroy()`). On a live mount it always answers + * with a string, including in the brief window right after + * `mount()`/`mountStandaloneApp()` return but before React has committed + * and run its effects, when it reports the bootstrap payload the designer + * is about to render. + * - **Never lags a pending edit.** The YAML editor commits typed text to + * the canvas model on an 80ms debounce (or on blur); `getPayload()` + * forces that flush first, so a call made mid-keystroke reflects the + * text already typed — the same content an action click sends (a click + * blurs the editor, which flushes the debounce, before the payload is + * read). + * - **Never resurrects a pre-push draft.** A `setPayload()` push is + * authoritative: it discards any debounced edit typed before it, so the + * flush above can only ever commit text typed *after* the last push. + * - **While the YAML editor is blocked** by a parse/schema error (every + * payload-carrying action is disabled), returns the last valid payload — + * the canvas model is frozen there too, so this is exactly what the last + * action would have sent, and the only way to read anything at all. + * + * See [`docs/embedding.md`](../../docs/embedding.md#getpayload-issue-104) + * for the full semantics and rationale. + */ + getPayload(): string; + /** + * The designer's own rasterization of the current payload, right now — the + * exact bytes its own Copy PNG / Download PNG would produce outside + * Display preview, full font/renderer fidelity included. Exists so a host + * with no rendering backend of its own (a demo, a thin adapter) can answer + * `renderPreview` by reading this instead of writing a second renderer — + * the same "read access" fix {@link getPayload} is for reading the payload + * instead of driving the Save button. + * + * - **Independent of Display preview.** Always the client-side render, even + * while the toggle is on and a host image is showing — a `renderPreview` + * provider built on this can therefore never call itself. + * - **Rejects, never throws synchronously**, while the designer has not + * yet committed its first render (the brief window right after + * `mount()`/`mountStandaloneApp()` returns) — there is no bootstrap + * fallback for a raster the way {@link getPayload} falls back to + * serialized YAML, since fonts/assets have not loaded yet either. + * - Throws (does not reject) `MountHandle used after destroy()`, like every + * other method on this handle. + */ + getPngBlob(): Promise; + /** + * The designer's current status (issue #133, ADR-018's observability + * clause) — a small, frozen, derived snapshot; never authoritative, and it + * carries no designer internals (no elements, no YAML text). + * + * **Flushes a pending debounced YAML edit first**, exactly like + * {@link getPayload} does — the two must never disagree about whether there + * is unsaved, uncommitted text: a call made moments after typing already + * reflects the typed edit in `payloadRevision`/`lastEditAt`, not the state + * as of 80ms ago. Calling `getStatus()` before `getPayload()` or vice versa + * flushes the same way either order. + * + * Always answers synchronously, including in the brief pre-registration + * window right after `mount()`/`mountStandaloneApp()` returns — before that + * registration has run, reports a default status (`yamlValid: true`, no + * edits yet, revision `0`, nothing selected), the same "safe default before + * the shell exists" shape {@link getPayload}'s bootstrap fallback uses. + * Throws `MountHandle used after destroy()` like every other method here. + */ + getStatus(): DesignerStatus; +} + +export declare interface MountOptions { + /** Initial drawcustom YAML payload (list of draw elements). */ + payload?: string; + /** + * Initial states for template preview. A mount option *is* an initial push + * (ADR-018 seam grammar): identical to calling {@link MountHandle.setStates} + * before the first painted frame, validated the same way — a malformed map + * throws out of `mount()`, like an invalid `payload`. + */ + states?: HostStates; + /** Initial theme; defaults to 'light'. */ + theme?: EmbedTheme; + /** + * Initial host action buttons (issue #108). A mount option *is* an initial + * push (ADR-018 seam grammar): identical to calling + * {@link MountHandle.setActions} before the first painted frame, and + * re-pushable from then on. A malformed list throws out of `mount()`, like + * an invalid `payload`. + * + * Requires {@link MountOptions.onAction}: registering actions no one can + * hear about is rejected rather than rendered. + */ + actions?: readonly HostAction[]; + /** + * Called when the user clicks one of the {@link MountOptions.actions}. + * A stable closure — there is no update channel for it (ADR-018: data is + * pushed, functions are not) — which is why a mount without it can never + * take actions, at mount time or through a later `setActions()`. + */ + onAction?: HostActionHandler; + /** + * Initial display targets (issue #106) — the designer's only display + * channel. A mount option *is* an initial push (ADR-018 seam grammar): + * identical to calling {@link MountHandle.setTargets} before the first + * painted frame, and re-pushable from then on. A malformed list throws out + * of `mount()`, like an invalid `payload`. + * + * A list the user can choose between only says what they *can* pick — it + * never moves the canvas by itself. A **one-element** list says "this is the + * display": it is adopted and locked straight away, so a single-display host + * needs no pick and no seeding option (issue #121). + */ + targets?: readonly HostTarget[]; + /** + * Called when the selected display target changes, including to `null` for + * the virtual display. Optional: a host that only needs the id when + * something happens gets it from `onAction`'s context instead. Hosts that + * *react* to the selection — re-pushing `actions` with a + * `disabledReason: 'No display selected'`, say — want this. + */ + onTargetSelected?: HostTargetSelectedHandler; + /** + * Host-side render of the current payload (issue #109). Supplying one is + * what makes the designer offer its **Display preview** toggle at all — no + * provider, no toggle and no other visual trace, exactly like `actions` and + * `targets` (conditional chrome; standalone output is unchanged). + * + * A stable closure — there is no update channel for it (ADR-018: data is + * pushed, functions are not). + */ + renderPreview?: HostPreviewRenderer; + /** + * Resolve a font or image the designer could not resolve locally + * ([issue #138](https://github.com/schlomo/odl-drawcustom-designer/issues/138)). + * + * Payloads reference assets by the name the *host* understands + * (`Ubuntu-R.ttf`, `logo.png`) — for the OpenDisplay integration, a file in + * its font/media directories. The designer asks this closure for any + * reference left over after its own tiers (Content Manager uploads, bundled + * assets), and caches what comes back for the life of the mount: + * + * - a `Blob` — the asset's bytes (the safest answer: no CORS, no tainting); + * - a `string` — a URL the designer can load (data:, blob:, or same-origin); + * - `null` — "I don't have that", which surfaces as the designer's explicit + * render-error state on every element referencing the asset, naming it and + * saying the host could not supply it. A rejection reads the same way, + * with its reason. Never a silent skip, never a wrong render. + * + * Search paths, directory layout and permissions stay host-side: the + * contract is `name -> asset` and nothing else (ADR-018). A stable closure + * fixed at mount — like `onAction`, there is no update channel for it; an + * unresolvable name is retried after a short interval, so a host whose store + * comes back can answer differently without a remount. + */ + resolveAsset?: HostAssetResolver; + /** + * Declares that the host owns asset resolution (ADR-002 host asset + * resolver, issue #138) — set this when the host supplies + * {@link MountOptions.resolveAsset} (or otherwise resolves the payload's + * fonts and images itself). A designer-local upload lives only in that + * one browser's IndexedDB and never reaches the host: it renders fine on + * the canvas here and then fails the moment the design is sent, because + * whatever finally draws the image looks for it in the host's own + * directories and finds nothing — a trap found on real hardware, not a + * hypothetical. + * + * `true` turns the Content tab **read-only**: every write path into the + * local asset store is removed outright, not merely disabled — the + * upload/replace and delete controls in the tab, and the upload + * affordances on font and image-URL property fields. The tab stays + * visible and keeps listing what the current payload references and how + * each one resolves (including through `resolveAsset`, badged **Host**) + * — a read-only explorer, the same role the host-fed States panel already + * plays for states (issue #107). **This does not make the host's own + * asset library appear in the tab**; it only removes the affordance that + * silently fails at send time. Resolution order is unchanged (ADR-002): + * local content map, then bundled assets, then `resolveAsset` — this + * option stops new entries from reaching the first tier, it does not + * reorder or remove the tiers, and anything already stored still resolves + * and still lists. + * + * Default `false`: uploads work exactly as they do today. Absent, this + * option changes nothing — the same "conditional chrome, presence gates + * it" rule ADR-018 uses for `actions`, `targets` and `renderPreview`. + * + * Pass `{ hint }` instead of `true` to also replace the tab's upload + * instructions with a sentence in the host's own words — e.g. pointing at + * *its* standard upload location — instead of the designer's generic + * fallback. The designer's published surface stays domain-neutral + * (ADR-018: never `entity`, `hass`, or a specific host's paths), so it + * cannot word this for you; the host names its own directories, the + * designer just renders the string. Three guarantees: + * + * - **Plain text only**, always — never parsed as HTML or Markdown (no + * `dangerouslySetInnerHTML`, no link parsing). A published surface that + * interprets a host-supplied string as markup is a footgun the designer + * does not ship, even though the host is the embedder, not an untrusted + * third party. + * - Rendered where the upload instructions used to be, in the sidebar's + * existing muted/hint text style — no new visual treatment. + * - `true` (or `{ hint }` with an empty/missing string) falls back to a + * neutral sentence of the designer's own — assets are provided by the + * host application, nothing is stored in this browser — itself free of + * any host-specific vocabulary. + */ + hostOwnsAssets?: boolean | { + hint: string; + }; + /** + * Called on a designer status transition (issue #133) — see + * {@link HostStatusChangeHandler}. Optional: a host that only wants status + * on demand reads {@link MountHandle.getStatus} instead and never supplies + * this. + * + * A stable closure fixed at mount — there is no update channel for it + * (ADR-018: data is pushed, functions are not). + */ + onStatusChange?: HostStatusChangeHandler; +} + +/** + * Runtime version (issue #23, reworked 2026-07-29: git tags are the sole + * version source, not package.json — see `tools/version.ts`). Baked in at + * build time (`tools/buildDefines.ts`) from the release pipeline's + * `APP_VERSION` env var; a non-release build (local dev, CI `checks`, a PR + * preview) has none set and falls back to `0.0.0-dev`. Re-exported from + * `src/embed/index.ts` (`version`) and surfaced on `MountHandle.version`. + * + * This is the project's ONE version signal (reworked 2026-09-01): the + * release pipeline computes the version once and every build in that run — + * the published library AND the standalone site — bakes this same string. + * There is no separate site-version define that could disagree with it any + * more (docs/releasing.md). + */ +export declare const version: string; + +export { } diff --git a/custom_components/opendisplay/designer/frontend/vendor/odl-drawcustom-designer.js b/custom_components/opendisplay/designer/frontend/vendor/odl-drawcustom-designer.js new file mode 100644 index 00000000..588311f2 --- /dev/null +++ b/custom_components/opendisplay/designer/frontend/vendor/odl-drawcustom-designer.js @@ -0,0 +1,77709 @@ +//#region \0rolldown/runtime.js +var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescriptor, r = Object.getOwnPropertyNames, i = Object.getPrototypeOf, a = Object.prototype.hasOwnProperty, o = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), s = (e, n) => { + let r = {}; + for (var i in e) t(r, i, { + get: e[i], + enumerable: !0 + }); + return n || t(r, Symbol.toStringTag, { value: "Module" }), r; +}, c = (e, i, o, s) => { + if (i && typeof i == "object" || typeof i == "function") for (var c = r(i), l = 0, u = c.length, d; l < u; l++) d = c[l], !a.call(e, d) && d !== o && t(e, d, { + get: ((e) => i[e]).bind(null, d), + enumerable: !(s = n(i, d)) || s.enumerable + }); + return e; +}, l = (n, r, o) => (o = n == null ? {} : e(i(n)), c(r || !n || !n.__esModule || !a.call(n, "default") ? t(o, "default", { + value: n, + enumerable: !0 +}) : o, n)), u = /* @__PURE__ */ o(((e) => { + var t = Symbol.for("react.transitional.element"), n = Symbol.for("react.portal"), r = Symbol.for("react.fragment"), i = Symbol.for("react.strict_mode"), a = Symbol.for("react.profiler"), o = Symbol.for("react.consumer"), s = Symbol.for("react.context"), c = Symbol.for("react.forward_ref"), l = Symbol.for("react.suspense"), u = Symbol.for("react.memo"), d = Symbol.for("react.lazy"), f = Symbol.for("react.activity"), p = Symbol.iterator; + function m(e) { + return typeof e != "object" || !e ? null : (e = p && e[p] || e["@@iterator"], typeof e == "function" ? e : null); + } + var h = { + isMounted: function() { + return !1; + }, + enqueueForceUpdate: function() {}, + enqueueReplaceState: function() {}, + enqueueSetState: function() {} + }, g = Object.assign, _ = {}; + function v(e, t, n) { + this.props = e, this.context = t, this.refs = _, this.updater = n || h; + } + v.prototype.isReactComponent = {}, v.prototype.setState = function(e, t) { + if (typeof e != "object" && typeof e != "function" && e != null) throw Error("takes an object of state variables to update or a function which returns an object of state variables."); + this.updater.enqueueSetState(this, e, t, "setState"); + }, v.prototype.forceUpdate = function(e) { + this.updater.enqueueForceUpdate(this, e, "forceUpdate"); + }; + function y() {} + y.prototype = v.prototype; + function b(e, t, n) { + this.props = e, this.context = t, this.refs = _, this.updater = n || h; + } + var x = b.prototype = new y(); + x.constructor = b, g(x, v.prototype), x.isPureReactComponent = !0; + var S = Array.isArray; + function C() {} + var w = { + H: null, + A: null, + T: null, + S: null + }, T = Object.prototype.hasOwnProperty; + function E(e, n, r) { + var i = r.ref; + return { + $$typeof: t, + type: e, + key: n, + ref: i === void 0 ? null : i, + props: r + }; + } + function D(e, t) { + return E(e.type, t, e.props); + } + function O(e) { + return typeof e == "object" && !!e && e.$$typeof === t; + } + function ee(e) { + var t = { + "=": "=0", + ":": "=2" + }; + return "$" + e.replace(/[=:]/g, function(e) { + return t[e]; + }); + } + var te = /\/+/g; + function ne(e, t) { + return typeof e == "object" && e && e.key != null ? ee("" + e.key) : t.toString(36); + } + function re(e) { + switch (e.status) { + case "fulfilled": return e.value; + case "rejected": throw e.reason; + default: switch (typeof e.status == "string" ? e.then(C, C) : (e.status = "pending", e.then(function(t) { + e.status === "pending" && (e.status = "fulfilled", e.value = t); + }, function(t) { + e.status === "pending" && (e.status = "rejected", e.reason = t); + })), e.status) { + case "fulfilled": return e.value; + case "rejected": throw e.reason; + } + } + throw e; + } + function k(e, r, i, a, o) { + var s = typeof e; + (s === "undefined" || s === "boolean") && (e = null); + var c = !1; + if (e === null) c = !0; + else switch (s) { + case "bigint": + case "string": + case "number": + c = !0; + break; + case "object": switch (e.$$typeof) { + case t: + case n: + c = !0; + break; + case d: return c = e._init, k(c(e._payload), r, i, a, o); + } + } + if (c) return o = o(e), c = a === "" ? "." + ne(e, 0) : a, S(o) ? (i = "", c != null && (i = c.replace(te, "$&/") + "/"), k(o, r, i, "", function(e) { + return e; + })) : o != null && (O(o) && (o = D(o, i + (o.key == null || e && e.key === o.key ? "" : ("" + o.key).replace(te, "$&/") + "/") + c)), r.push(o)), 1; + c = 0; + var l = a === "" ? "." : a + ":"; + if (S(e)) for (var u = 0; u < e.length; u++) a = e[u], s = l + ne(a, u), c += k(a, r, i, s, o); + else if (u = m(e), typeof u == "function") for (e = u.call(e), u = 0; !(a = e.next()).done;) a = a.value, s = l + ne(a, u++), c += k(a, r, i, s, o); + else if (s === "object") { + if (typeof e.then == "function") return k(re(e), r, i, a, o); + throw r = String(e), Error("Objects are not valid as a React child (found: " + (r === "[object Object]" ? "object with keys {" + Object.keys(e).join(", ") + "}" : r) + "). If you meant to render a collection of children, use an array instead."); + } + return c; + } + function ie(e, t, n) { + if (e == null) return e; + var r = [], i = 0; + return k(e, r, "", "", function(e) { + return t.call(n, e, i++); + }), r; + } + function ae(e) { + if (e._status === -1) { + var t = e._result; + t = t(), t.then(function(t) { + (e._status === 0 || e._status === -1) && (e._status = 1, e._result = t); + }, function(t) { + (e._status === 0 || e._status === -1) && (e._status = 2, e._result = t); + }), e._status === -1 && (e._status = 0, e._result = t); + } + if (e._status === 1) return e._result.default; + throw e._result; + } + var A = typeof reportError == "function" ? reportError : function(e) { + if (typeof window == "object" && typeof window.ErrorEvent == "function") { + var t = new window.ErrorEvent("error", { + bubbles: !0, + cancelable: !0, + message: typeof e == "object" && e && typeof e.message == "string" ? String(e.message) : String(e), + error: e + }); + if (!window.dispatchEvent(t)) return; + } else if (typeof process == "object" && typeof process.emit == "function") { + process.emit("uncaughtException", e); + return; + } + console.error(e); + }, j = { + map: ie, + forEach: function(e, t, n) { + ie(e, function() { + t.apply(this, arguments); + }, n); + }, + count: function(e) { + var t = 0; + return ie(e, function() { + t++; + }), t; + }, + toArray: function(e) { + return ie(e, function(e) { + return e; + }) || []; + }, + only: function(e) { + if (!O(e)) throw Error("React.Children.only expected to receive a single React element child."); + return e; + } + }; + e.Activity = f, e.Children = j, e.Component = v, e.Fragment = r, e.Profiler = a, e.PureComponent = b, e.StrictMode = i, e.Suspense = l, e.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE = w, e.__COMPILER_RUNTIME = { + __proto__: null, + c: function(e) { + return w.H.useMemoCache(e); + } + }, e.cache = function(e) { + return function() { + return e.apply(null, arguments); + }; + }, e.cacheSignal = function() { + return null; + }, e.cloneElement = function(e, t, n) { + if (e == null) throw Error("The argument must be a React element, but you passed " + e + "."); + var r = g({}, e.props), i = e.key; + if (t != null) for (a in t.key !== void 0 && (i = "" + t.key), t) !T.call(t, a) || a === "key" || a === "__self" || a === "__source" || a === "ref" && t.ref === void 0 || (r[a] = t[a]); + var a = arguments.length - 2; + if (a === 1) r.children = n; + else if (1 < a) { + for (var o = Array(a), s = 0; s < a; s++) o[s] = arguments[s + 2]; + r.children = o; + } + return E(e.type, i, r); + }, e.createContext = function(e) { + return e = { + $$typeof: s, + _currentValue: e, + _currentValue2: e, + _threadCount: 0, + Provider: null, + Consumer: null + }, e.Provider = e, e.Consumer = { + $$typeof: o, + _context: e + }, e; + }, e.createElement = function(e, t, n) { + var r, i = {}, a = null; + if (t != null) for (r in t.key !== void 0 && (a = "" + t.key), t) T.call(t, r) && r !== "key" && r !== "__self" && r !== "__source" && (i[r] = t[r]); + var o = arguments.length - 2; + if (o === 1) i.children = n; + else if (1 < o) { + for (var s = Array(o), c = 0; c < o; c++) s[c] = arguments[c + 2]; + i.children = s; + } + if (e && e.defaultProps) for (r in o = e.defaultProps, o) i[r] === void 0 && (i[r] = o[r]); + return E(e, a, i); + }, e.createRef = function() { + return { current: null }; + }, e.forwardRef = function(e) { + return { + $$typeof: c, + render: e + }; + }, e.isValidElement = O, e.lazy = function(e) { + return { + $$typeof: d, + _payload: { + _status: -1, + _result: e + }, + _init: ae + }; + }, e.memo = function(e, t) { + return { + $$typeof: u, + type: e, + compare: t === void 0 ? null : t + }; + }, e.startTransition = function(e) { + var t = w.T, n = {}; + w.T = n; + try { + var r = e(), i = w.S; + i !== null && i(n, r), typeof r == "object" && r && typeof r.then == "function" && r.then(C, A); + } catch (e) { + A(e); + } finally { + t !== null && n.types !== null && (t.types = n.types), w.T = t; + } + }, e.unstable_useCacheRefresh = function() { + return w.H.useCacheRefresh(); + }, e.use = function(e) { + return w.H.use(e); + }, e.useActionState = function(e, t, n) { + return w.H.useActionState(e, t, n); + }, e.useCallback = function(e, t) { + return w.H.useCallback(e, t); + }, e.useContext = function(e) { + return w.H.useContext(e); + }, e.useDebugValue = function() {}, e.useDeferredValue = function(e, t) { + return w.H.useDeferredValue(e, t); + }, e.useEffect = function(e, t) { + return w.H.useEffect(e, t); + }, e.useEffectEvent = function(e) { + return w.H.useEffectEvent(e); + }, e.useId = function() { + return w.H.useId(); + }, e.useImperativeHandle = function(e, t, n) { + return w.H.useImperativeHandle(e, t, n); + }, e.useInsertionEffect = function(e, t) { + return w.H.useInsertionEffect(e, t); + }, e.useLayoutEffect = function(e, t) { + return w.H.useLayoutEffect(e, t); + }, e.useMemo = function(e, t) { + return w.H.useMemo(e, t); + }, e.useOptimistic = function(e, t) { + return w.H.useOptimistic(e, t); + }, e.useReducer = function(e, t, n) { + return w.H.useReducer(e, t, n); + }, e.useRef = function(e) { + return w.H.useRef(e); + }, e.useState = function(e) { + return w.H.useState(e); + }, e.useSyncExternalStore = function(e, t, n) { + return w.H.useSyncExternalStore(e, t, n); + }, e.useTransition = function() { + return w.H.useTransition(); + }, e.version = "19.2.8"; +})), d = /* @__PURE__ */ o(((e, t) => { + t.exports = u(); +})), f = /* @__PURE__ */ o(((e) => { + function t(e, t) { + var n = e.length; + e.push(t); + a: for (; 0 < n;) { + var r = n - 1 >>> 1, a = e[r]; + if (0 < i(a, t)) e[r] = t, e[n] = a, n = r; + else break a; + } + } + function n(e) { + return e.length === 0 ? null : e[0]; + } + function r(e) { + if (e.length === 0) return null; + var t = e[0], n = e.pop(); + if (n !== t) { + e[0] = n; + a: for (var r = 0, a = e.length, o = a >>> 1; r < o;) { + var s = 2 * (r + 1) - 1, c = e[s], l = s + 1, u = e[l]; + if (0 > i(c, n)) l < a && 0 > i(u, c) ? (e[r] = u, e[l] = n, r = l) : (e[r] = c, e[s] = n, r = s); + else if (l < a && 0 > i(u, n)) e[r] = u, e[l] = n, r = l; + else break a; + } + } + return t; + } + function i(e, t) { + var n = e.sortIndex - t.sortIndex; + return n === 0 ? e.id - t.id : n; + } + if (e.unstable_now = void 0, typeof performance == "object" && typeof performance.now == "function") { + var a = performance; + e.unstable_now = function() { + return a.now(); + }; + } else { + var o = Date, s = o.now(); + e.unstable_now = function() { + return o.now() - s; + }; + } + var c = [], l = [], u = 1, d = null, f = 3, p = !1, m = !1, h = !1, g = !1, _ = typeof setTimeout == "function" ? setTimeout : null, v = typeof clearTimeout == "function" ? clearTimeout : null, y = typeof setImmediate < "u" ? setImmediate : null; + function b(e) { + for (var i = n(l); i !== null;) { + if (i.callback === null) r(l); + else if (i.startTime <= e) r(l), i.sortIndex = i.expirationTime, t(c, i); + else break; + i = n(l); + } + } + function x(e) { + if (h = !1, b(e), !m) { + if (n(c) !== null) m = !0, S || (S = !0, O()); + else { + var t = n(l); + t !== null && ne(x, t.startTime - e); + } + } + } + var S = !1, C = -1, w = 5, T = -1; + function E() { + return g ? !0 : !(e.unstable_now() - T < w); + } + function D() { + if (g = !1, S) { + var t = e.unstable_now(); + T = t; + var i = !0; + try { + a: { + m = !1, h && (h = !1, v(C), C = -1), p = !0; + var a = f; + try { + b: { + for (b(t), d = n(c); d !== null && !(d.expirationTime > t && E());) { + var o = d.callback; + if (typeof o == "function") { + d.callback = null, f = d.priorityLevel; + var s = o(d.expirationTime <= t); + if (t = e.unstable_now(), typeof s == "function") { + d.callback = s, b(t), i = !0; + break b; + } + d === n(c) && r(c), b(t); + } else r(c); + d = n(c); + } + if (d !== null) i = !0; + else { + var u = n(l); + u !== null && ne(x, u.startTime - t), i = !1; + } + } + break a; + } finally { + d = null, f = a, p = !1; + } + } + } finally { + i ? O() : S = !1; + } + } + } + var O; + if (typeof y == "function") O = function() { + y(D); + }; + else if (typeof MessageChannel < "u") { + var ee = new MessageChannel(), te = ee.port2; + ee.port1.onmessage = D, O = function() { + te.postMessage(null); + }; + } else O = function() { + _(D, 0); + }; + function ne(t, n) { + C = _(function() { + t(e.unstable_now()); + }, n); + } + e.unstable_IdlePriority = 5, e.unstable_ImmediatePriority = 1, e.unstable_LowPriority = 4, e.unstable_NormalPriority = 3, e.unstable_Profiling = null, e.unstable_UserBlockingPriority = 2, e.unstable_cancelCallback = function(e) { + e.callback = null; + }, e.unstable_forceFrameRate = function(e) { + 0 > e || 125 < e ? console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported") : w = 0 < e ? Math.floor(1e3 / e) : 5; + }, e.unstable_getCurrentPriorityLevel = function() { + return f; + }, e.unstable_next = function(e) { + switch (f) { + case 1: + case 2: + case 3: + var t = 3; + break; + default: t = f; + } + var n = f; + f = t; + try { + return e(); + } finally { + f = n; + } + }, e.unstable_requestPaint = function() { + g = !0; + }, e.unstable_runWithPriority = function(e, t) { + switch (e) { + case 1: + case 2: + case 3: + case 4: + case 5: break; + default: e = 3; + } + var n = f; + f = e; + try { + return t(); + } finally { + f = n; + } + }, e.unstable_scheduleCallback = function(r, i, a) { + var o = e.unstable_now(); + switch (typeof a == "object" && a ? (a = a.delay, a = typeof a == "number" && 0 < a ? o + a : o) : a = o, r) { + case 1: + var s = -1; + break; + case 2: + s = 250; + break; + case 5: + s = 1073741823; + break; + case 4: + s = 1e4; + break; + default: s = 5e3; + } + return s = a + s, r = { + id: u++, + callback: i, + priorityLevel: r, + startTime: a, + expirationTime: s, + sortIndex: -1 + }, a > o ? (r.sortIndex = a, t(l, r), n(c) === null && r === n(l) && (h ? (v(C), C = -1) : h = !0, ne(x, a - o))) : (r.sortIndex = s, t(c, r), m || p || (m = !0, S || (S = !0, O()))), r; + }, e.unstable_shouldYield = E, e.unstable_wrapCallback = function(e) { + var t = f; + return function() { + var n = f; + f = t; + try { + return e.apply(this, arguments); + } finally { + f = n; + } + }; + }; +})), p = /* @__PURE__ */ o(((e, t) => { + t.exports = f(); +})), m = /* @__PURE__ */ o(((e) => { + var t = d(); + function n(e) { + var t = "https://react.dev/errors/" + e; + if (1 < arguments.length) { + t += "?args[]=" + encodeURIComponent(arguments[1]); + for (var n = 2; n < arguments.length; n++) t += "&args[]=" + encodeURIComponent(arguments[n]); + } + return "Minified React error #" + e + "; visit " + t + " for the full message or use the non-minified dev environment for full errors and additional helpful warnings."; + } + function r() {} + var i = { + d: { + f: r, + r: function() { + throw Error(n(522)); + }, + D: r, + C: r, + L: r, + m: r, + X: r, + S: r, + M: r + }, + p: 0, + findDOMNode: null + }, a = Symbol.for("react.portal"); + function o(e, t, n) { + var r = 3 < arguments.length && arguments[3] !== void 0 ? arguments[3] : null; + return { + $$typeof: a, + key: r == null ? null : "" + r, + children: e, + containerInfo: t, + implementation: n + }; + } + var s = t.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE; + function c(e, t) { + if (e === "font") return ""; + if (typeof t == "string") return t === "use-credentials" ? t : ""; + } + e.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE = i, e.createPortal = function(e, t) { + var r = 2 < arguments.length && arguments[2] !== void 0 ? arguments[2] : null; + if (!t || t.nodeType !== 1 && t.nodeType !== 9 && t.nodeType !== 11) throw Error(n(299)); + return o(e, t, null, r); + }, e.flushSync = function(e) { + var t = s.T, n = i.p; + try { + if (s.T = null, i.p = 2, e) return e(); + } finally { + s.T = t, i.p = n, i.d.f(); + } + }, e.preconnect = function(e, t) { + typeof e == "string" && (t ? (t = t.crossOrigin, t = typeof t == "string" ? t === "use-credentials" ? t : "" : void 0) : t = null, i.d.C(e, t)); + }, e.prefetchDNS = function(e) { + typeof e == "string" && i.d.D(e); + }, e.preinit = function(e, t) { + if (typeof e == "string" && t && typeof t.as == "string") { + var n = t.as, r = c(n, t.crossOrigin), a = typeof t.integrity == "string" ? t.integrity : void 0, o = typeof t.fetchPriority == "string" ? t.fetchPriority : void 0; + n === "style" ? i.d.S(e, typeof t.precedence == "string" ? t.precedence : void 0, { + crossOrigin: r, + integrity: a, + fetchPriority: o + }) : n === "script" && i.d.X(e, { + crossOrigin: r, + integrity: a, + fetchPriority: o, + nonce: typeof t.nonce == "string" ? t.nonce : void 0 + }); + } + }, e.preinitModule = function(e, t) { + if (typeof e == "string") { + if (typeof t == "object" && t) { + if (t.as == null || t.as === "script") { + var n = c(t.as, t.crossOrigin); + i.d.M(e, { + crossOrigin: n, + integrity: typeof t.integrity == "string" ? t.integrity : void 0, + nonce: typeof t.nonce == "string" ? t.nonce : void 0 + }); + } + } else t ?? i.d.M(e); + } + }, e.preload = function(e, t) { + if (typeof e == "string" && typeof t == "object" && t && typeof t.as == "string") { + var n = t.as, r = c(n, t.crossOrigin); + i.d.L(e, n, { + crossOrigin: r, + integrity: typeof t.integrity == "string" ? t.integrity : void 0, + nonce: typeof t.nonce == "string" ? t.nonce : void 0, + type: typeof t.type == "string" ? t.type : void 0, + fetchPriority: typeof t.fetchPriority == "string" ? t.fetchPriority : void 0, + referrerPolicy: typeof t.referrerPolicy == "string" ? t.referrerPolicy : void 0, + imageSrcSet: typeof t.imageSrcSet == "string" ? t.imageSrcSet : void 0, + imageSizes: typeof t.imageSizes == "string" ? t.imageSizes : void 0, + media: typeof t.media == "string" ? t.media : void 0 + }); + } + }, e.preloadModule = function(e, t) { + if (typeof e == "string") { + if (t) { + var n = c(t.as, t.crossOrigin); + i.d.m(e, { + as: typeof t.as == "string" && t.as !== "script" ? t.as : void 0, + crossOrigin: n, + integrity: typeof t.integrity == "string" ? t.integrity : void 0 + }); + } else i.d.m(e); + } + }, e.requestFormReset = function(e) { + i.d.r(e); + }, e.unstable_batchedUpdates = function(e, t) { + return e(t); + }, e.useFormState = function(e, t, n) { + return s.H.useFormState(e, t, n); + }, e.useFormStatus = function() { + return s.H.useHostTransitionStatus(); + }, e.version = "19.2.8"; +})), h = /* @__PURE__ */ o(((e, t) => { + function n() { + if (!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ > "u" || typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE != "function")) try { + __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n); + } catch (e) { + console.error(e); + } + } + n(), t.exports = m(); +})), g = /* @__PURE__ */ o(((e) => { + var t = p(), n = d(), r = h(); + function i(e) { + var t = "https://react.dev/errors/" + e; + if (1 < arguments.length) { + t += "?args[]=" + encodeURIComponent(arguments[1]); + for (var n = 2; n < arguments.length; n++) t += "&args[]=" + encodeURIComponent(arguments[n]); + } + return "Minified React error #" + e + "; visit " + t + " for the full message or use the non-minified dev environment for full errors and additional helpful warnings."; + } + function a(e) { + return !(!e || e.nodeType !== 1 && e.nodeType !== 9 && e.nodeType !== 11); + } + function o(e) { + var t = e, n = e; + if (e.alternate) for (; t.return;) t = t.return; + else { + e = t; + do + t = e, t.flags & 4098 && (n = t.return), e = t.return; + while (e); + } + return t.tag === 3 ? n : null; + } + function s(e) { + if (e.tag === 13) { + var t = e.memoizedState; + if (t === null && (e = e.alternate, e !== null && (t = e.memoizedState)), t !== null) return t.dehydrated; + } + return null; + } + function c(e) { + if (e.tag === 31) { + var t = e.memoizedState; + if (t === null && (e = e.alternate, e !== null && (t = e.memoizedState)), t !== null) return t.dehydrated; + } + return null; + } + function l(e) { + if (o(e) !== e) throw Error(i(188)); + } + function u(e) { + var t = e.alternate; + if (!t) { + if (t = o(e), t === null) throw Error(i(188)); + return t === e ? e : null; + } + for (var n = e, r = t;;) { + var a = n.return; + if (a === null) break; + var s = a.alternate; + if (s === null) { + if (r = a.return, r !== null) { + n = r; + continue; + } + break; + } + if (a.child === s.child) { + for (s = a.child; s;) { + if (s === n) return l(a), e; + if (s === r) return l(a), t; + s = s.sibling; + } + throw Error(i(188)); + } + if (n.return !== r.return) n = a, r = s; + else { + for (var c = !1, u = a.child; u;) { + if (u === n) { + c = !0, n = a, r = s; + break; + } + if (u === r) { + c = !0, r = a, n = s; + break; + } + u = u.sibling; + } + if (!c) { + for (u = s.child; u;) { + if (u === n) { + c = !0, n = s, r = a; + break; + } + if (u === r) { + c = !0, r = s, n = a; + break; + } + u = u.sibling; + } + if (!c) throw Error(i(189)); + } + } + if (n.alternate !== r) throw Error(i(190)); + } + if (n.tag !== 3) throw Error(i(188)); + return n.stateNode.current === n ? e : t; + } + function f(e) { + var t = e.tag; + if (t === 5 || t === 26 || t === 27 || t === 6) return e; + for (e = e.child; e !== null;) { + if (t = f(e), t !== null) return t; + e = e.sibling; + } + return null; + } + var m = Object.assign, g = Symbol.for("react.element"), _ = Symbol.for("react.transitional.element"), v = Symbol.for("react.portal"), y = Symbol.for("react.fragment"), b = Symbol.for("react.strict_mode"), x = Symbol.for("react.profiler"), S = Symbol.for("react.consumer"), C = Symbol.for("react.context"), w = Symbol.for("react.forward_ref"), T = Symbol.for("react.suspense"), E = Symbol.for("react.suspense_list"), D = Symbol.for("react.memo"), O = Symbol.for("react.lazy"), ee = Symbol.for("react.activity"), te = Symbol.for("react.memo_cache_sentinel"), ne = Symbol.iterator; + function re(e) { + return typeof e != "object" || !e ? null : (e = ne && e[ne] || e["@@iterator"], typeof e == "function" ? e : null); + } + var k = Symbol.for("react.client.reference"); + function ie(e) { + if (e == null) return null; + if (typeof e == "function") return e.$$typeof === k ? null : e.displayName || e.name || null; + if (typeof e == "string") return e; + switch (e) { + case y: return "Fragment"; + case x: return "Profiler"; + case b: return "StrictMode"; + case T: return "Suspense"; + case E: return "SuspenseList"; + case ee: return "Activity"; + } + if (typeof e == "object") switch (e.$$typeof) { + case v: return "Portal"; + case C: return e.displayName || "Context"; + case S: return (e._context.displayName || "Context") + ".Consumer"; + case w: + var t = e.render; + return e = e.displayName, e ||= (e = t.displayName || t.name || "", e === "" ? "ForwardRef" : "ForwardRef(" + e + ")"), e; + case D: return t = e.displayName || null, t === null ? ie(e.type) || "Memo" : t; + case O: + t = e._payload, e = e._init; + try { + return ie(e(t)); + } catch {} + } + return null; + } + var ae = Array.isArray, A = n.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, j = r.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, oe = { + pending: !1, + data: null, + method: null, + action: null + }, M = [], se = -1; + function ce(e) { + return { current: e }; + } + function le(e) { + 0 > se || (e.current = M[se], M[se] = null, se--); + } + function N(e, t) { + se++, M[se] = e.current, e.current = t; + } + var P = ce(null), F = ce(null), ue = ce(null), I = ce(null); + function de(e, t) { + switch (N(ue, t), N(F, e), N(P, null), t.nodeType) { + case 9: + case 11: + e = (e = t.documentElement) && (e = e.namespaceURI) ? Yd(e) : 0; + break; + default: if (e = t.tagName, t = t.namespaceURI) t = Yd(t), e = Xd(t, e); + else switch (e) { + case "svg": + e = 1; + break; + case "math": + e = 2; + break; + default: e = 0; + } + } + le(P), N(P, e); + } + function fe() { + le(P), le(F), le(ue); + } + function L(e) { + e.memoizedState !== null && N(I, e); + var t = P.current, n = Xd(t, e.type); + t !== n && (N(F, e), N(P, n)); + } + function R(e) { + F.current === e && (le(P), le(F)), I.current === e && (le(I), op._currentValue = oe); + } + var pe, me; + function he(e) { + if (pe === void 0) try { + throw Error(); + } catch (e) { + var t = e.stack.trim().match(/\n( *(at )?)/); + pe = t && t[1] || "", me = -1 < e.stack.indexOf("\n at") ? " ()" : -1 < e.stack.indexOf("@") ? "@unknown:0:0" : ""; + } + return "\n" + pe + e + me; + } + var ge = !1; + function _e(e, t) { + if (!e || ge) return ""; + ge = !0; + var n = Error.prepareStackTrace; + Error.prepareStackTrace = void 0; + try { + var r = { DetermineComponentFrameRoot: function() { + try { + if (t) { + var n = function() { + throw Error(); + }; + if (Object.defineProperty(n.prototype, "props", { set: function() { + throw Error(); + } }), typeof Reflect == "object" && Reflect.construct) { + try { + Reflect.construct(n, []); + } catch (e) { + var r = e; + } + Reflect.construct(e, [], n); + } else { + try { + n.call(); + } catch (e) { + r = e; + } + e.call(n.prototype); + } + } else { + try { + throw Error(); + } catch (e) { + r = e; + } + (n = e()) && typeof n.catch == "function" && n.catch(function() {}); + } + } catch (e) { + if (e && r && typeof e.stack == "string") return [e.stack, r.stack]; + } + return [null, null]; + } }; + r.DetermineComponentFrameRoot.displayName = "DetermineComponentFrameRoot"; + var i = Object.getOwnPropertyDescriptor(r.DetermineComponentFrameRoot, "name"); + i && i.configurable && Object.defineProperty(r.DetermineComponentFrameRoot, "name", { value: "DetermineComponentFrameRoot" }); + var a = r.DetermineComponentFrameRoot(), o = a[0], s = a[1]; + if (o && s) { + var c = o.split("\n"), l = s.split("\n"); + for (i = r = 0; r < c.length && !c[r].includes("DetermineComponentFrameRoot");) r++; + for (; i < l.length && !l[i].includes("DetermineComponentFrameRoot");) i++; + if (r === c.length || i === l.length) for (r = c.length - 1, i = l.length - 1; 1 <= r && 0 <= i && c[r] !== l[i];) i--; + for (; 1 <= r && 0 <= i; r--, i--) if (c[r] !== l[i]) { + if (r !== 1 || i !== 1) do + if (r--, i--, 0 > i || c[r] !== l[i]) { + var u = "\n" + c[r].replace(" at new ", " at "); + return e.displayName && u.includes("") && (u = u.replace("", e.displayName)), u; + } + while (1 <= r && 0 <= i); + break; + } + } + } finally { + ge = !1, Error.prepareStackTrace = n; + } + return (n = e ? e.displayName || e.name : "") ? he(n) : ""; + } + function ve(e, t) { + switch (e.tag) { + case 26: + case 27: + case 5: return he(e.type); + case 16: return he("Lazy"); + case 13: return e.child !== t && t !== null ? he("Suspense Fallback") : he("Suspense"); + case 19: return he("SuspenseList"); + case 0: + case 15: return _e(e.type, !1); + case 11: return _e(e.type.render, !1); + case 1: return _e(e.type, !0); + case 31: return he("Activity"); + default: return ""; + } + } + function ye(e) { + try { + var t = "", n = null; + do + t += ve(e, n), n = e, e = e.return; + while (e); + return t; + } catch (e) { + return "\nError generating stack: " + e.message + "\n" + e.stack; + } + } + var be = Object.prototype.hasOwnProperty, xe = t.unstable_scheduleCallback, Se = t.unstable_cancelCallback, Ce = t.unstable_shouldYield, we = t.unstable_requestPaint, Te = t.unstable_now, Ee = t.unstable_getCurrentPriorityLevel, De = t.unstable_ImmediatePriority, Oe = t.unstable_UserBlockingPriority, ke = t.unstable_NormalPriority, Ae = t.unstable_LowPriority, je = t.unstable_IdlePriority, z = t.log, Me = t.unstable_setDisableYieldValue, Ne = null, Pe = null; + function B(e) { + if (typeof z == "function" && Me(e), Pe && typeof Pe.setStrictMode == "function") try { + Pe.setStrictMode(Ne, e); + } catch {} + } + var Fe = Math.clz32 ? Math.clz32 : Re, Ie = Math.log, Le = Math.LN2; + function Re(e) { + return e >>>= 0, e === 0 ? 32 : 31 - (Ie(e) / Le | 0) | 0; + } + var ze = 256, Be = 262144, Ve = 4194304; + function He(e) { + var t = e & 42; + if (t !== 0) return t; + switch (e & -e) { + case 1: return 1; + case 2: return 2; + case 4: return 4; + case 8: return 8; + case 16: return 16; + case 32: return 32; + case 64: return 64; + case 128: return 128; + case 256: + case 512: + case 1024: + case 2048: + case 4096: + case 8192: + case 16384: + case 32768: + case 65536: + case 131072: return e & 261888; + case 262144: + case 524288: + case 1048576: + case 2097152: return e & 3932160; + case 4194304: + case 8388608: + case 16777216: + case 33554432: return e & 62914560; + case 67108864: return 67108864; + case 134217728: return 134217728; + case 268435456: return 268435456; + case 536870912: return 536870912; + case 1073741824: return 0; + default: return e; + } + } + function V(e, t, n) { + var r = e.pendingLanes; + if (r === 0) return 0; + var i = 0, a = e.suspendedLanes, o = e.pingedLanes; + e = e.warmLanes; + var s = r & 134217727; + return s === 0 ? (s = r & ~a, s === 0 ? o === 0 ? n || (n = r & ~e, n !== 0 && (i = He(n))) : i = He(o) : i = He(s)) : (r = s & ~a, r === 0 ? (o &= s, o === 0 ? n || (n = s & ~e, n !== 0 && (i = He(n))) : i = He(o)) : i = He(r)), i === 0 ? 0 : t !== 0 && t !== i && (t & a) === 0 && (a = i & -i, n = t & -t, a >= n || a === 32 && n & 4194048) ? t : i; + } + function H(e, t) { + return (e.pendingLanes & ~(e.suspendedLanes & ~e.pingedLanes) & t) === 0; + } + function Ue(e, t) { + switch (e) { + case 1: + case 2: + case 4: + case 8: + case 64: return t + 250; + case 16: + case 32: + case 128: + case 256: + case 512: + case 1024: + case 2048: + case 4096: + case 8192: + case 16384: + case 32768: + case 65536: + case 131072: + case 262144: + case 524288: + case 1048576: + case 2097152: return t + 5e3; + case 4194304: + case 8388608: + case 16777216: + case 33554432: return -1; + case 67108864: + case 134217728: + case 268435456: + case 536870912: + case 1073741824: return -1; + default: return -1; + } + } + function U() { + var e = Ve; + return Ve <<= 1, !(Ve & 62914560) && (Ve = 4194304), e; + } + function We(e) { + for (var t = [], n = 0; 31 > n; n++) t.push(e); + return t; + } + function Ge(e, t) { + e.pendingLanes |= t, t !== 268435456 && (e.suspendedLanes = 0, e.pingedLanes = 0, e.warmLanes = 0); + } + function Ke(e, t, n, r, i, a) { + var o = e.pendingLanes; + e.pendingLanes = n, e.suspendedLanes = 0, e.pingedLanes = 0, e.warmLanes = 0, e.expiredLanes &= n, e.entangledLanes &= n, e.errorRecoveryDisabledLanes &= n, e.shellSuspendCounter = 0; + var s = e.entanglements, c = e.expirationTimes, l = e.hiddenUpdates; + for (n = o & ~n; 0 < n;) { + var u = 31 - Fe(n), d = 1 << u; + s[u] = 0, c[u] = -1; + var f = l[u]; + if (f !== null) for (l[u] = null, u = 0; u < f.length; u++) { + var p = f[u]; + p !== null && (p.lane &= -536870913); + } + n &= ~d; + } + r !== 0 && qe(e, r, 0), a !== 0 && i === 0 && e.tag !== 0 && (e.suspendedLanes |= a & ~(o & ~t)); + } + function qe(e, t, n) { + e.pendingLanes |= t, e.suspendedLanes &= ~t; + var r = 31 - Fe(t); + e.entangledLanes |= t, e.entanglements[r] = e.entanglements[r] | 1073741824 | n & 261930; + } + function Je(e, t) { + var n = e.entangledLanes |= t; + for (e = e.entanglements; n;) { + var r = 31 - Fe(n), i = 1 << r; + i & t | e[r] & t && (e[r] |= t), n &= ~i; + } + } + function Ye(e, t) { + var n = t & -t; + return n = n & 42 ? 1 : Xe(n), (n & (e.suspendedLanes | t)) === 0 ? n : 0; + } + function Xe(e) { + switch (e) { + case 2: + e = 1; + break; + case 8: + e = 4; + break; + case 32: + e = 16; + break; + case 256: + case 512: + case 1024: + case 2048: + case 4096: + case 8192: + case 16384: + case 32768: + case 65536: + case 131072: + case 262144: + case 524288: + case 1048576: + case 2097152: + case 4194304: + case 8388608: + case 16777216: + case 33554432: + e = 128; + break; + case 268435456: + e = 134217728; + break; + default: e = 0; + } + return e; + } + function Ze(e) { + return e &= -e, 2 < e ? 8 < e ? e & 134217727 ? 32 : 268435456 : 8 : 2; + } + function Qe() { + var e = j.p; + return e === 0 ? (e = window.event, e === void 0 ? 32 : Sp(e.type)) : e; + } + function $e(e, t) { + var n = j.p; + try { + return j.p = e, t(); + } finally { + j.p = n; + } + } + var et = Math.random().toString(36).slice(2), tt = "__reactFiber$" + et, nt = "__reactProps$" + et, rt = "__reactContainer$" + et, it = "__reactEvents$" + et, at = "__reactListeners$" + et, ot = "__reactHandles$" + et, st = "__reactResources$" + et, ct = "__reactMarker$" + et; + function lt(e) { + delete e[tt], delete e[nt], delete e[it], delete e[at], delete e[ot]; + } + function ut(e) { + var t = e[tt]; + if (t) return t; + for (var n = e.parentNode; n;) { + if (t = n[rt] || n[tt]) { + if (n = t.alternate, t.child !== null || n !== null && n.child !== null) for (e = yf(e); e !== null;) { + if (n = e[tt]) return n; + e = yf(e); + } + return t; + } + e = n, n = e.parentNode; + } + return null; + } + function dt(e) { + if (e = e[tt] || e[rt]) { + var t = e.tag; + if (t === 5 || t === 6 || t === 13 || t === 31 || t === 26 || t === 27 || t === 3) return e; + } + return null; + } + function ft(e) { + var t = e.tag; + if (t === 5 || t === 26 || t === 27 || t === 6) return e.stateNode; + throw Error(i(33)); + } + function pt(e) { + var t = e[st]; + return t ||= e[st] = { + hoistableStyles: /* @__PURE__ */ new Map(), + hoistableScripts: /* @__PURE__ */ new Map() + }, t; + } + function mt(e) { + e[ct] = !0; + } + var ht = /* @__PURE__ */ new Set(), gt = {}; + function W(e, t) { + _t(e, t), _t(e + "Capture", t); + } + function _t(e, t) { + for (gt[e] = t, e = 0; e < t.length; e++) ht.add(t[e]); + } + var vt = RegExp("^[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD][:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*$"), yt = {}, bt = {}; + function xt(e) { + return be.call(bt, e) ? !0 : be.call(yt, e) ? !1 : vt.test(e) ? bt[e] = !0 : (yt[e] = !0, !1); + } + function St(e, t, n) { + if (xt(t)) { + if (n === null) e.removeAttribute(t); + else { + switch (typeof n) { + case "undefined": + case "function": + case "symbol": + e.removeAttribute(t); + return; + case "boolean": + var r = t.toLowerCase().slice(0, 5); + if (r !== "data-" && r !== "aria-") { + e.removeAttribute(t); + return; + } + } + e.setAttribute(t, "" + n); + } + } + } + function Ct(e, t, n) { + if (n === null) e.removeAttribute(t); + else { + switch (typeof n) { + case "undefined": + case "function": + case "symbol": + case "boolean": + e.removeAttribute(t); + return; + } + e.setAttribute(t, "" + n); + } + } + function wt(e, t, n, r) { + if (r === null) e.removeAttribute(n); + else { + switch (typeof r) { + case "undefined": + case "function": + case "symbol": + case "boolean": + e.removeAttribute(n); + return; + } + e.setAttributeNS(t, n, "" + r); + } + } + function Tt(e) { + switch (typeof e) { + case "bigint": + case "boolean": + case "number": + case "string": + case "undefined": return e; + case "object": return e; + default: return ""; + } + } + function Et(e) { + var t = e.type; + return (e = e.nodeName) && e.toLowerCase() === "input" && (t === "checkbox" || t === "radio"); + } + function Dt(e, t, n) { + var r = Object.getOwnPropertyDescriptor(e.constructor.prototype, t); + if (!e.hasOwnProperty(t) && r !== void 0 && typeof r.get == "function" && typeof r.set == "function") { + var i = r.get, a = r.set; + return Object.defineProperty(e, t, { + configurable: !0, + get: function() { + return i.call(this); + }, + set: function(e) { + n = "" + e, a.call(this, e); + } + }), Object.defineProperty(e, t, { enumerable: r.enumerable }), { + getValue: function() { + return n; + }, + setValue: function(e) { + n = "" + e; + }, + stopTracking: function() { + e._valueTracker = null, delete e[t]; + } + }; + } + } + function Ot(e) { + if (!e._valueTracker) { + var t = Et(e) ? "checked" : "value"; + e._valueTracker = Dt(e, t, "" + e[t]); + } + } + function kt(e) { + if (!e) return !1; + var t = e._valueTracker; + if (!t) return !0; + var n = t.getValue(), r = ""; + return e && (r = Et(e) ? e.checked ? "true" : "false" : e.value), e = r, e !== n && (t.setValue(e), !0); + } + function At(e) { + if (e ||= typeof document < "u" ? document : void 0, e === void 0) return null; + try { + return e.activeElement || e.body; + } catch { + return e.body; + } + } + var jt = /[\n"\\]/g; + function Mt(e) { + return e.replace(jt, function(e) { + return "\\" + e.charCodeAt(0).toString(16) + " "; + }); + } + function Nt(e, t, n, r, i, a, o, s) { + e.name = "", o != null && typeof o != "function" && typeof o != "symbol" && typeof o != "boolean" ? e.type = o : e.removeAttribute("type"), t == null ? o !== "submit" && o !== "reset" || e.removeAttribute("value") : o === "number" ? (t === 0 && e.value === "" || e.value != t) && (e.value = "" + Tt(t)) : e.value !== "" + Tt(t) && (e.value = "" + Tt(t)), t == null ? n == null ? r != null && e.removeAttribute("value") : Ft(e, o, Tt(n)) : Ft(e, o, Tt(t)), i == null && a != null && (e.defaultChecked = !!a), i != null && (e.checked = i && typeof i != "function" && typeof i != "symbol"), s != null && typeof s != "function" && typeof s != "symbol" && typeof s != "boolean" ? e.name = "" + Tt(s) : e.removeAttribute("name"); + } + function Pt(e, t, n, r, i, a, o, s) { + if (a != null && typeof a != "function" && typeof a != "symbol" && typeof a != "boolean" && (e.type = a), t != null || n != null) { + if (!(a !== "submit" && a !== "reset" || t != null)) { + Ot(e); + return; + } + n = n == null ? "" : "" + Tt(n), t = t == null ? n : "" + Tt(t), s || t === e.value || (e.value = t), e.defaultValue = t; + } + r ??= i, r = typeof r != "function" && typeof r != "symbol" && !!r, e.checked = s ? e.checked : !!r, e.defaultChecked = !!r, o != null && typeof o != "function" && typeof o != "symbol" && typeof o != "boolean" && (e.name = o), Ot(e); + } + function Ft(e, t, n) { + t === "number" && At(e.ownerDocument) === e || e.defaultValue === "" + n || (e.defaultValue = "" + n); + } + function It(e, t, n, r) { + if (e = e.options, t) { + t = {}; + for (var i = 0; i < n.length; i++) t["$" + n[i]] = !0; + for (n = 0; n < e.length; n++) i = t.hasOwnProperty("$" + e[n].value), e[n].selected !== i && (e[n].selected = i), i && r && (e[n].defaultSelected = !0); + } else { + for (n = "" + Tt(n), t = null, i = 0; i < e.length; i++) { + if (e[i].value === n) { + e[i].selected = !0, r && (e[i].defaultSelected = !0); + return; + } + t !== null || e[i].disabled || (t = e[i]); + } + t !== null && (t.selected = !0); + } + } + function Lt(e, t, n) { + if (t != null && (t = "" + Tt(t), t !== e.value && (e.value = t), n == null)) { + e.defaultValue !== t && (e.defaultValue = t); + return; + } + e.defaultValue = n == null ? "" : "" + Tt(n); + } + function Rt(e, t, n, r) { + if (t == null) { + if (r != null) { + if (n != null) throw Error(i(92)); + if (ae(r)) { + if (1 < r.length) throw Error(i(93)); + r = r[0]; + } + n = r; + } + n ??= "", t = n; + } + n = Tt(t), e.defaultValue = n, r = e.textContent, r === n && r !== "" && r !== null && (e.value = r), Ot(e); + } + function zt(e, t) { + if (t) { + var n = e.firstChild; + if (n && n === e.lastChild && n.nodeType === 3) { + n.nodeValue = t; + return; + } + } + e.textContent = t; + } + var Bt = new Set("animationIterationCount aspectRatio borderImageOutset borderImageSlice borderImageWidth boxFlex boxFlexGroup boxOrdinalGroup columnCount columns flex flexGrow flexPositive flexShrink flexNegative flexOrder gridArea gridRow gridRowEnd gridRowSpan gridRowStart gridColumn gridColumnEnd gridColumnSpan gridColumnStart fontWeight lineClamp lineHeight opacity order orphans scale tabSize widows zIndex zoom fillOpacity floodOpacity stopOpacity strokeDasharray strokeDashoffset strokeMiterlimit strokeOpacity strokeWidth MozAnimationIterationCount MozBoxFlex MozBoxFlexGroup MozLineClamp msAnimationIterationCount msFlex msZoom msFlexGrow msFlexNegative msFlexOrder msFlexPositive msFlexShrink msGridColumn msGridColumnSpan msGridRow msGridRowSpan WebkitAnimationIterationCount WebkitBoxFlex WebKitBoxFlexGroup WebkitBoxOrdinalGroup WebkitColumnCount WebkitColumns WebkitFlex WebkitFlexGrow WebkitFlexPositive WebkitFlexShrink WebkitLineClamp".split(" ")); + function Vt(e, t, n) { + var r = t.indexOf("--") === 0; + n == null || typeof n == "boolean" || n === "" ? r ? e.setProperty(t, "") : t === "float" ? e.cssFloat = "" : e[t] = "" : r ? e.setProperty(t, n) : typeof n != "number" || n === 0 || Bt.has(t) ? t === "float" ? e.cssFloat = n : e[t] = ("" + n).trim() : e[t] = n + "px"; + } + function Ht(e, t, n) { + if (t != null && typeof t != "object") throw Error(i(62)); + if (e = e.style, n != null) { + for (var r in n) !n.hasOwnProperty(r) || t != null && t.hasOwnProperty(r) || (r.indexOf("--") === 0 ? e.setProperty(r, "") : r === "float" ? e.cssFloat = "" : e[r] = ""); + for (var a in t) r = t[a], t.hasOwnProperty(a) && n[a] !== r && Vt(e, a, r); + } else for (var o in t) t.hasOwnProperty(o) && Vt(e, o, t[o]); + } + function Ut(e) { + if (e.indexOf("-") === -1) return !1; + switch (e) { + case "annotation-xml": + case "color-profile": + case "font-face": + case "font-face-src": + case "font-face-uri": + case "font-face-format": + case "font-face-name": + case "missing-glyph": return !1; + default: return !0; + } + } + var Wt = /* @__PURE__ */ new Map([ + ["acceptCharset", "accept-charset"], + ["htmlFor", "for"], + ["httpEquiv", "http-equiv"], + ["crossOrigin", "crossorigin"], + ["accentHeight", "accent-height"], + ["alignmentBaseline", "alignment-baseline"], + ["arabicForm", "arabic-form"], + ["baselineShift", "baseline-shift"], + ["capHeight", "cap-height"], + ["clipPath", "clip-path"], + ["clipRule", "clip-rule"], + ["colorInterpolation", "color-interpolation"], + ["colorInterpolationFilters", "color-interpolation-filters"], + ["colorProfile", "color-profile"], + ["colorRendering", "color-rendering"], + ["dominantBaseline", "dominant-baseline"], + ["enableBackground", "enable-background"], + ["fillOpacity", "fill-opacity"], + ["fillRule", "fill-rule"], + ["floodColor", "flood-color"], + ["floodOpacity", "flood-opacity"], + ["fontFamily", "font-family"], + ["fontSize", "font-size"], + ["fontSizeAdjust", "font-size-adjust"], + ["fontStretch", "font-stretch"], + ["fontStyle", "font-style"], + ["fontVariant", "font-variant"], + ["fontWeight", "font-weight"], + ["glyphName", "glyph-name"], + ["glyphOrientationHorizontal", "glyph-orientation-horizontal"], + ["glyphOrientationVertical", "glyph-orientation-vertical"], + ["horizAdvX", "horiz-adv-x"], + ["horizOriginX", "horiz-origin-x"], + ["imageRendering", "image-rendering"], + ["letterSpacing", "letter-spacing"], + ["lightingColor", "lighting-color"], + ["markerEnd", "marker-end"], + ["markerMid", "marker-mid"], + ["markerStart", "marker-start"], + ["overlinePosition", "overline-position"], + ["overlineThickness", "overline-thickness"], + ["paintOrder", "paint-order"], + ["panose-1", "panose-1"], + ["pointerEvents", "pointer-events"], + ["renderingIntent", "rendering-intent"], + ["shapeRendering", "shape-rendering"], + ["stopColor", "stop-color"], + ["stopOpacity", "stop-opacity"], + ["strikethroughPosition", "strikethrough-position"], + ["strikethroughThickness", "strikethrough-thickness"], + ["strokeDasharray", "stroke-dasharray"], + ["strokeDashoffset", "stroke-dashoffset"], + ["strokeLinecap", "stroke-linecap"], + ["strokeLinejoin", "stroke-linejoin"], + ["strokeMiterlimit", "stroke-miterlimit"], + ["strokeOpacity", "stroke-opacity"], + ["strokeWidth", "stroke-width"], + ["textAnchor", "text-anchor"], + ["textDecoration", "text-decoration"], + ["textRendering", "text-rendering"], + ["transformOrigin", "transform-origin"], + ["underlinePosition", "underline-position"], + ["underlineThickness", "underline-thickness"], + ["unicodeBidi", "unicode-bidi"], + ["unicodeRange", "unicode-range"], + ["unitsPerEm", "units-per-em"], + ["vAlphabetic", "v-alphabetic"], + ["vHanging", "v-hanging"], + ["vIdeographic", "v-ideographic"], + ["vMathematical", "v-mathematical"], + ["vectorEffect", "vector-effect"], + ["vertAdvY", "vert-adv-y"], + ["vertOriginX", "vert-origin-x"], + ["vertOriginY", "vert-origin-y"], + ["wordSpacing", "word-spacing"], + ["writingMode", "writing-mode"], + ["xmlnsXlink", "xmlns:xlink"], + ["xHeight", "x-height"] + ]), Gt = /^[\u0000-\u001F ]*j[\r\n\t]*a[\r\n\t]*v[\r\n\t]*a[\r\n\t]*s[\r\n\t]*c[\r\n\t]*r[\r\n\t]*i[\r\n\t]*p[\r\n\t]*t[\r\n\t]*:/i; + function Kt(e) { + return Gt.test("" + e) ? "javascript:throw new Error('React has blocked a javascript: URL as a security precaution.')" : e; + } + function qt() {} + var Jt = null; + function Yt(e) { + return e = e.target || e.srcElement || window, e.correspondingUseElement && (e = e.correspondingUseElement), e.nodeType === 3 ? e.parentNode : e; + } + var Xt = null, Zt = null; + function Qt(e) { + var t = dt(e); + if (t && (e = t.stateNode)) { + var n = e[nt] || null; + a: switch (e = t.stateNode, t.type) { + case "input": + if (Nt(e, n.value, n.defaultValue, n.defaultValue, n.checked, n.defaultChecked, n.type, n.name), t = n.name, n.type === "radio" && t != null) { + for (n = e; n.parentNode;) n = n.parentNode; + for (n = n.querySelectorAll("input[name=\"" + Mt("" + t) + "\"][type=\"radio\"]"), t = 0; t < n.length; t++) { + var r = n[t]; + if (r !== e && r.form === e.form) { + var a = r[nt] || null; + if (!a) throw Error(i(90)); + Nt(r, a.value, a.defaultValue, a.defaultValue, a.checked, a.defaultChecked, a.type, a.name); + } + } + for (t = 0; t < n.length; t++) r = n[t], r.form === e.form && kt(r); + } + break a; + case "textarea": + Lt(e, n.value, n.defaultValue); + break a; + case "select": t = n.value, t != null && It(e, !!n.multiple, t, !1); + } + } + } + var $t = !1; + function en(e, t, n) { + if ($t) return e(t, n); + $t = !0; + try { + return e(t); + } finally { + if ($t = !1, (Xt !== null || Zt !== null) && (Tu(), Xt && (t = Xt, e = Zt, Zt = Xt = null, Qt(t), e))) for (t = 0; t < e.length; t++) Qt(e[t]); + } + } + function tn(e, t) { + var n = e.stateNode; + if (n === null) return null; + var r = n[nt] || null; + if (r === null) return null; + n = r[t]; + a: switch (t) { + case "onClick": + case "onClickCapture": + case "onDoubleClick": + case "onDoubleClickCapture": + case "onMouseDown": + case "onMouseDownCapture": + case "onMouseMove": + case "onMouseMoveCapture": + case "onMouseUp": + case "onMouseUpCapture": + case "onMouseEnter": + (r = !r.disabled) || (e = e.type, r = e !== "button" && e !== "input" && e !== "select" && e !== "textarea"), e = !r; + break a; + default: e = !1; + } + if (e) return null; + if (n && typeof n != "function") throw Error(i(231, t, typeof n)); + return n; + } + var nn = !(typeof window > "u" || window.document === void 0 || window.document.createElement === void 0), rn = !1; + if (nn) try { + var an = {}; + Object.defineProperty(an, "passive", { get: function() { + rn = !0; + } }), window.addEventListener("test", an, an), window.removeEventListener("test", an, an); + } catch { + rn = !1; + } + var on = null, sn = null, cn = null; + function ln() { + if (cn) return cn; + var e, t = sn, n = t.length, r, i = "value" in on ? on.value : on.textContent, a = i.length; + for (e = 0; e < n && t[e] === i[e]; e++); + var o = n - e; + for (r = 1; r <= o && t[n - r] === i[a - r]; r++); + return cn = i.slice(e, 1 < r ? 1 - r : void 0); + } + function un(e) { + var t = e.keyCode; + return "charCode" in e ? (e = e.charCode, e === 0 && t === 13 && (e = 13)) : e = t, e === 10 && (e = 13), 32 <= e || e === 13 ? e : 0; + } + function dn() { + return !0; + } + function fn() { + return !1; + } + function pn(e) { + function t(t, n, r, i, a) { + for (var o in this._reactName = t, this._targetInst = r, this.type = n, this.nativeEvent = i, this.target = a, this.currentTarget = null, e) e.hasOwnProperty(o) && (t = e[o], this[o] = t ? t(i) : i[o]); + return this.isDefaultPrevented = (i.defaultPrevented == null ? !1 === i.returnValue : i.defaultPrevented) ? dn : fn, this.isPropagationStopped = fn, this; + } + return m(t.prototype, { + preventDefault: function() { + this.defaultPrevented = !0; + var e = this.nativeEvent; + e && (e.preventDefault ? e.preventDefault() : typeof e.returnValue != "unknown" && (e.returnValue = !1), this.isDefaultPrevented = dn); + }, + stopPropagation: function() { + var e = this.nativeEvent; + e && (e.stopPropagation ? e.stopPropagation() : typeof e.cancelBubble != "unknown" && (e.cancelBubble = !0), this.isPropagationStopped = dn); + }, + persist: function() {}, + isPersistent: dn + }), t; + } + var mn = { + eventPhase: 0, + bubbles: 0, + cancelable: 0, + timeStamp: function(e) { + return e.timeStamp || Date.now(); + }, + defaultPrevented: 0, + isTrusted: 0 + }, hn = pn(mn), gn = m({}, mn, { + view: 0, + detail: 0 + }), _n = pn(gn), vn, yn, bn, xn = m({}, gn, { + screenX: 0, + screenY: 0, + clientX: 0, + clientY: 0, + pageX: 0, + pageY: 0, + ctrlKey: 0, + shiftKey: 0, + altKey: 0, + metaKey: 0, + getModifierState: Mn, + button: 0, + buttons: 0, + relatedTarget: function(e) { + return e.relatedTarget === void 0 ? e.fromElement === e.srcElement ? e.toElement : e.fromElement : e.relatedTarget; + }, + movementX: function(e) { + return "movementX" in e ? e.movementX : (e !== bn && (bn && e.type === "mousemove" ? (vn = e.screenX - bn.screenX, yn = e.screenY - bn.screenY) : yn = vn = 0, bn = e), vn); + }, + movementY: function(e) { + return "movementY" in e ? e.movementY : yn; + } + }), Sn = pn(xn), Cn = pn(m({}, xn, { dataTransfer: 0 })), wn = pn(m({}, gn, { relatedTarget: 0 })), Tn = pn(m({}, mn, { + animationName: 0, + elapsedTime: 0, + pseudoElement: 0 + })), En = pn(m({}, mn, { clipboardData: function(e) { + return "clipboardData" in e ? e.clipboardData : window.clipboardData; + } })), Dn = pn(m({}, mn, { data: 0 })), On = { + Esc: "Escape", + Spacebar: " ", + Left: "ArrowLeft", + Up: "ArrowUp", + Right: "ArrowRight", + Down: "ArrowDown", + Del: "Delete", + Win: "OS", + Menu: "ContextMenu", + Apps: "ContextMenu", + Scroll: "ScrollLock", + MozPrintableKey: "Unidentified" + }, kn = { + 8: "Backspace", + 9: "Tab", + 12: "Clear", + 13: "Enter", + 16: "Shift", + 17: "Control", + 18: "Alt", + 19: "Pause", + 20: "CapsLock", + 27: "Escape", + 32: " ", + 33: "PageUp", + 34: "PageDown", + 35: "End", + 36: "Home", + 37: "ArrowLeft", + 38: "ArrowUp", + 39: "ArrowRight", + 40: "ArrowDown", + 45: "Insert", + 46: "Delete", + 112: "F1", + 113: "F2", + 114: "F3", + 115: "F4", + 116: "F5", + 117: "F6", + 118: "F7", + 119: "F8", + 120: "F9", + 121: "F10", + 122: "F11", + 123: "F12", + 144: "NumLock", + 145: "ScrollLock", + 224: "Meta" + }, An = { + Alt: "altKey", + Control: "ctrlKey", + Meta: "metaKey", + Shift: "shiftKey" + }; + function jn(e) { + var t = this.nativeEvent; + return t.getModifierState ? t.getModifierState(e) : (e = An[e]) ? !!t[e] : !1; + } + function Mn() { + return jn; + } + var Nn = pn(m({}, gn, { + key: function(e) { + if (e.key) { + var t = On[e.key] || e.key; + if (t !== "Unidentified") return t; + } + return e.type === "keypress" ? (e = un(e), e === 13 ? "Enter" : String.fromCharCode(e)) : e.type === "keydown" || e.type === "keyup" ? kn[e.keyCode] || "Unidentified" : ""; + }, + code: 0, + location: 0, + ctrlKey: 0, + shiftKey: 0, + altKey: 0, + metaKey: 0, + repeat: 0, + locale: 0, + getModifierState: Mn, + charCode: function(e) { + return e.type === "keypress" ? un(e) : 0; + }, + keyCode: function(e) { + return e.type === "keydown" || e.type === "keyup" ? e.keyCode : 0; + }, + which: function(e) { + return e.type === "keypress" ? un(e) : e.type === "keydown" || e.type === "keyup" ? e.keyCode : 0; + } + })), Pn = pn(m({}, xn, { + pointerId: 0, + width: 0, + height: 0, + pressure: 0, + tangentialPressure: 0, + tiltX: 0, + tiltY: 0, + twist: 0, + pointerType: 0, + isPrimary: 0 + })), Fn = pn(m({}, gn, { + touches: 0, + targetTouches: 0, + changedTouches: 0, + altKey: 0, + metaKey: 0, + ctrlKey: 0, + shiftKey: 0, + getModifierState: Mn + })), In = pn(m({}, mn, { + propertyName: 0, + elapsedTime: 0, + pseudoElement: 0 + })), Ln = pn(m({}, xn, { + deltaX: function(e) { + return "deltaX" in e ? e.deltaX : "wheelDeltaX" in e ? -e.wheelDeltaX : 0; + }, + deltaY: function(e) { + return "deltaY" in e ? e.deltaY : "wheelDeltaY" in e ? -e.wheelDeltaY : "wheelDelta" in e ? -e.wheelDelta : 0; + }, + deltaZ: 0, + deltaMode: 0 + })), Rn = pn(m({}, mn, { + newState: 0, + oldState: 0 + })), zn = [ + 9, + 13, + 27, + 32 + ], Bn = nn && "CompositionEvent" in window, Vn = null; + nn && "documentMode" in document && (Vn = document.documentMode); + var Hn = nn && "TextEvent" in window && !Vn, Un = nn && (!Bn || Vn && 8 < Vn && 11 >= Vn), Wn = " ", Gn = !1; + function Kn(e, t) { + switch (e) { + case "keyup": return zn.indexOf(t.keyCode) !== -1; + case "keydown": return t.keyCode !== 229; + case "keypress": + case "mousedown": + case "focusout": return !0; + default: return !1; + } + } + function qn(e) { + return e = e.detail, typeof e == "object" && "data" in e ? e.data : null; + } + var Jn = !1; + function Yn(e, t) { + switch (e) { + case "compositionend": return qn(t); + case "keypress": return t.which === 32 ? (Gn = !0, Wn) : null; + case "textInput": return e = t.data, e === Wn && Gn ? null : e; + default: return null; + } + } + function Xn(e, t) { + if (Jn) return e === "compositionend" || !Bn && Kn(e, t) ? (e = ln(), cn = sn = on = null, Jn = !1, e) : null; + switch (e) { + case "paste": return null; + case "keypress": + if (!(t.ctrlKey || t.altKey || t.metaKey) || t.ctrlKey && t.altKey) { + if (t.char && 1 < t.char.length) return t.char; + if (t.which) return String.fromCharCode(t.which); + } + return null; + case "compositionend": return Un && t.locale !== "ko" ? null : t.data; + default: return null; + } + } + var Zn = { + color: !0, + date: !0, + datetime: !0, + "datetime-local": !0, + email: !0, + month: !0, + number: !0, + password: !0, + range: !0, + search: !0, + tel: !0, + text: !0, + time: !0, + url: !0, + week: !0 + }; + function Qn(e) { + var t = e && e.nodeName && e.nodeName.toLowerCase(); + return t === "input" ? !!Zn[e.type] : t === "textarea"; + } + function $n(e, t, n, r) { + Xt ? Zt ? Zt.push(r) : Zt = [r] : Xt = r, t = Nd(t, "onChange"), 0 < t.length && (n = new hn("onChange", "change", null, n, r), e.push({ + event: n, + listeners: t + })); + } + var er = null, tr = null; + function nr(e) { + Td(e, 0); + } + function rr(e) { + if (kt(ft(e))) return e; + } + function ir(e, t) { + if (e === "change") return t; + } + var ar = !1; + if (nn) { + var or; + if (nn) { + var sr = "oninput" in document; + if (!sr) { + var cr = document.createElement("div"); + cr.setAttribute("oninput", "return;"), sr = typeof cr.oninput == "function"; + } + or = sr; + } else or = !1; + ar = or && (!document.documentMode || 9 < document.documentMode); + } + function lr() { + er && (er.detachEvent("onpropertychange", ur), tr = er = null); + } + function ur(e) { + if (e.propertyName === "value" && rr(tr)) { + var t = []; + $n(t, tr, e, Yt(e)), en(nr, t); + } + } + function dr(e, t, n) { + e === "focusin" ? (lr(), er = t, tr = n, er.attachEvent("onpropertychange", ur)) : e === "focusout" && lr(); + } + function fr(e) { + if (e === "selectionchange" || e === "keyup" || e === "keydown") return rr(tr); + } + function pr(e, t) { + if (e === "click") return rr(t); + } + function mr(e, t) { + if (e === "input" || e === "change") return rr(t); + } + function hr(e, t) { + return e === t && (e !== 0 || 1 / e == 1 / t) || e !== e && t !== t; + } + var gr = typeof Object.is == "function" ? Object.is : hr; + function _r(e, t) { + if (gr(e, t)) return !0; + if (typeof e != "object" || !e || typeof t != "object" || !t) return !1; + var n = Object.keys(e), r = Object.keys(t); + if (n.length !== r.length) return !1; + for (r = 0; r < n.length; r++) { + var i = n[r]; + if (!be.call(t, i) || !gr(e[i], t[i])) return !1; + } + return !0; + } + function vr(e) { + for (; e && e.firstChild;) e = e.firstChild; + return e; + } + function yr(e, t) { + var n = vr(e); + e = 0; + for (var r; n;) { + if (n.nodeType === 3) { + if (r = e + n.textContent.length, e <= t && r >= t) return { + node: n, + offset: t - e + }; + e = r; + } + a: { + for (; n;) { + if (n.nextSibling) { + n = n.nextSibling; + break a; + } + n = n.parentNode; + } + n = void 0; + } + n = vr(n); + } + } + function br(e, t) { + return e && t ? e === t ? !0 : e && e.nodeType === 3 ? !1 : t && t.nodeType === 3 ? br(e, t.parentNode) : "contains" in e ? e.contains(t) : e.compareDocumentPosition ? !!(e.compareDocumentPosition(t) & 16) : !1 : !1; + } + function xr(e) { + e = e != null && e.ownerDocument != null && e.ownerDocument.defaultView != null ? e.ownerDocument.defaultView : window; + for (var t = At(e.document); t instanceof e.HTMLIFrameElement;) { + try { + var n = typeof t.contentWindow.location.href == "string"; + } catch { + n = !1; + } + if (n) e = t.contentWindow; + else break; + t = At(e.document); + } + return t; + } + function Sr(e) { + var t = e && e.nodeName && e.nodeName.toLowerCase(); + return t && (t === "input" && (e.type === "text" || e.type === "search" || e.type === "tel" || e.type === "url" || e.type === "password") || t === "textarea" || e.contentEditable === "true"); + } + var Cr = nn && "documentMode" in document && 11 >= document.documentMode, wr = null, Tr = null, Er = null, Dr = !1; + function Or(e, t, n) { + var r = n.window === n ? n.document : n.nodeType === 9 ? n : n.ownerDocument; + Dr || wr == null || wr !== At(r) || (r = wr, "selectionStart" in r && Sr(r) ? r = { + start: r.selectionStart, + end: r.selectionEnd + } : (r = (r.ownerDocument && r.ownerDocument.defaultView || window).getSelection(), r = { + anchorNode: r.anchorNode, + anchorOffset: r.anchorOffset, + focusNode: r.focusNode, + focusOffset: r.focusOffset + }), Er && _r(Er, r) || (Er = r, r = Nd(Tr, "onSelect"), 0 < r.length && (t = new hn("onSelect", "select", null, t, n), e.push({ + event: t, + listeners: r + }), t.target = wr))); + } + function kr(e, t) { + var n = {}; + return n[e.toLowerCase()] = t.toLowerCase(), n["Webkit" + e] = "webkit" + t, n["Moz" + e] = "moz" + t, n; + } + var Ar = { + animationend: kr("Animation", "AnimationEnd"), + animationiteration: kr("Animation", "AnimationIteration"), + animationstart: kr("Animation", "AnimationStart"), + transitionrun: kr("Transition", "TransitionRun"), + transitionstart: kr("Transition", "TransitionStart"), + transitioncancel: kr("Transition", "TransitionCancel"), + transitionend: kr("Transition", "TransitionEnd") + }, jr = {}, Mr = {}; + nn && (Mr = document.createElement("div").style, "AnimationEvent" in window || (delete Ar.animationend.animation, delete Ar.animationiteration.animation, delete Ar.animationstart.animation), "TransitionEvent" in window || delete Ar.transitionend.transition); + function Nr(e) { + if (jr[e]) return jr[e]; + if (!Ar[e]) return e; + var t = Ar[e], n; + for (n in t) if (t.hasOwnProperty(n) && n in Mr) return jr[e] = t[n]; + return e; + } + var Pr = Nr("animationend"), Fr = Nr("animationiteration"), Ir = Nr("animationstart"), Lr = Nr("transitionrun"), Rr = Nr("transitionstart"), zr = Nr("transitioncancel"), Br = Nr("transitionend"), Vr = /* @__PURE__ */ new Map(), Hr = "abort auxClick beforeToggle cancel canPlay canPlayThrough click close contextMenu copy cut drag dragEnd dragEnter dragExit dragLeave dragOver dragStart drop durationChange emptied encrypted ended error gotPointerCapture input invalid keyDown keyPress keyUp load loadedData loadedMetadata loadStart lostPointerCapture mouseDown mouseMove mouseOut mouseOver mouseUp paste pause play playing pointerCancel pointerDown pointerMove pointerOut pointerOver pointerUp progress rateChange reset resize seeked seeking stalled submit suspend timeUpdate touchCancel touchEnd touchStart volumeChange scroll toggle touchMove waiting wheel".split(" "); + Hr.push("scrollEnd"); + function Ur(e, t) { + Vr.set(e, t), W(t, [e]); + } + var Wr = typeof reportError == "function" ? reportError : function(e) { + if (typeof window == "object" && typeof window.ErrorEvent == "function") { + var t = new window.ErrorEvent("error", { + bubbles: !0, + cancelable: !0, + message: typeof e == "object" && e && typeof e.message == "string" ? String(e.message) : String(e), + error: e + }); + if (!window.dispatchEvent(t)) return; + } else if (typeof process == "object" && typeof process.emit == "function") { + process.emit("uncaughtException", e); + return; + } + console.error(e); + }, Gr = [], Kr = 0, qr = 0; + function Jr() { + for (var e = Kr, t = qr = Kr = 0; t < e;) { + var n = Gr[t]; + Gr[t++] = null; + var r = Gr[t]; + Gr[t++] = null; + var i = Gr[t]; + Gr[t++] = null; + var a = Gr[t]; + if (Gr[t++] = null, r !== null && i !== null) { + var o = r.pending; + o === null ? i.next = i : (i.next = o.next, o.next = i), r.pending = i; + } + a !== 0 && Qr(n, i, a); + } + } + function Yr(e, t, n, r) { + Gr[Kr++] = e, Gr[Kr++] = t, Gr[Kr++] = n, Gr[Kr++] = r, qr |= r, e.lanes |= r, e = e.alternate, e !== null && (e.lanes |= r); + } + function Xr(e, t, n, r) { + return Yr(e, t, n, r), $r(e); + } + function Zr(e, t) { + return Yr(e, null, null, t), $r(e); + } + function Qr(e, t, n) { + e.lanes |= n; + var r = e.alternate; + r !== null && (r.lanes |= n); + for (var i = !1, a = e.return; a !== null;) a.childLanes |= n, r = a.alternate, r !== null && (r.childLanes |= n), a.tag === 22 && (e = a.stateNode, e === null || e._visibility & 1 || (i = !0)), e = a, a = a.return; + return e.tag === 3 ? (a = e.stateNode, i && t !== null && (i = 31 - Fe(n), e = a.hiddenUpdates, r = e[i], r === null ? e[i] = [t] : r.push(t), t.lane = n | 536870912), a) : null; + } + function $r(e) { + if (50 < gu) throw gu = 0, _u = null, Error(i(185)); + for (var t = e.return; t !== null;) e = t, t = e.return; + return e.tag === 3 ? e.stateNode : null; + } + var ei = {}; + function ti(e, t, n, r) { + this.tag = e, this.key = n, this.sibling = this.child = this.return = this.stateNode = this.type = this.elementType = null, this.index = 0, this.refCleanup = this.ref = null, this.pendingProps = t, this.dependencies = this.memoizedState = this.updateQueue = this.memoizedProps = null, this.mode = r, this.subtreeFlags = this.flags = 0, this.deletions = null, this.childLanes = this.lanes = 0, this.alternate = null; + } + function ni(e, t, n, r) { + return new ti(e, t, n, r); + } + function ri(e) { + return e = e.prototype, !(!e || !e.isReactComponent); + } + function ii(e, t) { + var n = e.alternate; + return n === null ? (n = ni(e.tag, t, e.key, e.mode), n.elementType = e.elementType, n.type = e.type, n.stateNode = e.stateNode, n.alternate = e, e.alternate = n) : (n.pendingProps = t, n.type = e.type, n.flags = 0, n.subtreeFlags = 0, n.deletions = null), n.flags = e.flags & 65011712, n.childLanes = e.childLanes, n.lanes = e.lanes, n.child = e.child, n.memoizedProps = e.memoizedProps, n.memoizedState = e.memoizedState, n.updateQueue = e.updateQueue, t = e.dependencies, n.dependencies = t === null ? null : { + lanes: t.lanes, + firstContext: t.firstContext + }, n.sibling = e.sibling, n.index = e.index, n.ref = e.ref, n.refCleanup = e.refCleanup, n; + } + function ai(e, t) { + e.flags &= 65011714; + var n = e.alternate; + return n === null ? (e.childLanes = 0, e.lanes = t, e.child = null, e.subtreeFlags = 0, e.memoizedProps = null, e.memoizedState = null, e.updateQueue = null, e.dependencies = null, e.stateNode = null) : (e.childLanes = n.childLanes, e.lanes = n.lanes, e.child = n.child, e.subtreeFlags = 0, e.deletions = null, e.memoizedProps = n.memoizedProps, e.memoizedState = n.memoizedState, e.updateQueue = n.updateQueue, e.type = n.type, t = n.dependencies, e.dependencies = t === null ? null : { + lanes: t.lanes, + firstContext: t.firstContext + }), e; + } + function oi(e, t, n, r, a, o) { + var s = 0; + if (r = e, typeof e == "function") ri(e) && (s = 1); + else if (typeof e == "string") s = Zf(e, n, P.current) ? 26 : e === "html" || e === "head" || e === "body" ? 27 : 5; + else a: switch (e) { + case ee: return e = ni(31, n, t, a), e.elementType = ee, e.lanes = o, e; + case y: return si(n.children, a, o, t); + case b: + s = 8, a |= 24; + break; + case x: return e = ni(12, n, t, a | 2), e.elementType = x, e.lanes = o, e; + case T: return e = ni(13, n, t, a), e.elementType = T, e.lanes = o, e; + case E: return e = ni(19, n, t, a), e.elementType = E, e.lanes = o, e; + default: + if (typeof e == "object" && e) switch (e.$$typeof) { + case C: + s = 10; + break a; + case S: + s = 9; + break a; + case w: + s = 11; + break a; + case D: + s = 14; + break a; + case O: + s = 16, r = null; + break a; + } + s = 29, n = Error(i(130, e === null ? "null" : typeof e, "")), r = null; + } + return t = ni(s, n, t, a), t.elementType = e, t.type = r, t.lanes = o, t; + } + function si(e, t, n, r) { + return e = ni(7, e, r, t), e.lanes = n, e; + } + function ci(e, t, n) { + return e = ni(6, e, null, t), e.lanes = n, e; + } + function li(e) { + var t = ni(18, null, null, 0); + return t.stateNode = e, t; + } + function ui(e, t, n) { + return t = ni(4, e.children === null ? [] : e.children, e.key, t), t.lanes = n, t.stateNode = { + containerInfo: e.containerInfo, + pendingChildren: null, + implementation: e.implementation + }, t; + } + var di = /* @__PURE__ */ new WeakMap(); + function fi(e, t) { + if (typeof e == "object" && e) { + var n = di.get(e); + return n === void 0 ? (t = { + value: e, + source: t, + stack: ye(t) + }, di.set(e, t), t) : n; + } + return { + value: e, + source: t, + stack: ye(t) + }; + } + var pi = [], mi = 0, hi = null, gi = 0, _i = [], vi = 0, yi = null, bi = 1, xi = ""; + function Si(e, t) { + pi[mi++] = gi, pi[mi++] = hi, hi = e, gi = t; + } + function Ci(e, t, n) { + _i[vi++] = bi, _i[vi++] = xi, _i[vi++] = yi, yi = e; + var r = bi; + e = xi; + var i = 32 - Fe(r) - 1; + r &= ~(1 << i), n += 1; + var a = 32 - Fe(t) + i; + if (30 < a) { + var o = i - i % 5; + a = (r & (1 << o) - 1).toString(32), r >>= o, i -= o, bi = 1 << 32 - Fe(t) + i | n << i | r, xi = a + e; + } else bi = 1 << a | n << i | r, xi = e; + } + function wi(e) { + e.return !== null && (Si(e, 1), Ci(e, 1, 0)); + } + function Ti(e) { + for (; e === hi;) hi = pi[--mi], pi[mi] = null, gi = pi[--mi], pi[mi] = null; + for (; e === yi;) yi = _i[--vi], _i[vi] = null, xi = _i[--vi], _i[vi] = null, bi = _i[--vi], _i[vi] = null; + } + function Ei(e, t) { + _i[vi++] = bi, _i[vi++] = xi, _i[vi++] = yi, bi = t.id, xi = t.overflow, yi = e; + } + var Di = null, Oi = null, ki = !1, Ai = null, ji = !1, Mi = Error(i(519)); + function Ni(e) { + throw zi(fi(Error(i(418, 1 < arguments.length && arguments[1] !== void 0 && arguments[1] ? "text" : "HTML", "")), e)), Mi; + } + function Pi(e) { + var t = e.stateNode, n = e.type, r = e.memoizedProps; + switch (t[tt] = e, t[nt] = r, n) { + case "dialog": + Ed("cancel", t), Ed("close", t); + break; + case "iframe": + case "object": + case "embed": + Ed("load", t); + break; + case "video": + case "audio": + for (n = 0; n < Cd.length; n++) Ed(Cd[n], t); + break; + case "source": + Ed("error", t); + break; + case "img": + case "image": + case "link": + Ed("error", t), Ed("load", t); + break; + case "details": + Ed("toggle", t); + break; + case "input": + Ed("invalid", t), Pt(t, r.value, r.defaultValue, r.checked, r.defaultChecked, r.type, r.name, !0); + break; + case "select": + Ed("invalid", t); + break; + case "textarea": Ed("invalid", t), Rt(t, r.value, r.defaultValue, r.children); + } + n = r.children, typeof n != "string" && typeof n != "number" && typeof n != "bigint" || t.textContent === "" + n || !0 === r.suppressHydrationWarning || zd(t.textContent, n) ? (r.popover != null && (Ed("beforetoggle", t), Ed("toggle", t)), r.onScroll != null && Ed("scroll", t), r.onScrollEnd != null && Ed("scrollend", t), r.onClick != null && (t.onclick = qt), t = !0) : t = !1, t || Ni(e, !0); + } + function Fi(e) { + for (Di = e.return; Di;) switch (Di.tag) { + case 5: + case 31: + case 13: + ji = !1; + return; + case 27: + case 3: + ji = !0; + return; + default: Di = Di.return; + } + } + function Ii(e) { + if (e !== Di) return !1; + if (!ki) return Fi(e), ki = !0, !1; + var t = e.tag, n; + if ((n = t !== 3 && t !== 27) && ((n = t === 5) && (n = e.type, n = n === "form" || n === "button" || Zd(e.type, e.memoizedProps)), n = !n), n && Oi && Ni(e), Fi(e), t === 13) { + if (e = e.memoizedState, e = e === null ? null : e.dehydrated, !e) throw Error(i(317)); + Oi = vf(e); + } else if (t === 31) { + if (e = e.memoizedState, e = e === null ? null : e.dehydrated, !e) throw Error(i(317)); + Oi = vf(e); + } else t === 27 ? (t = Oi, of(e.type) ? (e = _f, _f = null, Oi = e) : Oi = t) : Oi = Di ? gf(e.stateNode.nextSibling) : null; + return !0; + } + function Li() { + Oi = Di = null, ki = !1; + } + function Ri() { + var e = Ai; + return e !== null && (nu === null ? nu = e : nu.push.apply(nu, e), Ai = null), e; + } + function zi(e) { + Ai === null ? Ai = [e] : Ai.push(e); + } + var G = ce(null), Bi = null, Vi = null; + function Hi(e, t, n) { + N(G, t._currentValue), t._currentValue = n; + } + function Ui(e) { + e._currentValue = G.current, le(G); + } + function Wi(e, t, n) { + for (; e !== null;) { + var r = e.alternate; + if ((e.childLanes & t) === t ? r !== null && (r.childLanes & t) !== t && (r.childLanes |= t) : (e.childLanes |= t, r !== null && (r.childLanes |= t)), e === n) break; + e = e.return; + } + } + function Gi(e, t, n, r) { + var a = e.child; + for (a !== null && (a.return = e); a !== null;) { + var o = a.dependencies; + if (o !== null) { + var s = a.child; + o = o.firstContext; + a: for (; o !== null;) { + var c = o; + o = a; + for (var l = 0; l < t.length; l++) if (c.context === t[l]) { + o.lanes |= n, c = o.alternate, c !== null && (c.lanes |= n), Wi(o.return, n, e), r || (s = null); + break a; + } + o = c.next; + } + } else if (a.tag === 18) { + if (s = a.return, s === null) throw Error(i(341)); + s.lanes |= n, o = s.alternate, o !== null && (o.lanes |= n), Wi(s, n, e), s = null; + } else s = a.child; + if (s !== null) s.return = a; + else for (s = a; s !== null;) { + if (s === e) { + s = null; + break; + } + if (a = s.sibling, a !== null) { + a.return = s.return, s = a; + break; + } + s = s.return; + } + a = s; + } + } + function Ki(e, t, n, r) { + e = null; + for (var a = t, o = !1; a !== null;) { + if (!o) { + if (a.flags & 524288) o = !0; + else if (a.flags & 262144) break; + } + if (a.tag === 10) { + var s = a.alternate; + if (s === null) throw Error(i(387)); + if (s = s.memoizedProps, s !== null) { + var c = a.type; + gr(a.pendingProps.value, s.value) || (e === null ? e = [c] : e.push(c)); + } + } else if (a === I.current) { + if (s = a.alternate, s === null) throw Error(i(387)); + s.memoizedState.memoizedState !== a.memoizedState.memoizedState && (e === null ? e = [op] : e.push(op)); + } + a = a.return; + } + e !== null && Gi(t, e, n, r), t.flags |= 262144; + } + function qi(e) { + for (e = e.firstContext; e !== null;) { + if (!gr(e.context._currentValue, e.memoizedValue)) return !0; + e = e.next; + } + return !1; + } + function Ji(e) { + Bi = e, Vi = null, e = e.dependencies, e !== null && (e.firstContext = null); + } + function Yi(e) { + return Zi(Bi, e); + } + function Xi(e, t) { + return Bi === null && Ji(e), Zi(e, t); + } + function Zi(e, t) { + var n = t._currentValue; + if (t = { + context: t, + memoizedValue: n, + next: null + }, Vi === null) { + if (e === null) throw Error(i(308)); + Vi = t, e.dependencies = { + lanes: 0, + firstContext: t + }, e.flags |= 524288; + } else Vi = Vi.next = t; + return n; + } + var Qi = typeof AbortController < "u" ? AbortController : function() { + var e = [], t = this.signal = { + aborted: !1, + addEventListener: function(t, n) { + e.push(n); + } + }; + this.abort = function() { + t.aborted = !0, e.forEach(function(e) { + return e(); + }); + }; + }, $i = t.unstable_scheduleCallback, ea = t.unstable_NormalPriority, ta = { + $$typeof: C, + Consumer: null, + Provider: null, + _currentValue: null, + _currentValue2: null, + _threadCount: 0 + }; + function na() { + return { + controller: new Qi(), + data: /* @__PURE__ */ new Map(), + refCount: 0 + }; + } + function ra(e) { + e.refCount--, e.refCount === 0 && $i(ea, function() { + e.controller.abort(); + }); + } + var ia = null, aa = 0, oa = 0, sa = null; + function ca(e, t) { + if (ia === null) { + var n = ia = []; + aa = 0, oa = _d(), sa = { + status: "pending", + value: void 0, + then: function(e) { + n.push(e); + } + }; + } + return aa++, t.then(la, la), t; + } + function la() { + if (--aa === 0 && ia !== null) { + sa !== null && (sa.status = "fulfilled"); + var e = ia; + ia = null, oa = 0, sa = null; + for (var t = 0; t < e.length; t++) (0, e[t])(); + } + } + function ua(e, t) { + var n = [], r = { + status: "pending", + value: null, + reason: null, + then: function(e) { + n.push(e); + } + }; + return e.then(function() { + r.status = "fulfilled", r.value = t; + for (var e = 0; e < n.length; e++) (0, n[e])(t); + }, function(e) { + for (r.status = "rejected", r.reason = e, e = 0; e < n.length; e++) (0, n[e])(void 0); + }), r; + } + var da = A.S; + A.S = function(e, t) { + au = Te(), typeof t == "object" && t && typeof t.then == "function" && ca(e, t), da !== null && da(e, t); + }; + var fa = ce(null); + function pa() { + var e = fa.current; + return e === null ? Bl.pooledCache : e; + } + function ma(e, t) { + t === null ? N(fa, fa.current) : N(fa, t.pool); + } + function ha() { + var e = pa(); + return e === null ? null : { + parent: ta._currentValue, + pool: e + }; + } + var ga = Error(i(460)), _a = Error(i(474)), va = Error(i(542)), ya = { then: function() {} }; + function ba(e) { + return e = e.status, e === "fulfilled" || e === "rejected"; + } + function xa(e, t, n) { + switch (n = e[n], n === void 0 ? e.push(t) : n !== t && (t.then(qt, qt), t = n), t.status) { + case "fulfilled": return t.value; + case "rejected": throw e = t.reason, Ta(e), e; + default: + if (typeof t.status == "string") t.then(qt, qt); + else { + if (e = Bl, e !== null && 100 < e.shellSuspendCounter) throw Error(i(482)); + e = t, e.status = "pending", e.then(function(e) { + if (t.status === "pending") { + var n = t; + n.status = "fulfilled", n.value = e; + } + }, function(e) { + if (t.status === "pending") { + var n = t; + n.status = "rejected", n.reason = e; + } + }); + } + switch (t.status) { + case "fulfilled": return t.value; + case "rejected": throw e = t.reason, Ta(e), e; + } + throw Ca = t, ga; + } + } + function Sa(e) { + try { + var t = e._init; + return t(e._payload); + } catch (e) { + throw typeof e == "object" && e && typeof e.then == "function" ? (Ca = e, ga) : e; + } + } + var Ca = null; + function wa() { + if (Ca === null) throw Error(i(459)); + var e = Ca; + return Ca = null, e; + } + function Ta(e) { + if (e === ga || e === va) throw Error(i(483)); + } + var Ea = null, Da = 0; + function Oa(e) { + var t = Da; + return Da += 1, Ea === null && (Ea = []), xa(Ea, e, t); + } + function ka(e, t) { + t = t.props.ref, e.ref = t === void 0 ? null : t; + } + function Aa(e, t) { + throw t.$$typeof === g ? Error(i(525)) : (e = Object.prototype.toString.call(t), Error(i(31, e === "[object Object]" ? "object with keys {" + Object.keys(t).join(", ") + "}" : e))); + } + function ja(e) { + function t(t, n) { + if (e) { + var r = t.deletions; + r === null ? (t.deletions = [n], t.flags |= 16) : r.push(n); + } + } + function n(n, r) { + if (!e) return null; + for (; r !== null;) t(n, r), r = r.sibling; + return null; + } + function r(e) { + for (var t = /* @__PURE__ */ new Map(); e !== null;) e.key === null ? t.set(e.index, e) : t.set(e.key, e), e = e.sibling; + return t; + } + function a(e, t) { + return e = ii(e, t), e.index = 0, e.sibling = null, e; + } + function o(t, n, r) { + return t.index = r, e ? (r = t.alternate, r === null ? (t.flags |= 67108866, n) : (r = r.index, r < n ? (t.flags |= 67108866, n) : r)) : (t.flags |= 1048576, n); + } + function s(t) { + return e && t.alternate === null && (t.flags |= 67108866), t; + } + function c(e, t, n, r) { + return t === null || t.tag !== 6 ? (t = ci(n, e.mode, r), t.return = e, t) : (t = a(t, n), t.return = e, t); + } + function l(e, t, n, r) { + var i = n.type; + return i === y ? d(e, t, n.props.children, r, n.key) : t !== null && (t.elementType === i || typeof i == "object" && i && i.$$typeof === O && Sa(i) === t.type) ? (t = a(t, n.props), ka(t, n), t.return = e, t) : (t = oi(n.type, n.key, n.props, null, e.mode, r), ka(t, n), t.return = e, t); + } + function u(e, t, n, r) { + return t === null || t.tag !== 4 || t.stateNode.containerInfo !== n.containerInfo || t.stateNode.implementation !== n.implementation ? (t = ui(n, e.mode, r), t.return = e, t) : (t = a(t, n.children || []), t.return = e, t); + } + function d(e, t, n, r, i) { + return t === null || t.tag !== 7 ? (t = si(n, e.mode, r, i), t.return = e, t) : (t = a(t, n), t.return = e, t); + } + function f(e, t, n) { + if (typeof t == "string" && t !== "" || typeof t == "number" || typeof t == "bigint") return t = ci("" + t, e.mode, n), t.return = e, t; + if (typeof t == "object" && t) { + switch (t.$$typeof) { + case _: return n = oi(t.type, t.key, t.props, null, e.mode, n), ka(n, t), n.return = e, n; + case v: return t = ui(t, e.mode, n), t.return = e, t; + case O: return t = Sa(t), f(e, t, n); + } + if (ae(t) || re(t)) return t = si(t, e.mode, n, null), t.return = e, t; + if (typeof t.then == "function") return f(e, Oa(t), n); + if (t.$$typeof === C) return f(e, Xi(e, t), n); + Aa(e, t); + } + return null; + } + function p(e, t, n, r) { + var i = t === null ? null : t.key; + if (typeof n == "string" && n !== "" || typeof n == "number" || typeof n == "bigint") return i === null ? c(e, t, "" + n, r) : null; + if (typeof n == "object" && n) { + switch (n.$$typeof) { + case _: return n.key === i ? l(e, t, n, r) : null; + case v: return n.key === i ? u(e, t, n, r) : null; + case O: return n = Sa(n), p(e, t, n, r); + } + if (ae(n) || re(n)) return i === null ? d(e, t, n, r, null) : null; + if (typeof n.then == "function") return p(e, t, Oa(n), r); + if (n.$$typeof === C) return p(e, t, Xi(e, n), r); + Aa(e, n); + } + return null; + } + function m(e, t, n, r, i) { + if (typeof r == "string" && r !== "" || typeof r == "number" || typeof r == "bigint") return e = e.get(n) || null, c(t, e, "" + r, i); + if (typeof r == "object" && r) { + switch (r.$$typeof) { + case _: return e = e.get(r.key === null ? n : r.key) || null, l(t, e, r, i); + case v: return e = e.get(r.key === null ? n : r.key) || null, u(t, e, r, i); + case O: return r = Sa(r), m(e, t, n, r, i); + } + if (ae(r) || re(r)) return e = e.get(n) || null, d(t, e, r, i, null); + if (typeof r.then == "function") return m(e, t, n, Oa(r), i); + if (r.$$typeof === C) return m(e, t, n, Xi(t, r), i); + Aa(t, r); + } + return null; + } + function h(i, a, s, c) { + for (var l = null, u = null, d = a, h = a = 0, g = null; d !== null && h < s.length; h++) { + d.index > h ? (g = d, d = null) : g = d.sibling; + var _ = p(i, d, s[h], c); + if (_ === null) { + d === null && (d = g); + break; + } + e && d && _.alternate === null && t(i, d), a = o(_, a, h), u === null ? l = _ : u.sibling = _, u = _, d = g; + } + if (h === s.length) return n(i, d), ki && Si(i, h), l; + if (d === null) { + for (; h < s.length; h++) d = f(i, s[h], c), d !== null && (a = o(d, a, h), u === null ? l = d : u.sibling = d, u = d); + return ki && Si(i, h), l; + } + for (d = r(d); h < s.length; h++) g = m(d, i, h, s[h], c), g !== null && (e && g.alternate !== null && d.delete(g.key === null ? h : g.key), a = o(g, a, h), u === null ? l = g : u.sibling = g, u = g); + return e && d.forEach(function(e) { + return t(i, e); + }), ki && Si(i, h), l; + } + function g(a, s, c, l) { + if (c == null) throw Error(i(151)); + for (var u = null, d = null, h = s, g = s = 0, _ = null, v = c.next(); h !== null && !v.done; g++, v = c.next()) { + h.index > g ? (_ = h, h = null) : _ = h.sibling; + var y = p(a, h, v.value, l); + if (y === null) { + h === null && (h = _); + break; + } + e && h && y.alternate === null && t(a, h), s = o(y, s, g), d === null ? u = y : d.sibling = y, d = y, h = _; + } + if (v.done) return n(a, h), ki && Si(a, g), u; + if (h === null) { + for (; !v.done; g++, v = c.next()) v = f(a, v.value, l), v !== null && (s = o(v, s, g), d === null ? u = v : d.sibling = v, d = v); + return ki && Si(a, g), u; + } + for (h = r(h); !v.done; g++, v = c.next()) v = m(h, a, g, v.value, l), v !== null && (e && v.alternate !== null && h.delete(v.key === null ? g : v.key), s = o(v, s, g), d === null ? u = v : d.sibling = v, d = v); + return e && h.forEach(function(e) { + return t(a, e); + }), ki && Si(a, g), u; + } + function b(e, r, o, c) { + if (typeof o == "object" && o && o.type === y && o.key === null && (o = o.props.children), typeof o == "object" && o) { + switch (o.$$typeof) { + case _: + a: { + for (var l = o.key; r !== null;) { + if (r.key === l) { + if (l = o.type, l === y) { + if (r.tag === 7) { + n(e, r.sibling), c = a(r, o.props.children), c.return = e, e = c; + break a; + } + } else if (r.elementType === l || typeof l == "object" && l && l.$$typeof === O && Sa(l) === r.type) { + n(e, r.sibling), c = a(r, o.props), ka(c, o), c.return = e, e = c; + break a; + } + n(e, r); + break; + } + t(e, r), r = r.sibling; + } + o.type === y ? (c = si(o.props.children, e.mode, c, o.key), c.return = e, e = c) : (c = oi(o.type, o.key, o.props, null, e.mode, c), ka(c, o), c.return = e, e = c); + } + return s(e); + case v: + a: { + for (l = o.key; r !== null;) { + if (r.key === l) { + if (r.tag === 4 && r.stateNode.containerInfo === o.containerInfo && r.stateNode.implementation === o.implementation) { + n(e, r.sibling), c = a(r, o.children || []), c.return = e, e = c; + break a; + } + n(e, r); + break; + } + t(e, r), r = r.sibling; + } + c = ui(o, e.mode, c), c.return = e, e = c; + } + return s(e); + case O: return o = Sa(o), b(e, r, o, c); + } + if (ae(o)) return h(e, r, o, c); + if (re(o)) { + if (l = re(o), typeof l != "function") throw Error(i(150)); + return o = l.call(o), g(e, r, o, c); + } + if (typeof o.then == "function") return b(e, r, Oa(o), c); + if (o.$$typeof === C) return b(e, r, Xi(e, o), c); + Aa(e, o); + } + return typeof o == "string" && o !== "" || typeof o == "number" || typeof o == "bigint" ? (o = "" + o, r !== null && r.tag === 6 ? (n(e, r.sibling), c = a(r, o), c.return = e, e = c) : (n(e, r), c = ci(o, e.mode, c), c.return = e, e = c), s(e)) : n(e, r); + } + return function(e, t, n, r) { + try { + Da = 0; + var i = b(e, t, n, r); + return Ea = null, i; + } catch (t) { + if (t === ga || t === va) throw t; + var a = ni(29, t, null, e.mode); + return a.lanes = r, a.return = e, a; + } + }; + } + var Ma = ja(!0), Na = ja(!1), Pa = !1; + function Fa(e) { + e.updateQueue = { + baseState: e.memoizedState, + firstBaseUpdate: null, + lastBaseUpdate: null, + shared: { + pending: null, + lanes: 0, + hiddenCallbacks: null + }, + callbacks: null + }; + } + function Ia(e, t) { + e = e.updateQueue, t.updateQueue === e && (t.updateQueue = { + baseState: e.baseState, + firstBaseUpdate: e.firstBaseUpdate, + lastBaseUpdate: e.lastBaseUpdate, + shared: e.shared, + callbacks: null + }); + } + function La(e) { + return { + lane: e, + tag: 0, + payload: null, + callback: null, + next: null + }; + } + function Ra(e, t, n) { + var r = e.updateQueue; + if (r === null) return null; + if (r = r.shared, zl & 2) { + var i = r.pending; + return i === null ? t.next = t : (t.next = i.next, i.next = t), r.pending = t, t = $r(e), Qr(e, null, n), t; + } + return Yr(e, r, t, n), $r(e); + } + function za(e, t, n) { + if (t = t.updateQueue, t !== null && (t = t.shared, n & 4194048)) { + var r = t.lanes; + r &= e.pendingLanes, n |= r, t.lanes = n, Je(e, n); + } + } + function Ba(e, t) { + var n = e.updateQueue, r = e.alternate; + if (r !== null && (r = r.updateQueue, n === r)) { + var i = null, a = null; + if (n = n.firstBaseUpdate, n !== null) { + do { + var o = { + lane: n.lane, + tag: n.tag, + payload: n.payload, + callback: null, + next: null + }; + a === null ? i = a = o : a = a.next = o, n = n.next; + } while (n !== null); + a === null ? i = a = t : a = a.next = t; + } else i = a = t; + n = { + baseState: r.baseState, + firstBaseUpdate: i, + lastBaseUpdate: a, + shared: r.shared, + callbacks: r.callbacks + }, e.updateQueue = n; + return; + } + e = n.lastBaseUpdate, e === null ? n.firstBaseUpdate = t : e.next = t, n.lastBaseUpdate = t; + } + var Va = !1; + function Ha() { + if (Va) { + var e = sa; + if (e !== null) throw e; + } + } + function Ua(e, t, n, r) { + Va = !1; + var i = e.updateQueue; + Pa = !1; + var a = i.firstBaseUpdate, o = i.lastBaseUpdate, s = i.shared.pending; + if (s !== null) { + i.shared.pending = null; + var c = s, l = c.next; + c.next = null, o === null ? a = l : o.next = l, o = c; + var u = e.alternate; + u !== null && (u = u.updateQueue, s = u.lastBaseUpdate, s !== o && (s === null ? u.firstBaseUpdate = l : s.next = l, u.lastBaseUpdate = c)); + } + if (a !== null) { + var d = i.baseState; + o = 0, u = l = c = null, s = a; + do { + var f = s.lane & -536870913, p = f !== s.lane; + if (p ? (Hl & f) === f : (r & f) === f) { + f !== 0 && f === oa && (Va = !0), u !== null && (u = u.next = { + lane: 0, + tag: s.tag, + payload: s.payload, + callback: null, + next: null + }); + a: { + var h = e, g = s; + f = t; + var _ = n; + switch (g.tag) { + case 1: + if (h = g.payload, typeof h == "function") { + d = h.call(_, d, f); + break a; + } + d = h; + break a; + case 3: h.flags = h.flags & -65537 | 128; + case 0: + if (h = g.payload, f = typeof h == "function" ? h.call(_, d, f) : h, f == null) break a; + d = m({}, d, f); + break a; + case 2: Pa = !0; + } + } + f = s.callback, f !== null && (e.flags |= 64, p && (e.flags |= 8192), p = i.callbacks, p === null ? i.callbacks = [f] : p.push(f)); + } else p = { + lane: f, + tag: s.tag, + payload: s.payload, + callback: s.callback, + next: null + }, u === null ? (l = u = p, c = d) : u = u.next = p, o |= f; + if (s = s.next, s === null) { + if (s = i.shared.pending, s === null) break; + p = s, s = p.next, p.next = null, i.lastBaseUpdate = p, i.shared.pending = null; + } + } while (1); + u === null && (c = d), i.baseState = c, i.firstBaseUpdate = l, i.lastBaseUpdate = u, a === null && (i.shared.lanes = 0), Xl |= o, e.lanes = o, e.memoizedState = d; + } + } + function Wa(e, t) { + if (typeof e != "function") throw Error(i(191, e)); + e.call(t); + } + function Ga(e, t) { + var n = e.callbacks; + if (n !== null) for (e.callbacks = null, e = 0; e < n.length; e++) Wa(n[e], t); + } + var Ka = ce(null), qa = ce(0); + function Ja(e, t) { + e = Jl, N(qa, e), N(Ka, t), Jl = e | t.baseLanes; + } + function Ya() { + N(qa, Jl), N(Ka, Ka.current); + } + function Xa() { + Jl = qa.current, le(Ka), le(qa); + } + var Za = ce(null), Qa = null; + function $a(e) { + var t = e.alternate; + N(io, io.current & 1), N(Za, e), Qa === null && (t === null || Ka.current !== null || t.memoizedState !== null) && (Qa = e); + } + function eo(e) { + N(io, io.current), N(Za, e), Qa === null && (Qa = e); + } + function to(e) { + e.tag === 22 ? (N(io, io.current), N(Za, e), Qa === null && (Qa = e)) : no(e); + } + function no() { + N(io, io.current), N(Za, Za.current); + } + function ro(e) { + le(Za), Qa === e && (Qa = null), le(io); + } + var io = ce(0); + function ao(e) { + for (var t = e; t !== null;) { + if (t.tag === 13) { + var n = t.memoizedState; + if (n !== null && (n = n.dehydrated, n === null || pf(n) || mf(n))) return t; + } else if (t.tag === 19 && (t.memoizedProps.revealOrder === "forwards" || t.memoizedProps.revealOrder === "backwards" || t.memoizedProps.revealOrder === "unstable_legacy-backwards" || t.memoizedProps.revealOrder === "together")) { + if (t.flags & 128) return t; + } else if (t.child !== null) { + t.child.return = t, t = t.child; + continue; + } + if (t === e) break; + for (; t.sibling === null;) { + if (t.return === null || t.return === e) return null; + t = t.return; + } + t.sibling.return = t.return, t = t.sibling; + } + return null; + } + var oo = 0, so = null, co = null, lo = null, uo = !1, fo = !1, po = !1, mo = 0, ho = 0, go = null, _o = 0; + function vo() { + throw Error(i(321)); + } + function yo(e, t) { + if (t === null) return !1; + for (var n = 0; n < t.length && n < e.length; n++) if (!gr(e[n], t[n])) return !1; + return !0; + } + function bo(e, t, n, r, i, a) { + return oo = a, so = t, t.memoizedState = null, t.updateQueue = null, t.lanes = 0, A.H = e === null || e.memoizedState === null ? Ls : Rs, po = !1, a = n(r, i), po = !1, fo && (a = So(t, n, r, i)), xo(e), a; + } + function xo(e) { + A.H = Is; + var t = co !== null && co.next !== null; + if (oo = 0, lo = co = so = null, uo = !1, ho = 0, go = null, t) throw Error(i(300)); + e === null || tc || (e = e.dependencies, e !== null && qi(e) && (tc = !0)); + } + function So(e, t, n, r) { + so = e; + var a = 0; + do { + if (fo && (go = null), ho = 0, fo = !1, 25 <= a) throw Error(i(301)); + if (a += 1, lo = co = null, e.updateQueue != null) { + var o = e.updateQueue; + o.lastEffect = null, o.events = null, o.stores = null, o.memoCache != null && (o.memoCache.index = 0); + } + A.H = zs, o = t(n, r); + } while (fo); + return o; + } + function Co() { + var e = A.H, t = e.useState()[0]; + return t = typeof t.then == "function" ? Ao(t) : t, e = e.useState()[0], (co === null ? null : co.memoizedState) !== e && (so.flags |= 1024), t; + } + function wo() { + var e = mo !== 0; + return mo = 0, e; + } + function To(e, t, n) { + t.updateQueue = e.updateQueue, t.flags &= -2053, e.lanes &= ~n; + } + function Eo(e) { + if (uo) { + for (e = e.memoizedState; e !== null;) { + var t = e.queue; + t !== null && (t.pending = null), e = e.next; + } + uo = !1; + } + oo = 0, lo = co = so = null, fo = !1, ho = mo = 0, go = null; + } + function Do() { + var e = { + memoizedState: null, + baseState: null, + baseQueue: null, + queue: null, + next: null + }; + return lo === null ? so.memoizedState = lo = e : lo = lo.next = e, lo; + } + function Oo() { + if (co === null) { + var e = so.alternate; + e = e === null ? null : e.memoizedState; + } else e = co.next; + var t = lo === null ? so.memoizedState : lo.next; + if (t !== null) lo = t, co = e; + else { + if (e === null) throw so.alternate === null ? Error(i(467)) : Error(i(310)); + co = e, e = { + memoizedState: co.memoizedState, + baseState: co.baseState, + baseQueue: co.baseQueue, + queue: co.queue, + next: null + }, lo === null ? so.memoizedState = lo = e : lo = lo.next = e; + } + return lo; + } + function ko() { + return { + lastEffect: null, + events: null, + stores: null, + memoCache: null + }; + } + function Ao(e) { + var t = ho; + return ho += 1, go === null && (go = []), e = xa(go, e, t), t = so, (lo === null ? t.memoizedState : lo.next) === null && (t = t.alternate, A.H = t === null || t.memoizedState === null ? Ls : Rs), e; + } + function jo(e) { + if (typeof e == "object" && e) { + if (typeof e.then == "function") return Ao(e); + if (e.$$typeof === C) return Yi(e); + } + throw Error(i(438, String(e))); + } + function Mo(e) { + var t = null, n = so.updateQueue; + if (n !== null && (t = n.memoCache), t == null) { + var r = so.alternate; + r !== null && (r = r.updateQueue, r !== null && (r = r.memoCache, r != null && (t = { + data: r.data.map(function(e) { + return e.slice(); + }), + index: 0 + }))); + } + if (t ??= { + data: [], + index: 0 + }, n === null && (n = ko(), so.updateQueue = n), n.memoCache = t, n = t.data[t.index], n === void 0) for (n = t.data[t.index] = Array(e), r = 0; r < e; r++) n[r] = te; + return t.index++, n; + } + function No(e, t) { + return typeof t == "function" ? t(e) : t; + } + function Po(e) { + return Fo(Oo(), co, e); + } + function Fo(e, t, n) { + var r = e.queue; + if (r === null) throw Error(i(311)); + r.lastRenderedReducer = n; + var a = e.baseQueue, o = r.pending; + if (o !== null) { + if (a !== null) { + var s = a.next; + a.next = o.next, o.next = s; + } + t.baseQueue = a = o, r.pending = null; + } + if (o = e.baseState, a === null) e.memoizedState = o; + else { + t = a.next; + var c = s = null, l = null, u = t, d = !1; + do { + var f = u.lane & -536870913; + if (f === u.lane ? (oo & f) === f : (Hl & f) === f) { + var p = u.revertLane; + if (p === 0) l !== null && (l = l.next = { + lane: 0, + revertLane: 0, + gesture: null, + action: u.action, + hasEagerState: u.hasEagerState, + eagerState: u.eagerState, + next: null + }), f === oa && (d = !0); + else if ((oo & p) === p) { + u = u.next, p === oa && (d = !0); + continue; + } else f = { + lane: 0, + revertLane: u.revertLane, + gesture: null, + action: u.action, + hasEagerState: u.hasEagerState, + eagerState: u.eagerState, + next: null + }, l === null ? (c = l = f, s = o) : l = l.next = f, so.lanes |= p, Xl |= p; + f = u.action, po && n(o, f), o = u.hasEagerState ? u.eagerState : n(o, f); + } else p = { + lane: f, + revertLane: u.revertLane, + gesture: u.gesture, + action: u.action, + hasEagerState: u.hasEagerState, + eagerState: u.eagerState, + next: null + }, l === null ? (c = l = p, s = o) : l = l.next = p, so.lanes |= f, Xl |= f; + u = u.next; + } while (u !== null && u !== t); + if (l === null ? s = o : l.next = c, !gr(o, e.memoizedState) && (tc = !0, d && (n = sa, n !== null))) throw n; + e.memoizedState = o, e.baseState = s, e.baseQueue = l, r.lastRenderedState = o; + } + return a === null && (r.lanes = 0), [e.memoizedState, r.dispatch]; + } + function Io(e) { + var t = Oo(), n = t.queue; + if (n === null) throw Error(i(311)); + n.lastRenderedReducer = e; + var r = n.dispatch, a = n.pending, o = t.memoizedState; + if (a !== null) { + n.pending = null; + var s = a = a.next; + do + o = e(o, s.action), s = s.next; + while (s !== a); + gr(o, t.memoizedState) || (tc = !0), t.memoizedState = o, t.baseQueue === null && (t.baseState = o), n.lastRenderedState = o; + } + return [o, r]; + } + function Lo(e, t, n) { + var r = so, a = Oo(), o = ki; + if (o) { + if (n === void 0) throw Error(i(407)); + n = n(); + } else n = t(); + var s = !gr((co || a).memoizedState, n); + if (s && (a.memoizedState = n, tc = !0), a = a.queue, cs(Bo.bind(null, r, a, e), [e]), a.getSnapshot !== t || s || lo !== null && lo.memoizedState.tag & 1) { + if (r.flags |= 2048, rs(9, { destroy: void 0 }, zo.bind(null, r, a, n, t), null), Bl === null) throw Error(i(349)); + o || oo & 127 || Ro(r, t, n); + } + return n; + } + function Ro(e, t, n) { + e.flags |= 16384, e = { + getSnapshot: t, + value: n + }, t = so.updateQueue, t === null ? (t = ko(), so.updateQueue = t, t.stores = [e]) : (n = t.stores, n === null ? t.stores = [e] : n.push(e)); + } + function zo(e, t, n, r) { + t.value = n, t.getSnapshot = r, Vo(t) && Ho(e); + } + function Bo(e, t, n) { + return n(function() { + Vo(t) && Ho(e); + }); + } + function Vo(e) { + var t = e.getSnapshot; + e = e.value; + try { + var n = t(); + return !gr(e, n); + } catch { + return !0; + } + } + function Ho(e) { + var t = Zr(e, 2); + t !== null && bu(t, e, 2); + } + function Uo(e) { + var t = Do(); + if (typeof e == "function") { + var n = e; + if (e = n(), po) { + B(!0); + try { + n(); + } finally { + B(!1); + } + } + } + return t.memoizedState = t.baseState = e, t.queue = { + pending: null, + lanes: 0, + dispatch: null, + lastRenderedReducer: No, + lastRenderedState: e + }, t; + } + function Wo(e, t, n, r) { + return e.baseState = n, Fo(e, co, typeof r == "function" ? r : No); + } + function Go(e, t, n, r, a) { + if (Ns(e)) throw Error(i(485)); + if (e = t.action, e !== null) { + var o = { + payload: a, + action: e, + next: null, + isTransition: !0, + status: "pending", + value: null, + reason: null, + listeners: [], + then: function(e) { + o.listeners.push(e); + } + }; + A.T === null ? o.isTransition = !1 : n(!0), r(o), n = t.pending, n === null ? (o.next = t.pending = o, Ko(t, o)) : (o.next = n.next, t.pending = n.next = o); + } + } + function Ko(e, t) { + var n = t.action, r = t.payload, i = e.state; + if (t.isTransition) { + var a = A.T, o = {}; + A.T = o; + try { + var s = n(i, r), c = A.S; + c !== null && c(o, s), qo(e, t, s); + } catch (n) { + Yo(e, t, n); + } finally { + a !== null && o.types !== null && (a.types = o.types), A.T = a; + } + } else try { + a = n(i, r), qo(e, t, a); + } catch (n) { + Yo(e, t, n); + } + } + function qo(e, t, n) { + typeof n == "object" && n && typeof n.then == "function" ? n.then(function(n) { + Jo(e, t, n); + }, function(n) { + return Yo(e, t, n); + }) : Jo(e, t, n); + } + function Jo(e, t, n) { + t.status = "fulfilled", t.value = n, Xo(t), e.state = n, t = e.pending, t !== null && (n = t.next, n === t ? e.pending = null : (n = n.next, t.next = n, Ko(e, n))); + } + function Yo(e, t, n) { + var r = e.pending; + if (e.pending = null, r !== null) { + r = r.next; + do + t.status = "rejected", t.reason = n, Xo(t), t = t.next; + while (t !== r); + } + e.action = null; + } + function Xo(e) { + e = e.listeners; + for (var t = 0; t < e.length; t++) (0, e[t])(); + } + function Zo(e, t) { + return t; + } + function Qo(e, t) { + if (ki) { + var n = Bl.formState; + if (n !== null) { + a: { + var r = so; + if (ki) { + if (Oi) { + b: { + for (var i = Oi, a = ji; i.nodeType !== 8;) { + if (!a) { + i = null; + break b; + } + if (i = gf(i.nextSibling), i === null) { + i = null; + break b; + } + } + a = i.data, i = a === "F!" || a === "F" ? i : null; + } + if (i) { + Oi = gf(i.nextSibling), r = i.data === "F!"; + break a; + } + } + Ni(r); + } + r = !1; + } + r && (t = n[0]); + } + } + return n = Do(), n.memoizedState = n.baseState = t, r = { + pending: null, + lanes: 0, + dispatch: null, + lastRenderedReducer: Zo, + lastRenderedState: t + }, n.queue = r, n = As.bind(null, so, r), r.dispatch = n, r = Uo(!1), a = Ms.bind(null, so, !1, r.queue), r = Do(), i = { + state: t, + dispatch: null, + action: e, + pending: null + }, r.queue = i, n = Go.bind(null, so, i, a, n), i.dispatch = n, r.memoizedState = e, [ + t, + n, + !1 + ]; + } + function $o(e) { + return es(Oo(), co, e); + } + function es(e, t, n) { + if (t = Fo(e, t, Zo)[0], e = Po(No)[0], typeof t == "object" && t && typeof t.then == "function") try { + var r = Ao(t); + } catch (e) { + throw e === ga ? va : e; + } + else r = t; + t = Oo(); + var i = t.queue, a = i.dispatch; + return n !== t.memoizedState && (so.flags |= 2048, rs(9, { destroy: void 0 }, ts.bind(null, i, n), null)), [ + r, + a, + e + ]; + } + function ts(e, t) { + e.action = t; + } + function ns(e) { + var t = Oo(), n = co; + if (n !== null) return es(t, n, e); + Oo(), t = t.memoizedState, n = Oo(); + var r = n.queue.dispatch; + return n.memoizedState = e, [ + t, + r, + !1 + ]; + } + function rs(e, t, n, r) { + return e = { + tag: e, + create: n, + deps: r, + inst: t, + next: null + }, t = so.updateQueue, t === null && (t = ko(), so.updateQueue = t), n = t.lastEffect, n === null ? t.lastEffect = e.next = e : (r = n.next, n.next = e, e.next = r, t.lastEffect = e), e; + } + function is() { + return Oo().memoizedState; + } + function as(e, t, n, r) { + var i = Do(); + so.flags |= e, i.memoizedState = rs(1 | t, { destroy: void 0 }, n, r === void 0 ? null : r); + } + function os(e, t, n, r) { + var i = Oo(); + r = r === void 0 ? null : r; + var a = i.memoizedState.inst; + co !== null && r !== null && yo(r, co.memoizedState.deps) ? i.memoizedState = rs(t, a, n, r) : (so.flags |= e, i.memoizedState = rs(1 | t, a, n, r)); + } + function ss(e, t) { + as(8390656, 8, e, t); + } + function cs(e, t) { + os(2048, 8, e, t); + } + function ls(e) { + so.flags |= 4; + var t = so.updateQueue; + if (t === null) t = ko(), so.updateQueue = t, t.events = [e]; + else { + var n = t.events; + n === null ? t.events = [e] : n.push(e); + } + } + function us(e) { + var t = Oo().memoizedState; + return ls({ + ref: t, + nextImpl: e + }), function() { + if (zl & 2) throw Error(i(440)); + return t.impl.apply(void 0, arguments); + }; + } + function ds(e, t) { + return os(4, 2, e, t); + } + function fs(e, t) { + return os(4, 4, e, t); + } + function ps(e, t) { + if (typeof t == "function") { + e = e(); + var n = t(e); + return function() { + typeof n == "function" ? n() : t(null); + }; + } + if (t != null) return e = e(), t.current = e, function() { + t.current = null; + }; + } + function ms(e, t, n) { + n = n == null ? null : n.concat([e]), os(4, 4, ps.bind(null, t, e), n); + } + function hs() {} + function gs(e, t) { + var n = Oo(); + t = t === void 0 ? null : t; + var r = n.memoizedState; + return t !== null && yo(t, r[1]) ? r[0] : (n.memoizedState = [e, t], e); + } + function _s(e, t) { + var n = Oo(); + t = t === void 0 ? null : t; + var r = n.memoizedState; + if (t !== null && yo(t, r[1])) return r[0]; + if (r = e(), po) { + B(!0); + try { + e(); + } finally { + B(!1); + } + } + return n.memoizedState = [r, t], r; + } + function vs(e, t, n) { + return n === void 0 || oo & 1073741824 && !(Hl & 261930) ? e.memoizedState = t : (e.memoizedState = n, e = yu(), so.lanes |= e, Xl |= e, n); + } + function ys(e, t, n, r) { + return gr(n, t) ? n : Ka.current === null ? !(oo & 42) || oo & 1073741824 && !(Hl & 261930) ? (tc = !0, e.memoizedState = n) : (e = yu(), so.lanes |= e, Xl |= e, t) : (e = vs(e, n, r), gr(e, t) || (tc = !0), e); + } + function bs(e, t, n, r, i) { + var a = j.p; + j.p = a !== 0 && 8 > a ? a : 8; + var o = A.T, s = {}; + A.T = s, Ms(e, !1, t, n); + try { + var c = i(), l = A.S; + l !== null && l(s, c), typeof c == "object" && c && typeof c.then == "function" ? js(e, t, ua(c, r), vu(e)) : js(e, t, r, vu(e)); + } catch (n) { + js(e, t, { + then: function() {}, + status: "rejected", + reason: n + }, vu()); + } finally { + j.p = a, o !== null && s.types !== null && (o.types = s.types), A.T = o; + } + } + function xs() {} + function Ss(e, t, n, r) { + if (e.tag !== 5) throw Error(i(476)); + var a = Cs(e).queue; + bs(e, a, t, oe, n === null ? xs : function() { + return ws(e), n(r); + }); + } + function Cs(e) { + var t = e.memoizedState; + if (t !== null) return t; + t = { + memoizedState: oe, + baseState: oe, + baseQueue: null, + queue: { + pending: null, + lanes: 0, + dispatch: null, + lastRenderedReducer: No, + lastRenderedState: oe + }, + next: null + }; + var n = {}; + return t.next = { + memoizedState: n, + baseState: n, + baseQueue: null, + queue: { + pending: null, + lanes: 0, + dispatch: null, + lastRenderedReducer: No, + lastRenderedState: n + }, + next: null + }, e.memoizedState = t, e = e.alternate, e !== null && (e.memoizedState = t), t; + } + function ws(e) { + var t = Cs(e); + t.next === null && (t = e.alternate.memoizedState), js(e, t.next.queue, {}, vu()); + } + function Ts() { + return Yi(op); + } + function Es() { + return Oo().memoizedState; + } + function Ds() { + return Oo().memoizedState; + } + function Os(e) { + for (var t = e.return; t !== null;) { + switch (t.tag) { + case 24: + case 3: + var n = vu(); + e = La(n); + var r = Ra(t, e, n); + r !== null && (bu(r, t, n), za(r, t, n)), t = { cache: na() }, e.payload = t; + return; + } + t = t.return; + } + } + function ks(e, t, n) { + var r = vu(); + n = { + lane: r, + revertLane: 0, + gesture: null, + action: n, + hasEagerState: !1, + eagerState: null, + next: null + }, Ns(e) ? Ps(t, n) : (n = Xr(e, t, n, r), n !== null && (bu(n, e, r), Fs(n, t, r))); + } + function As(e, t, n) { + js(e, t, n, vu()); + } + function js(e, t, n, r) { + var i = { + lane: r, + revertLane: 0, + gesture: null, + action: n, + hasEagerState: !1, + eagerState: null, + next: null + }; + if (Ns(e)) Ps(t, i); + else { + var a = e.alternate; + if (e.lanes === 0 && (a === null || a.lanes === 0) && (a = t.lastRenderedReducer, a !== null)) try { + var o = t.lastRenderedState, s = a(o, n); + if (i.hasEagerState = !0, i.eagerState = s, gr(s, o)) return Yr(e, t, i, 0), Bl === null && Jr(), !1; + } catch {} + if (n = Xr(e, t, i, r), n !== null) return bu(n, e, r), Fs(n, t, r), !0; + } + return !1; + } + function Ms(e, t, n, r) { + if (r = { + lane: 2, + revertLane: _d(), + gesture: null, + action: r, + hasEagerState: !1, + eagerState: null, + next: null + }, Ns(e)) { + if (t) throw Error(i(479)); + } else t = Xr(e, n, r, 2), t !== null && bu(t, e, 2); + } + function Ns(e) { + var t = e.alternate; + return e === so || t !== null && t === so; + } + function Ps(e, t) { + fo = uo = !0; + var n = e.pending; + n === null ? t.next = t : (t.next = n.next, n.next = t), e.pending = t; + } + function Fs(e, t, n) { + if (n & 4194048) { + var r = t.lanes; + r &= e.pendingLanes, n |= r, t.lanes = n, Je(e, n); + } + } + var Is = { + readContext: Yi, + use: jo, + useCallback: vo, + useContext: vo, + useEffect: vo, + useImperativeHandle: vo, + useLayoutEffect: vo, + useInsertionEffect: vo, + useMemo: vo, + useReducer: vo, + useRef: vo, + useState: vo, + useDebugValue: vo, + useDeferredValue: vo, + useTransition: vo, + useSyncExternalStore: vo, + useId: vo, + useHostTransitionStatus: vo, + useFormState: vo, + useActionState: vo, + useOptimistic: vo, + useMemoCache: vo, + useCacheRefresh: vo + }; + Is.useEffectEvent = vo; + var Ls = { + readContext: Yi, + use: jo, + useCallback: function(e, t) { + return Do().memoizedState = [e, t === void 0 ? null : t], e; + }, + useContext: Yi, + useEffect: ss, + useImperativeHandle: function(e, t, n) { + n = n == null ? null : n.concat([e]), as(4194308, 4, ps.bind(null, t, e), n); + }, + useLayoutEffect: function(e, t) { + return as(4194308, 4, e, t); + }, + useInsertionEffect: function(e, t) { + as(4, 2, e, t); + }, + useMemo: function(e, t) { + var n = Do(); + t = t === void 0 ? null : t; + var r = e(); + if (po) { + B(!0); + try { + e(); + } finally { + B(!1); + } + } + return n.memoizedState = [r, t], r; + }, + useReducer: function(e, t, n) { + var r = Do(); + if (n !== void 0) { + var i = n(t); + if (po) { + B(!0); + try { + n(t); + } finally { + B(!1); + } + } + } else i = t; + return r.memoizedState = r.baseState = i, e = { + pending: null, + lanes: 0, + dispatch: null, + lastRenderedReducer: e, + lastRenderedState: i + }, r.queue = e, e = e.dispatch = ks.bind(null, so, e), [r.memoizedState, e]; + }, + useRef: function(e) { + var t = Do(); + return e = { current: e }, t.memoizedState = e; + }, + useState: function(e) { + e = Uo(e); + var t = e.queue, n = As.bind(null, so, t); + return t.dispatch = n, [e.memoizedState, n]; + }, + useDebugValue: hs, + useDeferredValue: function(e, t) { + return vs(Do(), e, t); + }, + useTransition: function() { + var e = Uo(!1); + return e = bs.bind(null, so, e.queue, !0, !1), Do().memoizedState = e, [!1, e]; + }, + useSyncExternalStore: function(e, t, n) { + var r = so, a = Do(); + if (ki) { + if (n === void 0) throw Error(i(407)); + n = n(); + } else { + if (n = t(), Bl === null) throw Error(i(349)); + Hl & 127 || Ro(r, t, n); + } + a.memoizedState = n; + var o = { + value: n, + getSnapshot: t + }; + return a.queue = o, ss(Bo.bind(null, r, o, e), [e]), r.flags |= 2048, rs(9, { destroy: void 0 }, zo.bind(null, r, o, n, t), null), n; + }, + useId: function() { + var e = Do(), t = Bl.identifierPrefix; + if (ki) { + var n = xi, r = bi; + n = (r & ~(1 << 32 - Fe(r) - 1)).toString(32) + n, t = "_" + t + "R_" + n, n = mo++, 0 < n && (t += "H" + n.toString(32)), t += "_"; + } else n = _o++, t = "_" + t + "r_" + n.toString(32) + "_"; + return e.memoizedState = t; + }, + useHostTransitionStatus: Ts, + useFormState: Qo, + useActionState: Qo, + useOptimistic: function(e) { + var t = Do(); + t.memoizedState = t.baseState = e; + var n = { + pending: null, + lanes: 0, + dispatch: null, + lastRenderedReducer: null, + lastRenderedState: null + }; + return t.queue = n, t = Ms.bind(null, so, !0, n), n.dispatch = t, [e, t]; + }, + useMemoCache: Mo, + useCacheRefresh: function() { + return Do().memoizedState = Os.bind(null, so); + }, + useEffectEvent: function(e) { + var t = Do(), n = { impl: e }; + return t.memoizedState = n, function() { + if (zl & 2) throw Error(i(440)); + return n.impl.apply(void 0, arguments); + }; + } + }, Rs = { + readContext: Yi, + use: jo, + useCallback: gs, + useContext: Yi, + useEffect: cs, + useImperativeHandle: ms, + useInsertionEffect: ds, + useLayoutEffect: fs, + useMemo: _s, + useReducer: Po, + useRef: is, + useState: function() { + return Po(No); + }, + useDebugValue: hs, + useDeferredValue: function(e, t) { + return ys(Oo(), co.memoizedState, e, t); + }, + useTransition: function() { + var e = Po(No)[0], t = Oo().memoizedState; + return [typeof e == "boolean" ? e : Ao(e), t]; + }, + useSyncExternalStore: Lo, + useId: Es, + useHostTransitionStatus: Ts, + useFormState: $o, + useActionState: $o, + useOptimistic: function(e, t) { + return Wo(Oo(), co, e, t); + }, + useMemoCache: Mo, + useCacheRefresh: Ds + }; + Rs.useEffectEvent = us; + var zs = { + readContext: Yi, + use: jo, + useCallback: gs, + useContext: Yi, + useEffect: cs, + useImperativeHandle: ms, + useInsertionEffect: ds, + useLayoutEffect: fs, + useMemo: _s, + useReducer: Io, + useRef: is, + useState: function() { + return Io(No); + }, + useDebugValue: hs, + useDeferredValue: function(e, t) { + var n = Oo(); + return co === null ? vs(n, e, t) : ys(n, co.memoizedState, e, t); + }, + useTransition: function() { + var e = Io(No)[0], t = Oo().memoizedState; + return [typeof e == "boolean" ? e : Ao(e), t]; + }, + useSyncExternalStore: Lo, + useId: Es, + useHostTransitionStatus: Ts, + useFormState: ns, + useActionState: ns, + useOptimistic: function(e, t) { + var n = Oo(); + return co === null ? (n.baseState = e, [e, n.queue.dispatch]) : Wo(n, co, e, t); + }, + useMemoCache: Mo, + useCacheRefresh: Ds + }; + zs.useEffectEvent = us; + function Bs(e, t, n, r) { + t = e.memoizedState, n = n(r, t), n = n == null ? t : m({}, t, n), e.memoizedState = n, e.lanes === 0 && (e.updateQueue.baseState = n); + } + var Vs = { + enqueueSetState: function(e, t, n) { + e = e._reactInternals; + var r = vu(), i = La(r); + i.payload = t, n != null && (i.callback = n), t = Ra(e, i, r), t !== null && (bu(t, e, r), za(t, e, r)); + }, + enqueueReplaceState: function(e, t, n) { + e = e._reactInternals; + var r = vu(), i = La(r); + i.tag = 1, i.payload = t, n != null && (i.callback = n), t = Ra(e, i, r), t !== null && (bu(t, e, r), za(t, e, r)); + }, + enqueueForceUpdate: function(e, t) { + e = e._reactInternals; + var n = vu(), r = La(n); + r.tag = 2, t != null && (r.callback = t), t = Ra(e, r, n), t !== null && (bu(t, e, n), za(t, e, n)); + } + }; + function Hs(e, t, n, r, i, a, o) { + return e = e.stateNode, typeof e.shouldComponentUpdate == "function" ? e.shouldComponentUpdate(r, a, o) : t.prototype && t.prototype.isPureReactComponent ? !_r(n, r) || !_r(i, a) : !0; + } + function Us(e, t, n, r) { + e = t.state, typeof t.componentWillReceiveProps == "function" && t.componentWillReceiveProps(n, r), typeof t.UNSAFE_componentWillReceiveProps == "function" && t.UNSAFE_componentWillReceiveProps(n, r), t.state !== e && Vs.enqueueReplaceState(t, t.state, null); + } + function Ws(e, t) { + var n = t; + if ("ref" in t) for (var r in n = {}, t) r !== "ref" && (n[r] = t[r]); + if (e = e.defaultProps) for (var i in n === t && (n = m({}, n)), e) n[i] === void 0 && (n[i] = e[i]); + return n; + } + function Gs(e) { + Wr(e); + } + function Ks(e) { + console.error(e); + } + function qs(e) { + Wr(e); + } + function Js(e, t) { + try { + var n = e.onUncaughtError; + n(t.value, { componentStack: t.stack }); + } catch (e) { + setTimeout(function() { + throw e; + }); + } + } + function Ys(e, t, n) { + try { + var r = e.onCaughtError; + r(n.value, { + componentStack: n.stack, + errorBoundary: t.tag === 1 ? t.stateNode : null + }); + } catch (e) { + setTimeout(function() { + throw e; + }); + } + } + function Xs(e, t, n) { + return n = La(n), n.tag = 3, n.payload = { element: null }, n.callback = function() { + Js(e, t); + }, n; + } + function Zs(e) { + return e = La(e), e.tag = 3, e; + } + function Qs(e, t, n, r) { + var i = n.type.getDerivedStateFromError; + if (typeof i == "function") { + var a = r.value; + e.payload = function() { + return i(a); + }, e.callback = function() { + Ys(t, n, r); + }; + } + var o = n.stateNode; + o !== null && typeof o.componentDidCatch == "function" && (e.callback = function() { + Ys(t, n, r), typeof i != "function" && (cu === null ? cu = /* @__PURE__ */ new Set([this]) : cu.add(this)); + var e = r.stack; + this.componentDidCatch(r.value, { componentStack: e === null ? "" : e }); + }); + } + function $s(e, t, n, r, a) { + if (n.flags |= 32768, typeof r == "object" && r && typeof r.then == "function") { + if (t = n.alternate, t !== null && Ki(t, n, a, !0), n = Za.current, n !== null) { + switch (n.tag) { + case 31: + case 13: return Qa === null ? Mu() : n.alternate === null && Yl === 0 && (Yl = 3), n.flags &= -257, n.flags |= 65536, n.lanes = a, r === ya ? n.flags |= 16384 : (t = n.updateQueue, t === null ? n.updateQueue = /* @__PURE__ */ new Set([r]) : t.add(r), Zu(e, r, a)), !1; + case 22: return n.flags |= 65536, r === ya ? n.flags |= 16384 : (t = n.updateQueue, t === null ? (t = { + transitions: null, + markerInstances: null, + retryQueue: /* @__PURE__ */ new Set([r]) + }, n.updateQueue = t) : (n = t.retryQueue, n === null ? t.retryQueue = /* @__PURE__ */ new Set([r]) : n.add(r)), Zu(e, r, a)), !1; + } + throw Error(i(435, n.tag)); + } + return Zu(e, r, a), Mu(), !1; + } + if (ki) return t = Za.current, t === null ? (r !== Mi && (t = Error(i(423), { cause: r }), zi(fi(t, n))), e = e.current.alternate, e.flags |= 65536, a &= -a, e.lanes |= a, r = fi(r, n), a = Xs(e.stateNode, r, a), Ba(e, a), Yl !== 4 && (Yl = 2)) : (!(t.flags & 65536) && (t.flags |= 256), t.flags |= 65536, t.lanes = a, r !== Mi && (e = Error(i(422), { cause: r }), zi(fi(e, n)))), !1; + var o = Error(i(520), { cause: r }); + if (o = fi(o, n), tu === null ? tu = [o] : tu.push(o), Yl !== 4 && (Yl = 2), t === null) return !0; + r = fi(r, n), n = t; + do { + switch (n.tag) { + case 3: return n.flags |= 65536, e = a & -a, n.lanes |= e, e = Xs(n.stateNode, r, e), Ba(n, e), !1; + case 1: if (t = n.type, o = n.stateNode, !(n.flags & 128) && (typeof t.getDerivedStateFromError == "function" || o !== null && typeof o.componentDidCatch == "function" && (cu === null || !cu.has(o)))) return n.flags |= 65536, a &= -a, n.lanes |= a, a = Zs(a), Qs(a, e, n, r), Ba(n, a), !1; + } + n = n.return; + } while (n !== null); + return !1; + } + var ec = Error(i(461)), tc = !1; + function nc(e, t, n, r) { + t.child = e === null ? Na(t, null, n, r) : Ma(t, e.child, n, r); + } + function rc(e, t, n, r, i) { + n = n.render; + var a = t.ref; + if ("ref" in r) { + var o = {}; + for (var s in r) s !== "ref" && (o[s] = r[s]); + } else o = r; + return Ji(t), r = bo(e, t, n, o, a, i), s = wo(), e !== null && !tc ? (To(e, t, i), Dc(e, t, i)) : (ki && s && wi(t), t.flags |= 1, nc(e, t, r, i), t.child); + } + function ic(e, t, n, r, i) { + if (e === null) { + var a = n.type; + return typeof a == "function" && !ri(a) && a.defaultProps === void 0 && n.compare === null ? (t.tag = 15, t.type = a, ac(e, t, a, r, i)) : (e = oi(n.type, null, r, t, t.mode, i), e.ref = t.ref, e.return = t, t.child = e); + } + if (a = e.child, !Oc(e, i)) { + var o = a.memoizedProps; + if (n = n.compare, n = n === null ? _r : n, n(o, r) && e.ref === t.ref) return Dc(e, t, i); + } + return t.flags |= 1, e = ii(a, r), e.ref = t.ref, e.return = t, t.child = e; + } + function ac(e, t, n, r, i) { + if (e !== null) { + var a = e.memoizedProps; + if (_r(a, r) && e.ref === t.ref) { + if (tc = !1, t.pendingProps = r = a, Oc(e, i)) e.flags & 131072 && (tc = !0); + else return t.lanes = e.lanes, Dc(e, t, i); + } + } + return pc(e, t, n, r, i); + } + function oc(e, t, n, r) { + var i = r.children, a = e === null ? null : e.memoizedState; + if (e === null && t.stateNode === null && (t.stateNode = { + _visibility: 1, + _pendingMarkers: null, + _retryCache: null, + _transitions: null + }), r.mode === "hidden") { + if (t.flags & 128) { + if (a = a === null ? n : a.baseLanes | n, e !== null) { + for (r = t.child = e.child, i = 0; r !== null;) i = i | r.lanes | r.childLanes, r = r.sibling; + r = i & ~a; + } else r = 0, t.child = null; + return cc(e, t, a, n, r); + } + if (n & 536870912) t.memoizedState = { + baseLanes: 0, + cachePool: null + }, e !== null && ma(t, a === null ? null : a.cachePool), a === null ? Ya() : Ja(t, a), to(t); + else return r = t.lanes = 536870912, cc(e, t, a === null ? n : a.baseLanes | n, n, r); + } else a === null ? (e !== null && ma(t, null), Ya(), no(t)) : (ma(t, a.cachePool), Ja(t, a), no(t), t.memoizedState = null); + return nc(e, t, i, n), t.child; + } + function sc(e, t) { + return e !== null && e.tag === 22 || t.stateNode !== null || (t.stateNode = { + _visibility: 1, + _pendingMarkers: null, + _retryCache: null, + _transitions: null + }), t.sibling; + } + function cc(e, t, n, r, i) { + var a = pa(); + return a = a === null ? null : { + parent: ta._currentValue, + pool: a + }, t.memoizedState = { + baseLanes: n, + cachePool: a + }, e !== null && ma(t, null), Ya(), to(t), e !== null && Ki(e, t, r, !0), t.childLanes = i, null; + } + function lc(e, t) { + return t = Sc({ + mode: t.mode, + children: t.children + }, e.mode), t.ref = e.ref, e.child = t, t.return = e, t; + } + function uc(e, t, n) { + return Ma(t, e.child, null, n), e = lc(t, t.pendingProps), e.flags |= 2, ro(t), t.memoizedState = null, e; + } + function dc(e, t, n) { + var r = t.pendingProps, a = !!(t.flags & 128); + if (t.flags &= -129, e === null) { + if (ki) { + if (r.mode === "hidden") return e = lc(t, r), t.lanes = 536870912, sc(null, e); + if (eo(t), (e = Oi) ? (e = ff(e, ji), e = e !== null && e.data === "&" ? e : null, e !== null && (t.memoizedState = { + dehydrated: e, + treeContext: yi === null ? null : { + id: bi, + overflow: xi + }, + retryLane: 536870912, + hydrationErrors: null + }, n = li(e), n.return = t, t.child = n, Di = t, Oi = null)) : e = null, e === null) throw Ni(t); + return t.lanes = 536870912, null; + } + return lc(t, r); + } + var o = e.memoizedState; + if (o !== null) { + var s = o.dehydrated; + if (eo(t), a) { + if (t.flags & 256) t.flags &= -257, t = uc(e, t, n); + else if (t.memoizedState !== null) t.child = e.child, t.flags |= 128, t = null; + else throw Error(i(558)); + } else if (tc || Ki(e, t, n, !1), a = (n & e.childLanes) !== 0, tc || a) { + if (r = Bl, r !== null && (s = Ye(r, n), s !== 0 && s !== o.retryLane)) throw o.retryLane = s, Zr(e, s), bu(r, e, s), ec; + Mu(), t = uc(e, t, n); + } else e = o.treeContext, Oi = gf(s.nextSibling), Di = t, ki = !0, Ai = null, ji = !1, e !== null && Ei(t, e), t = lc(t, r), t.flags |= 4096; + return t; + } + return e = ii(e.child, { + mode: r.mode, + children: r.children + }), e.ref = t.ref, t.child = e, e.return = t, e; + } + function fc(e, t) { + var n = t.ref; + if (n === null) e !== null && e.ref !== null && (t.flags |= 4194816); + else { + if (typeof n != "function" && typeof n != "object") throw Error(i(284)); + (e === null || e.ref !== n) && (t.flags |= 4194816); + } + } + function pc(e, t, n, r, i) { + return Ji(t), n = bo(e, t, n, r, void 0, i), r = wo(), e !== null && !tc ? (To(e, t, i), Dc(e, t, i)) : (ki && r && wi(t), t.flags |= 1, nc(e, t, n, i), t.child); + } + function mc(e, t, n, r, i, a) { + return Ji(t), t.updateQueue = null, n = So(t, r, n, i), xo(e), r = wo(), e !== null && !tc ? (To(e, t, a), Dc(e, t, a)) : (ki && r && wi(t), t.flags |= 1, nc(e, t, n, a), t.child); + } + function hc(e, t, n, r, i) { + if (Ji(t), t.stateNode === null) { + var a = ei, o = n.contextType; + typeof o == "object" && o && (a = Yi(o)), a = new n(r, a), t.memoizedState = a.state !== null && a.state !== void 0 ? a.state : null, a.updater = Vs, t.stateNode = a, a._reactInternals = t, a = t.stateNode, a.props = r, a.state = t.memoizedState, a.refs = {}, Fa(t), o = n.contextType, a.context = typeof o == "object" && o ? Yi(o) : ei, a.state = t.memoizedState, o = n.getDerivedStateFromProps, typeof o == "function" && (Bs(t, n, o, r), a.state = t.memoizedState), typeof n.getDerivedStateFromProps == "function" || typeof a.getSnapshotBeforeUpdate == "function" || typeof a.UNSAFE_componentWillMount != "function" && typeof a.componentWillMount != "function" || (o = a.state, typeof a.componentWillMount == "function" && a.componentWillMount(), typeof a.UNSAFE_componentWillMount == "function" && a.UNSAFE_componentWillMount(), o !== a.state && Vs.enqueueReplaceState(a, a.state, null), Ua(t, r, a, i), Ha(), a.state = t.memoizedState), typeof a.componentDidMount == "function" && (t.flags |= 4194308), r = !0; + } else if (e === null) { + a = t.stateNode; + var s = t.memoizedProps, c = Ws(n, s); + a.props = c; + var l = a.context, u = n.contextType; + o = ei, typeof u == "object" && u && (o = Yi(u)); + var d = n.getDerivedStateFromProps; + u = typeof d == "function" || typeof a.getSnapshotBeforeUpdate == "function", s = t.pendingProps !== s, u || typeof a.UNSAFE_componentWillReceiveProps != "function" && typeof a.componentWillReceiveProps != "function" || (s || l !== o) && Us(t, a, r, o), Pa = !1; + var f = t.memoizedState; + a.state = f, Ua(t, r, a, i), Ha(), l = t.memoizedState, s || f !== l || Pa ? (typeof d == "function" && (Bs(t, n, d, r), l = t.memoizedState), (c = Pa || Hs(t, n, c, r, f, l, o)) ? (u || typeof a.UNSAFE_componentWillMount != "function" && typeof a.componentWillMount != "function" || (typeof a.componentWillMount == "function" && a.componentWillMount(), typeof a.UNSAFE_componentWillMount == "function" && a.UNSAFE_componentWillMount()), typeof a.componentDidMount == "function" && (t.flags |= 4194308)) : (typeof a.componentDidMount == "function" && (t.flags |= 4194308), t.memoizedProps = r, t.memoizedState = l), a.props = r, a.state = l, a.context = o, r = c) : (typeof a.componentDidMount == "function" && (t.flags |= 4194308), r = !1); + } else { + a = t.stateNode, Ia(e, t), o = t.memoizedProps, u = Ws(n, o), a.props = u, d = t.pendingProps, f = a.context, l = n.contextType, c = ei, typeof l == "object" && l && (c = Yi(l)), s = n.getDerivedStateFromProps, (l = typeof s == "function" || typeof a.getSnapshotBeforeUpdate == "function") || typeof a.UNSAFE_componentWillReceiveProps != "function" && typeof a.componentWillReceiveProps != "function" || (o !== d || f !== c) && Us(t, a, r, c), Pa = !1, f = t.memoizedState, a.state = f, Ua(t, r, a, i), Ha(); + var p = t.memoizedState; + o !== d || f !== p || Pa || e !== null && e.dependencies !== null && qi(e.dependencies) ? (typeof s == "function" && (Bs(t, n, s, r), p = t.memoizedState), (u = Pa || Hs(t, n, u, r, f, p, c) || e !== null && e.dependencies !== null && qi(e.dependencies)) ? (l || typeof a.UNSAFE_componentWillUpdate != "function" && typeof a.componentWillUpdate != "function" || (typeof a.componentWillUpdate == "function" && a.componentWillUpdate(r, p, c), typeof a.UNSAFE_componentWillUpdate == "function" && a.UNSAFE_componentWillUpdate(r, p, c)), typeof a.componentDidUpdate == "function" && (t.flags |= 4), typeof a.getSnapshotBeforeUpdate == "function" && (t.flags |= 1024)) : (typeof a.componentDidUpdate != "function" || o === e.memoizedProps && f === e.memoizedState || (t.flags |= 4), typeof a.getSnapshotBeforeUpdate != "function" || o === e.memoizedProps && f === e.memoizedState || (t.flags |= 1024), t.memoizedProps = r, t.memoizedState = p), a.props = r, a.state = p, a.context = c, r = u) : (typeof a.componentDidUpdate != "function" || o === e.memoizedProps && f === e.memoizedState || (t.flags |= 4), typeof a.getSnapshotBeforeUpdate != "function" || o === e.memoizedProps && f === e.memoizedState || (t.flags |= 1024), r = !1); + } + return a = r, fc(e, t), r = !!(t.flags & 128), a || r ? (a = t.stateNode, n = r && typeof n.getDerivedStateFromError != "function" ? null : a.render(), t.flags |= 1, e !== null && r ? (t.child = Ma(t, e.child, null, i), t.child = Ma(t, null, n, i)) : nc(e, t, n, i), t.memoizedState = a.state, e = t.child) : e = Dc(e, t, i), e; + } + function gc(e, t, n, r) { + return Li(), t.flags |= 256, nc(e, t, n, r), t.child; + } + var _c = { + dehydrated: null, + treeContext: null, + retryLane: 0, + hydrationErrors: null + }; + function vc(e) { + return { + baseLanes: e, + cachePool: ha() + }; + } + function yc(e, t, n) { + return e = e === null ? 0 : e.childLanes & ~n, t && (e |= $l), e; + } + function bc(e, t, n) { + var r = t.pendingProps, a = !1, o = !!(t.flags & 128), s; + if ((s = o) || (s = e !== null && e.memoizedState === null ? !1 : !!(io.current & 2)), s && (a = !0, t.flags &= -129), s = !!(t.flags & 32), t.flags &= -33, e === null) { + if (ki) { + if (a ? $a(t) : no(t), (e = Oi) ? (e = ff(e, ji), e = e !== null && e.data !== "&" ? e : null, e !== null && (t.memoizedState = { + dehydrated: e, + treeContext: yi === null ? null : { + id: bi, + overflow: xi + }, + retryLane: 536870912, + hydrationErrors: null + }, n = li(e), n.return = t, t.child = n, Di = t, Oi = null)) : e = null, e === null) throw Ni(t); + return mf(e) ? t.lanes = 32 : t.lanes = 536870912, null; + } + var c = r.children; + return r = r.fallback, a ? (no(t), a = t.mode, c = Sc({ + mode: "hidden", + children: c + }, a), r = si(r, a, n, null), c.return = t, r.return = t, c.sibling = r, t.child = c, r = t.child, r.memoizedState = vc(n), r.childLanes = yc(e, s, n), t.memoizedState = _c, sc(null, r)) : ($a(t), xc(t, c)); + } + var l = e.memoizedState; + if (l !== null && (c = l.dehydrated, c !== null)) { + if (o) t.flags & 256 ? ($a(t), t.flags &= -257, t = Cc(e, t, n)) : t.memoizedState === null ? (no(t), c = r.fallback, a = t.mode, r = Sc({ + mode: "visible", + children: r.children + }, a), c = si(c, a, n, null), c.flags |= 2, r.return = t, c.return = t, r.sibling = c, t.child = r, Ma(t, e.child, null, n), r = t.child, r.memoizedState = vc(n), r.childLanes = yc(e, s, n), t.memoizedState = _c, t = sc(null, r)) : (no(t), t.child = e.child, t.flags |= 128, t = null); + else if ($a(t), mf(c)) { + if (s = c.nextSibling && c.nextSibling.dataset, s) var u = s.dgst; + s = u, r = Error(i(419)), r.stack = "", r.digest = s, zi({ + value: r, + source: null, + stack: null + }), t = Cc(e, t, n); + } else if (tc || Ki(e, t, n, !1), s = (n & e.childLanes) !== 0, tc || s) { + if (s = Bl, s !== null && (r = Ye(s, n), r !== 0 && r !== l.retryLane)) throw l.retryLane = r, Zr(e, r), bu(s, e, r), ec; + pf(c) || Mu(), t = Cc(e, t, n); + } else pf(c) ? (t.flags |= 192, t.child = e.child, t = null) : (e = l.treeContext, Oi = gf(c.nextSibling), Di = t, ki = !0, Ai = null, ji = !1, e !== null && Ei(t, e), t = xc(t, r.children), t.flags |= 4096); + return t; + } + return a ? (no(t), c = r.fallback, a = t.mode, l = e.child, u = l.sibling, r = ii(l, { + mode: "hidden", + children: r.children + }), r.subtreeFlags = l.subtreeFlags & 65011712, u === null ? (c = si(c, a, n, null), c.flags |= 2) : c = ii(u, c), c.return = t, r.return = t, r.sibling = c, t.child = r, sc(null, r), r = t.child, c = e.child.memoizedState, c === null ? c = vc(n) : (a = c.cachePool, a === null ? a = ha() : (l = ta._currentValue, a = a.parent === l ? a : { + parent: l, + pool: l + }), c = { + baseLanes: c.baseLanes | n, + cachePool: a + }), r.memoizedState = c, r.childLanes = yc(e, s, n), t.memoizedState = _c, sc(e.child, r)) : ($a(t), n = e.child, e = n.sibling, n = ii(n, { + mode: "visible", + children: r.children + }), n.return = t, n.sibling = null, e !== null && (s = t.deletions, s === null ? (t.deletions = [e], t.flags |= 16) : s.push(e)), t.child = n, t.memoizedState = null, n); + } + function xc(e, t) { + return t = Sc({ + mode: "visible", + children: t + }, e.mode), t.return = e, e.child = t; + } + function Sc(e, t) { + return e = ni(22, e, null, t), e.lanes = 0, e; + } + function Cc(e, t, n) { + return Ma(t, e.child, null, n), e = xc(t, t.pendingProps.children), e.flags |= 2, t.memoizedState = null, e; + } + function wc(e, t, n) { + e.lanes |= t; + var r = e.alternate; + r !== null && (r.lanes |= t), Wi(e.return, t, n); + } + function Tc(e, t, n, r, i, a) { + var o = e.memoizedState; + o === null ? e.memoizedState = { + isBackwards: t, + rendering: null, + renderingStartTime: 0, + last: r, + tail: n, + tailMode: i, + treeForkCount: a + } : (o.isBackwards = t, o.rendering = null, o.renderingStartTime = 0, o.last = r, o.tail = n, o.tailMode = i, o.treeForkCount = a); + } + function Ec(e, t, n) { + var r = t.pendingProps, i = r.revealOrder, a = r.tail; + r = r.children; + var o = io.current, s = !!(o & 2); + if (s ? (o = o & 1 | 2, t.flags |= 128) : o &= 1, N(io, o), nc(e, t, r, n), r = ki ? gi : 0, !s && e !== null && e.flags & 128) a: for (e = t.child; e !== null;) { + if (e.tag === 13) e.memoizedState !== null && wc(e, n, t); + else if (e.tag === 19) wc(e, n, t); + else if (e.child !== null) { + e.child.return = e, e = e.child; + continue; + } + if (e === t) break a; + for (; e.sibling === null;) { + if (e.return === null || e.return === t) break a; + e = e.return; + } + e.sibling.return = e.return, e = e.sibling; + } + switch (i) { + case "forwards": + for (n = t.child, i = null; n !== null;) e = n.alternate, e !== null && ao(e) === null && (i = n), n = n.sibling; + n = i, n === null ? (i = t.child, t.child = null) : (i = n.sibling, n.sibling = null), Tc(t, !1, i, n, a, r); + break; + case "backwards": + case "unstable_legacy-backwards": + for (n = null, i = t.child, t.child = null; i !== null;) { + if (e = i.alternate, e !== null && ao(e) === null) { + t.child = i; + break; + } + e = i.sibling, i.sibling = n, n = i, i = e; + } + Tc(t, !0, n, null, a, r); + break; + case "together": + Tc(t, !1, null, null, void 0, r); + break; + default: t.memoizedState = null; + } + return t.child; + } + function Dc(e, t, n) { + if (e !== null && (t.dependencies = e.dependencies), Xl |= t.lanes, (n & t.childLanes) === 0) { + if (e !== null) { + if (Ki(e, t, n, !1), (n & t.childLanes) === 0) return null; + } else return null; + } + if (e !== null && t.child !== e.child) throw Error(i(153)); + if (t.child !== null) { + for (e = t.child, n = ii(e, e.pendingProps), t.child = n, n.return = t; e.sibling !== null;) e = e.sibling, n = n.sibling = ii(e, e.pendingProps), n.return = t; + n.sibling = null; + } + return t.child; + } + function Oc(e, t) { + return (e.lanes & t) !== 0 || (e = e.dependencies, !!(e !== null && qi(e))); + } + function kc(e, t, n) { + switch (t.tag) { + case 3: + de(t, t.stateNode.containerInfo), Hi(t, ta, e.memoizedState.cache), Li(); + break; + case 27: + case 5: + L(t); + break; + case 4: + de(t, t.stateNode.containerInfo); + break; + case 10: + Hi(t, t.type, t.memoizedProps.value); + break; + case 31: + if (t.memoizedState !== null) return t.flags |= 128, eo(t), null; + break; + case 13: + var r = t.memoizedState; + if (r !== null) return r.dehydrated === null ? (n & t.child.childLanes) === 0 ? ($a(t), e = Dc(e, t, n), e === null ? null : e.sibling) : bc(e, t, n) : ($a(t), t.flags |= 128, null); + $a(t); + break; + case 19: + var i = !!(e.flags & 128); + if (r = (n & t.childLanes) !== 0, r ||= (Ki(e, t, n, !1), (n & t.childLanes) !== 0), i) { + if (r) return Ec(e, t, n); + t.flags |= 128; + } + if (i = t.memoizedState, i !== null && (i.rendering = null, i.tail = null, i.lastEffect = null), N(io, io.current), r) break; + return null; + case 22: return t.lanes = 0, oc(e, t, n, t.pendingProps); + case 24: Hi(t, ta, e.memoizedState.cache); + } + return Dc(e, t, n); + } + function Ac(e, t, n) { + if (e !== null) { + if (e.memoizedProps !== t.pendingProps) tc = !0; + else { + if (!Oc(e, n) && !(t.flags & 128)) return tc = !1, kc(e, t, n); + tc = !!(e.flags & 131072); + } + } else tc = !1, ki && t.flags & 1048576 && Ci(t, gi, t.index); + switch (t.lanes = 0, t.tag) { + case 16: + a: { + var r = t.pendingProps; + if (e = Sa(t.elementType), t.type = e, typeof e == "function") ri(e) ? (r = Ws(e, r), t.tag = 1, t = hc(null, t, e, r, n)) : (t.tag = 0, t = pc(null, t, e, r, n)); + else { + if (e != null) { + var a = e.$$typeof; + if (a === w) { + t.tag = 11, t = rc(null, t, e, r, n); + break a; + } + if (a === D) { + t.tag = 14, t = ic(null, t, e, r, n); + break a; + } + } + throw t = ie(e) || e, Error(i(306, t, "")); + } + } + return t; + case 0: return pc(e, t, t.type, t.pendingProps, n); + case 1: return r = t.type, a = Ws(r, t.pendingProps), hc(e, t, r, a, n); + case 3: + a: { + if (de(t, t.stateNode.containerInfo), e === null) throw Error(i(387)); + r = t.pendingProps; + var o = t.memoizedState; + a = o.element, Ia(e, t), Ua(t, r, null, n); + var s = t.memoizedState; + if (r = s.cache, Hi(t, ta, r), r !== o.cache && Gi(t, [ta], n, !0), Ha(), r = s.element, o.isDehydrated) { + if (o = { + element: r, + isDehydrated: !1, + cache: s.cache + }, t.updateQueue.baseState = o, t.memoizedState = o, t.flags & 256) { + t = gc(e, t, r, n); + break a; + } + if (r !== a) { + a = fi(Error(i(424)), t), zi(a), t = gc(e, t, r, n); + break a; + } + switch (e = t.stateNode.containerInfo, e.nodeType) { + case 9: + e = e.body; + break; + default: e = e.nodeName === "HTML" ? e.ownerDocument.body : e; + } + for (Oi = gf(e.firstChild), Di = t, ki = !0, Ai = null, ji = !0, n = Na(t, null, r, n), t.child = n; n;) n.flags = n.flags & -3 | 4096, n = n.sibling; + } else { + if (Li(), r === a) { + t = Dc(e, t, n); + break a; + } + nc(e, t, r, n); + } + t = t.child; + } + return t; + case 26: return fc(e, t), e === null ? (n = Lf(t.type, null, t.pendingProps, null)) ? t.memoizedState = n : ki || (n = t.type, e = t.pendingProps, r = Jd(ue.current).createElement(n), r[tt] = t, r[nt] = e, Hd(r, n, e), mt(r), t.stateNode = r) : t.memoizedState = Lf(t.type, e.memoizedProps, t.pendingProps, e.memoizedState), null; + case 27: return L(t), e === null && ki && (r = t.stateNode = bf(t.type, t.pendingProps, ue.current), Di = t, ji = !0, a = Oi, of(t.type) ? (_f = a, Oi = gf(r.firstChild)) : Oi = a), nc(e, t, t.pendingProps.children, n), fc(e, t), e === null && (t.flags |= 4194304), t.child; + case 5: return e === null && ki && ((a = r = Oi) && (r = uf(r, t.type, t.pendingProps, ji), r === null ? a = !1 : (t.stateNode = r, Di = t, Oi = gf(r.firstChild), ji = !1, a = !0)), a || Ni(t)), L(t), a = t.type, o = t.pendingProps, s = e === null ? null : e.memoizedProps, r = o.children, Zd(a, o) ? r = null : s !== null && Zd(a, s) && (t.flags |= 32), t.memoizedState !== null && (a = bo(e, t, Co, null, null, n), op._currentValue = a), fc(e, t), nc(e, t, r, n), t.child; + case 6: return e === null && ki && ((e = n = Oi) && (n = df(n, t.pendingProps, ji), n === null ? e = !1 : (t.stateNode = n, Di = t, Oi = null, e = !0)), e || Ni(t)), null; + case 13: return bc(e, t, n); + case 4: return de(t, t.stateNode.containerInfo), r = t.pendingProps, e === null ? t.child = Ma(t, null, r, n) : nc(e, t, r, n), t.child; + case 11: return rc(e, t, t.type, t.pendingProps, n); + case 7: return nc(e, t, t.pendingProps, n), t.child; + case 8: return nc(e, t, t.pendingProps.children, n), t.child; + case 12: return nc(e, t, t.pendingProps.children, n), t.child; + case 10: return r = t.pendingProps, Hi(t, t.type, r.value), nc(e, t, r.children, n), t.child; + case 9: return a = t.type._context, r = t.pendingProps.children, Ji(t), a = Yi(a), r = r(a), t.flags |= 1, nc(e, t, r, n), t.child; + case 14: return ic(e, t, t.type, t.pendingProps, n); + case 15: return ac(e, t, t.type, t.pendingProps, n); + case 19: return Ec(e, t, n); + case 31: return dc(e, t, n); + case 22: return oc(e, t, n, t.pendingProps); + case 24: return Ji(t), r = Yi(ta), e === null ? (a = pa(), a === null && (a = Bl, o = na(), a.pooledCache = o, o.refCount++, o !== null && (a.pooledCacheLanes |= n), a = o), t.memoizedState = { + parent: r, + cache: a + }, Fa(t), Hi(t, ta, a)) : ((e.lanes & n) !== 0 && (Ia(e, t), Ua(t, null, null, n), Ha()), a = e.memoizedState, o = t.memoizedState, a.parent === r ? (r = o.cache, Hi(t, ta, r), r !== a.cache && Gi(t, [ta], n, !0)) : (a = { + parent: r, + cache: r + }, t.memoizedState = a, t.lanes === 0 && (t.memoizedState = t.updateQueue.baseState = a), Hi(t, ta, r))), nc(e, t, t.pendingProps.children, n), t.child; + case 29: throw t.pendingProps; + } + throw Error(i(156, t.tag)); + } + function jc(e) { + e.flags |= 4; + } + function Mc(e, t, n, r, i) { + if ((t = !!(e.mode & 32)) && (t = !1), t) { + if (e.flags |= 16777216, (i & 335544128) === i) { + if (e.stateNode.complete) e.flags |= 8192; + else if (ku()) e.flags |= 8192; + else throw Ca = ya, _a; + } + } else e.flags &= -16777217; + } + function Nc(e, t) { + if (t.type !== "stylesheet" || t.state.loading & 4) e.flags &= -16777217; + else if (e.flags |= 16777216, !Qf(t)) { + if (ku()) e.flags |= 8192; + else throw Ca = ya, _a; + } + } + function Pc(e, t) { + t !== null && (e.flags |= 4), e.flags & 16384 && (t = e.tag === 22 ? 536870912 : U(), e.lanes |= t, eu |= t); + } + function Fc(e, t) { + if (!ki) switch (e.tailMode) { + case "hidden": + t = e.tail; + for (var n = null; t !== null;) t.alternate !== null && (n = t), t = t.sibling; + n === null ? e.tail = null : n.sibling = null; + break; + case "collapsed": + n = e.tail; + for (var r = null; n !== null;) n.alternate !== null && (r = n), n = n.sibling; + r === null ? t || e.tail === null ? e.tail = null : e.tail.sibling = null : r.sibling = null; + } + } + function Ic(e) { + var t = e.alternate !== null && e.alternate.child === e.child, n = 0, r = 0; + if (t) for (var i = e.child; i !== null;) n |= i.lanes | i.childLanes, r |= i.subtreeFlags & 65011712, r |= i.flags & 65011712, i.return = e, i = i.sibling; + else for (i = e.child; i !== null;) n |= i.lanes | i.childLanes, r |= i.subtreeFlags, r |= i.flags, i.return = e, i = i.sibling; + return e.subtreeFlags |= r, e.childLanes = n, t; + } + function Lc(e, t, n) { + var r = t.pendingProps; + switch (Ti(t), t.tag) { + case 16: + case 15: + case 0: + case 11: + case 7: + case 8: + case 12: + case 9: + case 14: return Ic(t), null; + case 1: return Ic(t), null; + case 3: return n = t.stateNode, r = null, e !== null && (r = e.memoizedState.cache), t.memoizedState.cache !== r && (t.flags |= 2048), Ui(ta), fe(), n.pendingContext && (n.context = n.pendingContext, n.pendingContext = null), (e === null || e.child === null) && (Ii(t) ? jc(t) : e === null || e.memoizedState.isDehydrated && !(t.flags & 256) || (t.flags |= 1024, Ri())), Ic(t), null; + case 26: + var a = t.type, o = t.memoizedState; + return e === null ? (jc(t), o === null ? (Ic(t), Mc(t, a, null, r, n)) : (Ic(t), Nc(t, o))) : o ? o === e.memoizedState ? (Ic(t), t.flags &= -16777217) : (jc(t), Ic(t), Nc(t, o)) : (e = e.memoizedProps, e !== r && jc(t), Ic(t), Mc(t, a, e, r, n)), null; + case 27: + if (R(t), n = ue.current, a = t.type, e !== null && t.stateNode != null) e.memoizedProps !== r && jc(t); + else { + if (!r) { + if (t.stateNode === null) throw Error(i(166)); + return Ic(t), null; + } + e = P.current, Ii(t) ? Pi(t, e) : (e = bf(a, r, n), t.stateNode = e, jc(t)); + } + return Ic(t), null; + case 5: + if (R(t), a = t.type, e !== null && t.stateNode != null) e.memoizedProps !== r && jc(t); + else { + if (!r) { + if (t.stateNode === null) throw Error(i(166)); + return Ic(t), null; + } + if (o = P.current, Ii(t)) Pi(t, o); + else { + var s = Jd(ue.current); + switch (o) { + case 1: + o = s.createElementNS("http://www.w3.org/2000/svg", a); + break; + case 2: + o = s.createElementNS("http://www.w3.org/1998/Math/MathML", a); + break; + default: switch (a) { + case "svg": + o = s.createElementNS("http://www.w3.org/2000/svg", a); + break; + case "math": + o = s.createElementNS("http://www.w3.org/1998/Math/MathML", a); + break; + case "script": + o = s.createElement("div"), o.innerHTML = "