diff --git a/.claude/skills/ctx-experimental-handoff/SKILL.md b/.claude/skills/ctx-experimental-handoff/SKILL.md index 39ab6f606..163d0354b 100644 --- a/.claude/skills/ctx-experimental-handoff/SKILL.md +++ b/.claude/skills/ctx-experimental-handoff/SKILL.md @@ -7,7 +7,7 @@ allowed-tools: Bash(specify:*), Read, Glob # Hand off an intent spec to spec-kit — experimental > **Experimental / discardable.** ctx-native port of an external -> spec-handoff skill. It is the delegation seam canonical ctx does +> `anchor-handoff` skill. It is the delegation seam canonical ctx does > not have: ctx's chain terminates at `/ctx-implement`, whereas this one > hands the intent spec to spec-kit. Trial it; if the seam is worth > keeping, promote it to a real `/ctx-handoff`. diff --git a/.claude/skills/ctx-experimental-plan/SKILL.md b/.claude/skills/ctx-experimental-plan/SKILL.md index f0a22d8d4..0c4a250f4 100644 --- a/.claude/skills/ctx-experimental-plan/SKILL.md +++ b/.claude/skills/ctx-experimental-plan/SKILL.md @@ -7,7 +7,7 @@ allowed-tools: Read, Write, Glob, Grep, Bash(date:*) # Plan scrutiny (adversarial interview) — experimental > **Experimental / discardable.** This is a ctx-native port of an -> external plan-scrutiny skill, kept as a project-level skill so it can +> external `anchor-plan` skill, kept as a project-level skill so it can > be trialed and deleted without touching ctx's canonical > `/ctx-plan`. It feeds the experimental spec-kit delegation chain > `/ctx-experimental-plan → /ctx-experimental-spec → diff --git a/.claude/skills/ctx-experimental-spec/SKILL.md b/.claude/skills/ctx-experimental-spec/SKILL.md index 7baa4ac2d..c89831f0b 100644 --- a/.claude/skills/ctx-experimental-spec/SKILL.md +++ b/.claude/skills/ctx-experimental-spec/SKILL.md @@ -7,7 +7,7 @@ allowed-tools: Read, Edit, Write, Glob, Grep # Write an intent spec from a debrief — experimental > **Experimental / discardable.** ctx-native port of an external -> intent-spec skill. It deliberately writes a **loose intent spec** in +> `anchor-spec` skill. It deliberately writes a **loose intent spec** in > a ctx-namespaced location (`.context/specs/`), separate from > spec-kit's repo-root `specs//`, so the two trees never > collide. This differs from canonical `/ctx-spec`, which walks the full diff --git a/.context/AGENT_PLAYBOOK.md b/.context/AGENT_PLAYBOOK.md index ef97eea04..11ec8ec8e 100644 --- a/.context/AGENT_PLAYBOOK.md +++ b/.context/AGENT_PLAYBOOK.md @@ -74,6 +74,15 @@ go run ./cmd/ctx # ✗ avoid unless developing ctx itself ``` Check with `which ctx` if unsure whether it's installed. +### Optional AI Backends + +`ctx ai` is optional and fail-closed. Use `ctx setup --backend ` to +configure a backend, `ctx ai ping` to verify it, and `ctx ai propose +--emit ...` only to write reviewable artifacts under `.context/proposals/ai/`. +Do not wire deterministic commands, ceremonies, or hooks to backend +availability; `ctx status`, `ctx agent`, and hooks must keep working with no +backend configured. + ### When ctx Returns an Error Triage the error before reacting: diff --git a/.context/CONVENTIONS.md b/.context/CONVENTIONS.md index 47fa7ad08..4ffc2e3b3 100644 --- a/.context/CONVENTIONS.md +++ b/.context/CONVENTIONS.md @@ -303,14 +303,7 @@ variants. Linters in `hack/` enforce the hard rules. - New editor integrations include an MCP-merge test covering: create / empty file / preserve existing keys / skip when registered / reject malformed JSON -- Substrate vs. artifact placement: cognitive substrate (consumed and mutated - via ctx-mediated paths — `ctx agent`, `ctx decision add`, `/ctx-kb-ingest`, - `/ctx-handover`, ceremonies) lives under `.context/`; project artifacts (read - and edited directly by humans — `specs/`, `CLAUDE.md`, `GETTING_STARTED.md`, - `docs/`) live at the project root; tool config and tool homes (`.ctxrc`, - `.claude/`) live at root by dotfile/tool convention. The kb is substrate, not - artifact: direct file edits remain possible per Invariant 1, but the - skill-mediated path is the discipline. Rationale recorded in DECISIONS.md. +- Substrate vs. artifact placement: cognitive substrate (consumed and mutated via ctx-mediated paths — `ctx agent`, `ctx decision add`, `/ctx-kb-ingest`, `/ctx-handover`, ceremonies) lives under `.context/`; project artifacts (read and edited directly by humans — `specs/`, `CLAUDE.md`, `GETTING_STARTED.md`, `docs/`) live at the project root; tool config and tool homes (`.ctxrc`, `.claude/`) live at root by dotfile/tool convention. The kb is substrate, not artifact: direct file edits remain possible per Invariant 1, but the skill-mediated path is the discipline. Rationale recorded in DECISIONS.md. ## User-Facing Surface Completeness @@ -385,6 +378,4 @@ resolves correctly under cwd-anchoring). `tools/ctxctl/` is the first inhabitant. Future maintainer binaries follow the same shape. -- Maintainer-only docs (features that run through the ctxctl binary, never - shipped to users) live under docs/operations/runbooks/, not docs/recipes/ - (user-facing). contributing.md is the entry point that links to the runbook. +- Maintainer-only docs (features that run through the ctxctl binary, never shipped to users) live under docs/operations/runbooks/, not docs/recipes/ (user-facing). contributing.md is the entry point that links to the runbook. diff --git a/.context/DECISIONS.md b/.context/DECISIONS.md index acde09da2..71771463b 100644 --- a/.context/DECISIONS.md +++ b/.context/DECISIONS.md @@ -3,8 +3,7 @@ | Date | Decision | |----|--------| -| 2026-07-04 | Statusline informs, never gates | -| 2026-07-03 | Keep sonnet-4-6 at the 200k default despite the API catalog listing 1M | +| 2026-06-19 | `ctx ai` is a separate namespace with proposed-patch output only | | 2026-06-07 | ctx-dream executor is a documented contract, not a hardcoded cron/claude assumption | | 2026-06-07 | Output belongs in write/ — taxonomy and emission style (consolidated) | | 2026-06-07 | Package taxonomy and shared-code placement (consolidated) | @@ -111,31 +110,48 @@ For significant decisions: --> -## [2026-07-04-152957] Statusline informs, never gates +## [2026-06-19-064500] `ctx ai` is a separate namespace with proposed-patch output only **Status**: Accepted -**Context**: Porting a cost-aware status line whose reference design escalates to a spend alarm with a model-switch suggestion when an expensive model family is detected - -**Decision**: Statusline informs, never gates - -**Rationale**: A family-substring rule carries no task context: the expensive model is often the cheaper choice per outcome, and a statusline cannot see outcomes, so it must not prescribe. Alarms also only reach operators who are present and already see the dollar figure; unattended overspend belongs to loop/cron notifications - -**Consequence**: ctx system statusline renders model, ctx%, and plain cost only; show_cost exists for screen-sharing; any future budget enforcement must be a separate, deliberate feature, not statusline creep - ---- - -## [2026-07-03-182236] Keep sonnet-4-6 at the 200k default despite the API catalog listing 1M - -**Status**: Accepted - -**Context**: Claude 5 window-detection fix (specs/model-context-window-fable.md); Anthropic's current catalog shows Sonnet 4.6 with a 1M window at the API level - -**Decision**: Keep sonnet-4-6 at the 200k default despite the API catalog listing 1M - -**Rationale**: ctx models Claude Code's per-session gating, not raw API capability: Sonnet 4.6's 1M is an explicit opt-in already handled by ModelSuffix1M and ClaudeSettingsHas1M, and the existing test deliberately pins the 200k default - -**Consequence**: Revisit only with session-level evidence (a sonnet-4-6 JSONL showing 1M without the [1m] suffix); over-reporting the window would silence the context hook while a session genuinely fills +**Context**: GitHub issue #92 (`ctx ai backend`) introduces an optional, +local-first AI backend layer. The governing spec left several Block A choices +open: whether AI use should live under a new `ctx ai ` namespace or as +flags on existing commands, where the validation consumer should write +proposals, whether Block A needs a companion skill, and how to reconcile the +spec's TOML examples with the repo's existing YAML `.ctxrc` parser. + +**Decision**: Block A uses a new top-level `ctx ai ` namespace. Backend +configuration uses the existing YAML `.ctxrc` shape under `backends:` rather +than TOML-style `[backends]` tables. `ctx setup --backend ` is a distinct +setup mode that can run without the current `` positional argument. The +provisional proposal queue is `.context/proposals/ai/`, and the Block A +validation consumer is `ctx ai propose --emit ...`, a generic +validation-only proposer that writes proposed-patch JSON artifacts and never +mutates `.context/*.md`. No new companion skill ships in Block A; command +assets, setup docs, the `ctx ai` CLI reference, the vLLM recipe, and the agent +playbook note cover the user-facing surface. + +**Rationale**: A separate `ctx ai` namespace keeps optional AI behavior out of +deterministic commands (`ctx status`, `ctx agent`, ceremonies, and hooks), makes +fail-closed behavior explicit, and avoids smuggling backend availability into +existing deterministic verbs through flags like `--use-ai`. YAML config matches +the actual `internal/rc` implementation and avoids landing a spec that cannot +be implemented without replacing the config parser. `.context/proposals/ai/` +keeps AI-produced suggestions inside the cognitive substrate while preserving +the human gate before canonical memory changes. A generic `propose` verb proves +backend dispatch and artifact writing without pretending to settle the final +Block B taxonomy; later `ctx ai compact` or `ctx ai ingest` commands remain +available once the extraction-and-recall spec is promoted. + +**Consequence**: Implementations must add a deterministic-boundary guard so +agent/status/ceremony paths cannot import `internal/backend` or invoke `ctx ai`. +Multiple configured backends require `--backend ` or `backends.default`; +there is no implicit selection and no deterministic fallback. Proposed-patch +artifacts need a minimal schema with backend, model, input reference, emit +kinds, proposed rows, source spans or citations when available, and status +metadata. Documentation and command assets are part of the same deliverable +because `ctx ai` is a user-facing surface. Spec: `specs/ctx-ai-backend.md`. --- @@ -143,30 +159,13 @@ For significant decisions: **Status**: Accepted -**Context**: Settling ctx-dream v1 open questions. The executor runs the -out-of-band dream pass (read ideas/, classify+ground, write proposals). Question -was cron 'claude -p' vs a raw Anthropic-API scheduled loop. +**Context**: Settling ctx-dream v1 open questions. The executor runs the out-of-band dream pass (read ideas/, classify+ground, write proposals). Question was cron 'claude -p' vs a raw Anthropic-API scheduled loop. -**Decision**: ctx-dream executor is a documented contract, not a hardcoded -cron/claude assumption +**Decision**: ctx-dream executor is a documented contract, not a hardcoded cron/claude assumption -**Rationale**: cron 'claude -p' is the reference executor (reuses Claude Code -auth, tool-calling, and PreToolUse hooks so the three guards are structural for -free; matches the existing skill draft and the cheap-validation goal). But we -must NOT assume it is the only executor: other harnesses (different AI CLI, raw -API loop, CI runner) must be able to run the same dream. So ctx owns an -executor-agnostic Go core (dreams/ layout, state record, ledger, proposal -schema, the three guards as callable logic) and the executor is a documented -contract: run one bounded pass, enforce the three guards STRUCTURALLY (Claude -Code via PreToolUse hooks; API loop via in-loop tool executor), fail loud, write -proposals-only into dreams/. Dream is opt-in, not enabled by default. +**Rationale**: cron 'claude -p' is the reference executor (reuses Claude Code auth, tool-calling, and PreToolUse hooks so the three guards are structural for free; matches the existing skill draft and the cheap-validation goal). But we must NOT assume it is the only executor: other harnesses (different AI CLI, raw API loop, CI runner) must be able to run the same dream. So ctx owns an executor-agnostic Go core (dreams/ layout, state record, ledger, proposal schema, the three guards as callable logic) and the executor is a documented contract: run one bounded pass, enforce the three guards STRUCTURALLY (Claude Code via PreToolUse hooks; API loop via in-loop tool executor), fail loud, write proposals-only into dreams/. Dream is opt-in, not enabled by default. -**Consequence**: Guards live as reusable Go logic in internal/dream/, not only -as a hook script. Two user-facing docs are required: a Claude Code enablement -guide and an executor-contract reference for other harnesses. The serendipity -review skill is split into its own spec (specs/ctx-serendipity.md). v1 ships the -cron/claude-p reference path but the data contract + guards stay -executor-portable. +**Consequence**: Guards live as reusable Go logic in internal/dream/, not only as a hook script. Two user-facing docs are required: a Claude Code enablement guide and an executor-contract reference for other harnesses. The serendipity review skill is split into its own spec (specs/ctx-serendipity.md). v1 ships the cron/claude-p reference path but the data contract + guards stay executor-portable. --- @@ -174,14 +173,8 @@ executor-portable. **Consolidated from**: 3 entries (2026-03-17 to 2026-04-03) -- Output functions belong in write/ (flat by domain, one package per CLI - feature); core/ owns logic and types, cmd/ owns Cobra orchestration. No - cmd.Print* calls in internal/cli/ outside internal/write/ — enables - localization and clean separation. -- Within write/, use pre-compute-then-print: functions with 4+ Printlns - pre-compute conditional strings then emit one multiline block (TplXxxBlock), - rejecting text/template (runtime errors, only 38/160 functions benefit); - trivial and loop-based functions stay imperative. +- Output functions belong in write/ (flat by domain, one package per CLI feature); core/ owns logic and types, cmd/ owns Cobra orchestration. No cmd.Print* calls in internal/cli/ outside internal/write/ — enables localization and clean separation. +- Within write/, use pre-compute-then-print: functions with 4+ Printlns pre-compute conditional strings then emit one multiline block (TplXxxBlock), rejecting text/template (runtime errors, only 38/160 functions benefit); trivial and loop-based functions stay imperative. --- @@ -189,24 +182,12 @@ executor-portable. **Consolidated from**: 6 entries (2026-03-06 to 2026-05-17) -- Three-zone taxonomy: cmd/ for Cobra wiring, core/ for logic and types, assets/ - for templates and user-facing text; config/ for structural constants only. - Symmetry makes navigation agent-friendly; shared domain types live in domain - packages (internal/entry), not CLI subpackages. -- Pure-logic functions return data structs; callers own I/O, file writes, and - reporting — lets MCP and CLI callers control output independently. - Receiver-stateless methods become free functions; callbacks that vary only by - a string key become text-key data. -- Shared formatting utilities (Pluralize, Duration, TruncateFirstLine, etc.) - live in internal/format, not duplicated across CLI subpackages. -- internal/parse is the home for shared text-to-typed-value conversions - (parse.Date first), scoped to avoid becoming a junk drawer. -- Every cross-package type goes in internal/entity/ — the cross-package-types - audit (zero grandfathered violations) is the hardline; entity.Sentinel lives - there even though it is a behavioral helper, over per-package duplication - across 9 err packages. -- Multi-segment directory paths are single composite constants - (DirHooksMessages, DirMemoryArchive), not joined from segment constants. +- Three-zone taxonomy: cmd/ for Cobra wiring, core/ for logic and types, assets/ for templates and user-facing text; config/ for structural constants only. Symmetry makes navigation agent-friendly; shared domain types live in domain packages (internal/entry), not CLI subpackages. +- Pure-logic functions return data structs; callers own I/O, file writes, and reporting — lets MCP and CLI callers control output independently. Receiver-stateless methods become free functions; callbacks that vary only by a string key become text-key data. +- Shared formatting utilities (Pluralize, Duration, TruncateFirstLine, etc.) live in internal/format, not duplicated across CLI subpackages. +- internal/parse is the home for shared text-to-typed-value conversions (parse.Date first), scoped to avoid becoming a junk drawer. +- Every cross-package type goes in internal/entity/ — the cross-package-types audit (zero grandfathered violations) is the hardline; entity.Sentinel lives there even though it is a behavioral helper, over per-package duplication across 9 err packages. +- Multi-segment directory paths are single composite constants (DirHooksMessages, DirMemoryArchive), not joined from segment constants. --- @@ -214,12 +195,8 @@ executor-portable. **Consolidated from**: 2 entries (2026-03-06 to 2026-03-14) -- Errors centralize in internal/err, not per-package err.go files — single - location makes duplicates visible, enables sentinel errors, prevents - broken-window accumulation; all CLI err.go files migrated and deleted. -- The monolithic 1995-line errors.go (188 functions) was split into 22 domain - files (backup, config, crypto, …, validation) named by responsibility, so - error constructors are findable by domain. +- Errors centralize in internal/err, not per-package err.go files — single location makes duplicates visible, enables sentinel errors, prevents broken-window accumulation; all CLI err.go files migrated and deleted. +- The monolithic 1995-line errors.go (188 functions) was split into 22 domain files (backup, config, crypto, …, validation) named by responsibility, so error constructors are findable by domain. --- @@ -227,19 +204,10 @@ executor-portable. **Consolidated from**: 4 entries (2026-03-23 to 2026-04-04) -- String-typed enums (type Foo string + const blocks) belong in config/, not - domain packages — types without behavior live in config; promote to entity/ - only when methods/interfaces appear. -- TestNoMagicStrings/TestNoMagicValues dropped the const/var exemption outside - config/ (it masked 156+ string and 7 numeric constants in the wrong place); - naming a constant in the wrong package does not fix the structural problem. -- The 60+ config/ sub-package "explosion" is correct, not a bottleneck: Go's - compile unit is the package, so granular packages give precise dependency - tracking and minimal recompile; the DX cost is fixed by a README decision - tree, not restructuring. -- Cross-package magic strings (e.g.
 HTML tags used by normalize and
-  format) promote to shared config constants (config/marker TagPre/TagPreClose);
-  package-local copies deleted.
+- String-typed enums (type Foo string + const blocks) belong in config/, not domain packages — types without behavior live in config; promote to entity/ only when methods/interfaces appear.
+- TestNoMagicStrings/TestNoMagicValues dropped the const/var exemption outside config/ (it masked 156+ string and 7 numeric constants in the wrong place); naming a constant in the wrong package does not fix the structural problem.
+- The 60+ config/ sub-package "explosion" is correct, not a bottleneck: Go's compile unit is the package, so granular packages give precise dependency tracking and minimal recompile; the DX cost is fixed by a README decision tree, not restructuring.
+- Cross-package magic strings (e.g. 
 HTML tags used by normalize and format) promote to shared config constants (config/marker TagPre/TagPreClose); package-local copies deleted.
 
 ---
 
@@ -247,24 +215,11 @@ executor-portable.
 
 **Consolidated from**: 5 entries (2026-03-13 to 2026-04-03)
 
-- All user-facing text externalizes to embedded YAML domain files
-  (commands/flags/text/examples split via dedicated loaders), justified by agent
-  legibility (named DescKey constants as traversable graphs) and drift
-  prevention, not i18n; the 3-file ceremony (DescKey + YAML + write/err fn) is
-  the accepted cost.
-- Static embedded data and resource lookups use an explicit Init() called
-  eagerly at startup, not per-accessor sync.Once or package-level init() —
-  makes the startup dependency visible and testable; maps unexported, accessors
-  are plain lookups.
-- A Go↔YAML linkage check (lint-drift check 5, shell grep+comm) catches
-  orphaned/broken DescKey↔YAML links and cross-namespace duplicates at CI
-  time, preventing silent runtime failures.
-- The build target depends on sync-why so derived assets/why/ files cannot drift
-  from their docs/ sources — build fails without sync.
-- MCP resource name constants live in config/mcp/resource (parallel to
-  config/mcp/tool); the resource→file mapping stays in server/resource (too
-  many cross-cutting deps for a config package), pre-built once at server init
-  for O(1) lookup.
+- All user-facing text externalizes to embedded YAML domain files (commands/flags/text/examples split via dedicated loaders), justified by agent legibility (named DescKey constants as traversable graphs) and drift prevention, not i18n; the 3-file ceremony (DescKey + YAML + write/err fn) is the accepted cost.
+- Static embedded data and resource lookups use an explicit Init() called eagerly at startup, not per-accessor sync.Once or package-level init() — makes the startup dependency visible and testable; maps unexported, accessors are plain lookups.
+- A Go↔YAML linkage check (lint-drift check 5, shell grep+comm) catches orphaned/broken DescKey↔YAML links and cross-namespace duplicates at CI time, preventing silent runtime failures.
+- The build target depends on sync-why so derived assets/why/ files cannot drift from their docs/ sources — build fails without sync.
+- MCP resource name constants live in config/mcp/resource (parallel to config/mcp/tool); the resource→file mapping stays in server/resource (too many cross-cutting deps for a config package), pre-built once at server init for O(1) lookup.
 
 ---
 
@@ -272,28 +227,11 @@ executor-portable.
 
 **Consolidated from**: 5 entries (2026-04-13 to 2026-05-21)
 
-- Walk boundary uses git as a hint, not a requirement: walkForContextDir
-  consults findGitRoot to anchor ancestor .context candidates and falls back to
-  CWD when no git is found — fixes nested-repo binding without making git
-  mandatory or relying on unreliable project markers.
-- ctx activate is strict-CWD (drop upward walk): state-setting commands follow
-  git's read-vs-state pattern (read walks, state refuses to cross repo
-  boundaries); workspace-shared layouts are preserved by user action (cd first),
-  not inferred walk.
-- Anchor ctx to CWD entirely: drop activate/deactivate, the env-var (CTX_DIR)
-  resolver, and all walks. With .context/ mandated as .git/'s sibling, every
-  resolver collapses to os.Stat; keeping any walk would force maintaining two
-  implementations. Mental model matches helm/terraform/Claude Code; ~600-1000
-  LOC net deletion (specs/cwd-anchored-context.md).
-- Spec steps 1+2 (resolver swap + init-guard removal) merged into one commit
-  because step 1 cannot compile without step 2; cleanest commit boundaries beat
-  strict spec adherence — remaining steps stay discrete (4-commit
-  decomposition, not the spec's 5).
-- Substrate vs. artifact placement: cognitive substrate (read AND written via
-  ctx-mediated paths) lives under .context/; project artifacts (read/edited
-  directly by humans, e.g. specs/, CLAUDE.md, docs/) live at root. kb passes all
-  three coupling tests (mediated queries, pipeline coupling, skill discipline)
-  so it stays under .context/.
+- Walk boundary uses git as a hint, not a requirement: walkForContextDir consults findGitRoot to anchor ancestor .context candidates and falls back to CWD when no git is found — fixes nested-repo binding without making git mandatory or relying on unreliable project markers.
+- ctx activate is strict-CWD (drop upward walk): state-setting commands follow git's read-vs-state pattern (read walks, state refuses to cross repo boundaries); workspace-shared layouts are preserved by user action (cd first), not inferred walk.
+- Anchor ctx to CWD entirely: drop activate/deactivate, the env-var (CTX_DIR) resolver, and all walks. With .context/ mandated as .git/'s sibling, every resolver collapses to os.Stat; keeping any walk would force maintaining two implementations. Mental model matches helm/terraform/Claude Code; ~600-1000 LOC net deletion (specs/cwd-anchored-context.md).
+- Spec steps 1+2 (resolver swap + init-guard removal) merged into one commit because step 1 cannot compile without step 2; cleanest commit boundaries beat strict spec adherence — remaining steps stay discrete (4-commit decomposition, not the spec's 5).
+- Substrate vs. artifact placement: cognitive substrate (read AND written via ctx-mediated paths) lives under .context/; project artifacts (read/edited directly by humans, e.g. specs/, CLAUDE.md, docs/) live at root. kb passes all three coupling tests (mediated queries, pipeline coupling, skill discipline) so it stays under .context/.
 
 ---
 
@@ -301,20 +239,9 @@ executor-portable.
 
 **Consolidated from**: 3 entries (2026-03-01 to 2026-06-02)
 
-- Single global key at ~/.ctx/.ctx.key (matches ~/.claude/ convention); one key
-  per machine covers ~99% of users. Replaced the over-engineered slug-based
-  per-project key system; project-local key-next-to-ciphertext was a security
-  antipattern that broke in worktrees. [Original 2026-03-01 entry was marked
-  Superseded by the 2026-03-02 simplification.]
-- Legacy-key auto-migration replaced with a stderr warning only: warn-only is
-  simpler, avoids silent file operations, and keeps the (small, alpha) userbase
-  in control; docs carry migration instructions.
-- Removed the implicit project-local .context/.ctx.key auto-detection tier from
-  ResolveKeyPath: resolution is now (1) explicit .ctxrc key_path, (2) global
-  ~/.ctx/.ctx.key, (3) project-local only as a degenerate fallback when home is
-  unavailable. The local tier was the only thing making worktrees differ from
-  side-by-side terminals; its removal is net deletion, and the previously-silent
-  fire-path decrypt failure is now surfaced.
+- Single global key at ~/.ctx/.ctx.key (matches ~/.claude/ convention); one key per machine covers ~99% of users. Replaced the over-engineered slug-based per-project key system; project-local key-next-to-ciphertext was a security antipattern that broke in worktrees. [Original 2026-03-01 entry was marked Superseded by the 2026-03-02 simplification.]
+- Legacy-key auto-migration replaced with a stderr warning only: warn-only is simpler, avoids silent file operations, and keeps the (small, alpha) userbase in control; docs carry migration instructions.
+- Removed the implicit project-local .context/.ctx.key auto-detection tier from ResolveKeyPath: resolution is now (1) explicit .ctxrc key_path, (2) global ~/.ctx/.ctx.key, (3) project-local only as a degenerate fallback when home is unavailable. The local tier was the only thing making worktrees differ from side-by-side terminals; its removal is net deletion, and the previously-silent fire-path decrypt failure is now surfaced.
 
 ---
 
@@ -322,27 +249,10 @@ executor-portable.
 
 **Consolidated from**: 4 entries (2026-05-24 to 2026-05-28)
 
-- Discipline enforcement belongs on the verbatim-relay channel, run out-of-band:
-  relay is the one discipline channel that survives tunnel vision; run the
-  auditor in a separate Claude Code session for fresh-context judgment and cost
-  control. New generic channel: a skill writes .context/audit/.md, a
-  check-audit hook relays unread reports verbatim, ctx audit list/show/dismiss
-  manages lifecycle (digest-bound dismissal).
-- [Superseded] ctxctl first placed at cmd/ctxctl in the same Go module:
-  binary-level isolation via transitive-import exclusion, zero relocation of
-  existing internal/audit files, on the belief a separate go.mod couldn't import
-  the parent's internal/.
-- That belief was empirically disproved: a nested module lexically under the
-  parent path CAN import internal/. So ctxctl became a separate Go module at
-  tools/ctxctl (own go.mod) — a hard module boundary guarantees ctx can never
-  import ctxctl (the asymmetric requirement that matters); one-directional
-  ctxctl→ctx coupling is acceptable for disposable maintainer tooling. A
-  go.work wires the workspace; a guard test asserts cmd/ctx never imports
-  internal/ctxctl.
-- ctxctl is PATH-installed alongside ctx (build to dist/, install to
-  /usr/local/bin/ctxctl) for clean repo roots and one binary across all
-  worktrees, mirroring ctx's install pattern; the local hook calls ctxctl from
-  PATH.
+- Discipline enforcement belongs on the verbatim-relay channel, run out-of-band: relay is the one discipline channel that survives tunnel vision; run the auditor in a separate Claude Code session for fresh-context judgment and cost control. New generic channel: a skill writes .context/audit/.md, a check-audit hook relays unread reports verbatim, ctx audit list/show/dismiss manages lifecycle (digest-bound dismissal).
+- [Superseded] ctxctl first placed at cmd/ctxctl in the same Go module: binary-level isolation via transitive-import exclusion, zero relocation of existing internal/audit files, on the belief a separate go.mod couldn't import the parent's internal/.
+- That belief was empirically disproved: a nested module lexically under the parent path CAN import internal/. So ctxctl became a separate Go module at tools/ctxctl (own go.mod) — a hard module boundary guarantees ctx can never import ctxctl (the asymmetric requirement that matters); one-directional ctxctl→ctx coupling is acceptable for disposable maintainer tooling. A go.work wires the workspace; a guard test asserts cmd/ctx never imports internal/ctxctl.
+- ctxctl is PATH-installed alongside ctx (build to dist/, install to /usr/local/bin/ctxctl) for clean repo roots and one binary across all worktrees, mirroring ctx's install pattern; the local hook calls ctxctl from PATH.
 
 ---
 
@@ -350,31 +260,12 @@ executor-portable.
 
 **Consolidated from**: 6 entries (2026-05-10 to 2026-05-16)
 
-- Lift the sibling clean-room project's battle-tested editorial pipeline into
-  ctx as v1, paired with handover: it is field-tested under production use and
-  your-project is already paying the workaround tax (N=1 lived validation); lift
-  the whole shape with a non-colliding rename, not hedge-and-defer.
-- Mandate git as an architectural precondition: persistent-memory is dishonest
-  without an undo layer (git reflog); refuse-on-no-git rather than auto-git-init
-  (ctx never modifies the filesystem outside .context/); eliminates commit:none
-  dead-code branches. Breaking change in next minor.
-- KB ontology is pipeline-only-writer; no /ctx-kb-decide skill: in a KB you
-  don't decide, you increase confidence — even NL assertions are
-  evidence-capture events, not decision-capture. KB surface stays small (4 mode
-  skills + ctx kb note); canonical capture skills unchanged.
-- Phase KB ships handover + editorial paired, not split: the closeout/fold
-  mechanism is the integration point; shipping paired stresses the fold on day
-  one rather than retrofitting it.
-- Editorial constitution lives at .context/ingest/KB-RULES.md, not
-  CONSTITUTION.md: lifts the sibling project's resolved naming-collision (their
-  10-INGEST_RULES.md rename) so ctx CONSTITUTION.md keeps its singular meaning;
-  same discipline carries to domain-decisions.md vs DECISIONS.md.
-- Phase KB lifts the *current* upstream pipeline shape (pass-mode contract,
-  completion circuit breaker, source-coverage state-machine ledger,
-  topic-adjacency pre-flight, cold-reader rubric, folder-shaped topics from day
-  one, CLI-as-scaffold-authority), superseding the brief's 4-phase model —
-  lifting the older shape would re-fight wounds the upstream author already
-  healed.
+- Lift the sibling clean-room project's battle-tested editorial pipeline into ctx as v1, paired with handover: it is field-tested under production use and your-project is already paying the workaround tax (N=1 lived validation); lift the whole shape with a non-colliding rename, not hedge-and-defer.
+- Mandate git as an architectural precondition: persistent-memory is dishonest without an undo layer (git reflog); refuse-on-no-git rather than auto-git-init (ctx never modifies the filesystem outside .context/); eliminates commit:none dead-code branches. Breaking change in next minor.
+- KB ontology is pipeline-only-writer; no /ctx-kb-decide skill: in a KB you don't decide, you increase confidence — even NL assertions are evidence-capture events, not decision-capture. KB surface stays small (4 mode skills + ctx kb note); canonical capture skills unchanged.
+- Phase KB ships handover + editorial paired, not split: the closeout/fold mechanism is the integration point; shipping paired stresses the fold on day one rather than retrofitting it.
+- Editorial constitution lives at .context/ingest/KB-RULES.md, not CONSTITUTION.md: lifts the sibling project's resolved naming-collision (their 10-INGEST_RULES.md rename) so ctx CONSTITUTION.md keeps its singular meaning; same discipline carries to domain-decisions.md vs DECISIONS.md.
+- Phase KB lifts the *current* upstream pipeline shape (pass-mode contract, completion circuit breaker, source-coverage state-machine ledger, topic-adjacency pre-flight, cold-reader rubric, folder-shaped topics from day one, CLI-as-scaffold-authority), superseding the brief's 4-phase model — lifting the older shape would re-fight wounds the upstream author already healed.
 
 ---
 
@@ -382,30 +273,12 @@ executor-portable.
 
 **Consolidated from**: 6 entries (2026-03-06 to 2026-05-23)
 
-- Peer MCP model for external tools (GitNexus, context-mode): side-by-side
-  servers each queried independently by the agent, chosen over orchestrator/hub
-  models to respect ctx's markdown-on-filesystem invariant and avoid
-  coupling/plugin registries.
-- Skills stay CLI-based; MCP Prompts are the protocol equivalent: CLI is always
-  available (PATH prereq), MCP is optional config, hooks are always CLI — two
-  access patterns in one tool is gratuitous complexity.
-- Recommend companion RAGs as peer MCP servers, not bridged through ctx: MCP is
-  the composition layer; ctx is context, RAGs are intelligence — no bridging,
-  plugin system, or schema abstraction.
-- Companion tools documented as optional MCP enhancements with a runtime check
-  (/ctx-remember smoke-tests MCPs at session start; companion_check:false
-  suppresses) so users learn what enhances their workflow without being forced
-  to install.
-- MCP gateway not worth the coupling cost: a gateway would make ctx own
-  install/uninstall/version/error-surface for tools it doesn't ship
-  (bidirectional ownership coupling); composition is already MCP's job and the
-  skills already work peer-to-peer. The pluggable-graph-tool task was skipped as
-  a direct consequence (pluggability without ownership is incoherent).
-- Skill body text uses capability-first language with canonical tools as
-  examples; install-guide docs name canonical implementations directly
-  (newcomers need a recommendation); allowed-tools frontmatter stays
-  MCP-specific (genericizing to mcp__* is a permission expansion). Pure text
-  rewrite, no new abstraction layer.
+- Peer MCP model for external tools (GitNexus, context-mode): side-by-side servers each queried independently by the agent, chosen over orchestrator/hub models to respect ctx's markdown-on-filesystem invariant and avoid coupling/plugin registries.
+- Skills stay CLI-based; MCP Prompts are the protocol equivalent: CLI is always available (PATH prereq), MCP is optional config, hooks are always CLI — two access patterns in one tool is gratuitous complexity.
+- Recommend companion RAGs as peer MCP servers, not bridged through ctx: MCP is the composition layer; ctx is context, RAGs are intelligence — no bridging, plugin system, or schema abstraction.
+- Companion tools documented as optional MCP enhancements with a runtime check (/ctx-remember smoke-tests MCPs at session start; companion_check:false suppresses) so users learn what enhances their workflow without being forced to install.
+- MCP gateway not worth the coupling cost: a gateway would make ctx own install/uninstall/version/error-surface for tools it doesn't ship (bidirectional ownership coupling); composition is already MCP's job and the skills already work peer-to-peer. The pluggable-graph-tool task was skipped as a direct consequence (pluggability without ownership is incoherent).
+- Skill body text uses capability-first language with canonical tools as examples; install-guide docs name canonical implementations directly (newcomers need a recommendation); allowed-tools frontmatter stays MCP-specific (genericizing to mcp__* is a permission expansion). Pure text rewrite, no new abstraction layer.
 
 ---
 
@@ -413,26 +286,11 @@ executor-portable.
 
 **Consolidated from**: 5 entries (2026-03-14 to 2026-05-23)
 
-- Session prefixes are parser vocabulary, not i18n text: header-recognition
-  patterns move to .ctxrc session_prefixes (default Session:), separating
-  content recognition from interface language so users parse multilingual
-  session files without code changes.
-- Classify rules are user-configurable via .ctxrc (classify_rules overrides
-  config/memory defaults) — same pattern as session_prefixes, for
-  non-English/specialized domains.
-- Spec signal words and the nudge threshold (spec_signal_words,
-  spec_nudge_min_len) are .ctxrc-configurable — signal words are language- and
-  project-dependent.
-- Keep i18n.Fold strict (Unicode case-fold, İ≠i, for identifier
-  dedup/parsing/security comparison); add i18n.MatchKey (Fold + NFKD + strip
-  combining marks) as a separate diacritic-insensitive primitive for matching
-  user input against vocabulary lists. Two explicit-contract primitives beat one
-  conflated primitive or an options flag.
-- Placeholder overrides use EXTEND, not REPLACE, semantics (diverging from
-  SessionPrefixes' REPLACE): the dominant bilingual EN+TR case needs both
-  default and added placeholders rejected simultaneously; REPLACE would silently
-  lose baseline coverage. Opt-in placeholders_replace:true reserved if REPLACE
-  is later wanted.
+- Session prefixes are parser vocabulary, not i18n text: header-recognition patterns move to .ctxrc session_prefixes (default Session:), separating content recognition from interface language so users parse multilingual session files without code changes.
+- Classify rules are user-configurable via .ctxrc (classify_rules overrides config/memory defaults) — same pattern as session_prefixes, for non-English/specialized domains.
+- Spec signal words and the nudge threshold (spec_signal_words, spec_nudge_min_len) are .ctxrc-configurable — signal words are language- and project-dependent.
+- Keep i18n.Fold strict (Unicode case-fold, İ≠i, for identifier dedup/parsing/security comparison); add i18n.MatchKey (Fold + NFKD + strip combining marks) as a separate diacritic-insensitive primitive for matching user input against vocabulary lists. Two explicit-contract primitives beat one conflated primitive or an options flag.
+- Placeholder overrides use EXTEND, not REPLACE, semantics (diverging from SessionPrefixes' REPLACE): the dominant bilingual EN+TR case needs both default and added placeholders rejected simultaneously; REPLACE would silently lose baseline coverage. Opt-in placeholders_replace:true reserved if REPLACE is later wanted.
 
 ---
 
@@ -440,32 +298,12 @@ executor-portable.
 
 **Consolidated from**: 7 entries (2026-04-01 to 2026-05-22)
 
-- Embedded foreign-language assets (TS/Bash/PowerShell/YAML) under
-  internal/assets/ are intentional, not a smell: every file is //go:embed'd into
-  the ctx binary and written at ctx setup; internal/ is about import privacy,
-  not source language. The fix for the legibility gap was a contract README, not
-  relocation (//go:embed can't reference ../).
-- assets/hooks/ split into assets/integrations/ (tool-integration assets:
-  Copilot instructions, AGENTS.md, CLI scripts/skills) + assets/hooks/messages/
-  (hook-system templates) — integration assets are not hooks.
-- Embedded harnesses (//go:embed'd, shipped via ctx setup) and
-  separately-published harnesses (e.g. VS Code extension → marketplace, own
-  cadence) are first-class peers with distinct CI/release pipelines; a new
-  harness declares which pattern it follows before placing files.
-- OpenCode plugin ships without a tool.execute.before hook: the natural fit
-  (block-dangerous-commands) isn't a ctx Go subcommand and shimming would brick
-  the editor (Cobra exit-1 read as {blocked:true}) on installs without the
-  Claude wrapper. This omission is permanent — block-dangerous-commands will
-  not be promoted to a ctx Go subcommand; the perpetually-pending re-add task is
-  closed.
-- Under cwd-anchored, the OpenCode plugin's agent shell tool can't be anchored
-  to project root (the @opencode-ai/plugin SDK exposes only env, not cwd on
-  shell.env); drop the shell.env handler and document launch-from-root.
-  Plugin-internal ceremony calls stay anchored; the cwd-anchored error message
-  is self-fixing.
-- Editor-integration plugins must filter post-commit to actual git commit
-  invocations (regex on the extracted command), not fire on every shell call —
-  firing on noise trains users to ignore nudges.
+- Embedded foreign-language assets (TS/Bash/PowerShell/YAML) under internal/assets/ are intentional, not a smell: every file is //go:embed'd into the ctx binary and written at ctx setup; internal/ is about import privacy, not source language. The fix for the legibility gap was a contract README, not relocation (//go:embed can't reference ../).
+- assets/hooks/ split into assets/integrations/ (tool-integration assets: Copilot instructions, AGENTS.md, CLI scripts/skills) + assets/hooks/messages/ (hook-system templates) — integration assets are not hooks.
+- Embedded harnesses (//go:embed'd, shipped via ctx setup) and separately-published harnesses (e.g. VS Code extension → marketplace, own cadence) are first-class peers with distinct CI/release pipelines; a new harness declares which pattern it follows before placing files.
+- OpenCode plugin ships without a tool.execute.before hook: the natural fit (block-dangerous-commands) isn't a ctx Go subcommand and shimming would brick the editor (Cobra exit-1 read as {blocked:true}) on installs without the Claude wrapper. This omission is permanent — block-dangerous-commands will not be promoted to a ctx Go subcommand; the perpetually-pending re-add task is closed.
+- Under cwd-anchored, the OpenCode plugin's agent shell tool can't be anchored to project root (the @opencode-ai/plugin SDK exposes only env, not cwd on shell.env); drop the shell.env handler and document launch-from-root. Plugin-internal ceremony calls stay anchored; the cwd-anchored error message is self-fixing.
+- Editor-integration plugins must filter post-commit to actual git commit invocations (regex on the extracted command), not fire on every shell call — firing on noise trains users to ignore nudges.
 
 ---
 
@@ -473,35 +311,13 @@ executor-portable.
 
 **Consolidated from**: 8 entries (2026-02-26 to 2026-05-08)
 
-- Context injection v2: extract ~600 lines of diagrams out of FileReadOrder (53%
-  token drop); auto-inject content via additionalContext (soft directives hit a
-  ~75-85% compliance ceiling); imperative framing with an unconditional
-  compliance checkpoint, verbatim relay as fallback. Inject
-  CONSTITUTION/CONVENTIONS/ARCHITECTURE/PLAYBOOK verbatim, DECISIONS/LEARNINGS
-  index-only, TASKS mention-only (~7,700 tokens).
-- Context-load-gate injects only CONSTITUTION + AGENT_PLAYBOOK_GATE (~2k
-  tokens), not the full ReadOrder: hard rules must be present pre-action;
-  everything else is pulled on-demand. AGENT_PLAYBOOK_GATE.md must stay in sync
-  with AGENT_PLAYBOOK.md.
-- .context/state/ is the gitignored, project-scoped home for ephemeral runtime
-  state (following the .context/logs/ precedent); all session state (cooldown
-  tombstones, pause/throttle markers) consolidated there from /tmp, dropping the
-  cleanup-tmp SessionEnd hook (4 hook events → 3).
-- Gate mkdir inside state.Dir() rather than per-caller so "no .context/state/ in
-  uninitialized projects" is structurally enforced; state.Dir() returns
-  ErrNotInitialized (hook callers absorb silently, interactive callers surface a
-  path-bearing message).
-- Tighten state.Dir / rc.ContextDir to (string, error) with sentinel
-  ErrDirNotDeclared: makes the empty-path case unrepresentable in a "looks fine"
-  branch, closing the filepath.Join("", rel) trap that wrote state into CWD.
-- Hook/notification design: prefer toning down docs claims over adding hooks
-  (fatigue from 9 UserPromptSubmit hooks); hook output must be structured JSON
-  (additionalContext), not plain text; dropped prompt-coach hook (zero useful
-  tips, invisible channel); de-emphasized /ctx-journal-normalize (expensive,
-  nondeterministic).
-- Hook log rotation is size-based with one previous generation (current + .1,
-  ~2MB cap), matching the eventlog pattern — O(1) size check, diagnostic logs
-  don't need deep history.
+- Context injection v2: extract ~600 lines of diagrams out of FileReadOrder (53% token drop); auto-inject content via additionalContext (soft directives hit a ~75-85% compliance ceiling); imperative framing with an unconditional compliance checkpoint, verbatim relay as fallback. Inject CONSTITUTION/CONVENTIONS/ARCHITECTURE/PLAYBOOK verbatim, DECISIONS/LEARNINGS index-only, TASKS mention-only (~7,700 tokens).
+- Context-load-gate injects only CONSTITUTION + AGENT_PLAYBOOK_GATE (~2k tokens), not the full ReadOrder: hard rules must be present pre-action; everything else is pulled on-demand. AGENT_PLAYBOOK_GATE.md must stay in sync with AGENT_PLAYBOOK.md.
+- .context/state/ is the gitignored, project-scoped home for ephemeral runtime state (following the .context/logs/ precedent); all session state (cooldown tombstones, pause/throttle markers) consolidated there from /tmp, dropping the cleanup-tmp SessionEnd hook (4 hook events → 3).
+- Gate mkdir inside state.Dir() rather than per-caller so "no .context/state/ in uninitialized projects" is structurally enforced; state.Dir() returns ErrNotInitialized (hook callers absorb silently, interactive callers surface a path-bearing message).
+- Tighten state.Dir / rc.ContextDir to (string, error) with sentinel ErrDirNotDeclared: makes the empty-path case unrepresentable in a "looks fine" branch, closing the filepath.Join("", rel) trap that wrote state into CWD.
+- Hook/notification design: prefer toning down docs claims over adding hooks (fatigue from 9 UserPromptSubmit hooks); hook output must be structured JSON (additionalContext), not plain text; dropped prompt-coach hook (zero useful tips, invisible channel); de-emphasized /ctx-journal-normalize (expensive, nondeterministic).
+- Hook log rotation is size-based with one previous generation (current + .1, ~2MB cap), matching the eventlog pattern — O(1) size check, diagnostic logs don't need deep history.
 
 ---
 
@@ -509,53 +325,13 @@ executor-portable.
 
 **Status**: Accepted
 
-**Context**: We explored whether ctx should grow a scheduled, background 'dream'
-(a sleep-time memory process) and how it should relate to canonical memory. Felt
-pain: the author's ideas/ folder is too overwhelming to triage, and canonical
-files bloat over time (109 decisions, 151 learnings, 154 unimported sessions).
-The risk to avoid: a background LLM job autonomously rewriting authoritative
-memory and silently corrupting it (the research shows continuous LLM
-consolidation is lossy and non-monotonic). Full debate:
-.context/briefs/20260606T203414Z-ctx-dream-disciplined-consolidator.md
-
-**Decision**: ctx-dream: standalone proposing memory consolidator (Option B),
-human-gated via serendipity
-
-**Rationale**: Chose a NEW, standalone, PROPOSING consolidator (Option B): it
-writes only to its own sidecar + proposals queue + ledger + per-dream archive,
-never autonomously to the five canonical files; a human 'serendipity' review
-session is the sole bridge (accept/reject/amend) into canonical. One skill, two
-modes: discipline (default; grounded, structured, provenanced proposals) and
-creative/exploration (a safe relaxation: resurface + chance, reader-only).
-Principle: decouple the cognition, reuse the plumbing (own the consolidation
-logic; reuse import/enrich/kb-ingest via the enriched-journal data contract).
-Standalone so mechanics evolve independently and changes to existing curation
-skills can't break it, and for creative freedom (don't assume existing verbs
-suffice). Discipline-first because it is the hard load-bearing substrate and
-creative is a strict, safer relaxation of it. Grounded in
-ideas/ctx-dreams/research: Auto-Dreamer (2605.20616) for the architecture,
-'Useful Memories Become Faulty When Continuously Updated by LLMs' (2605.12978)
-for the threat model, and the deep-research eval cluster for the finding that a
-single agreeable LLM is not an adversarial gate (it silently repairs the missing
-justification), which is why the gate must be human. Rejected: Option A (dream
-owns a parallel canonical store, which does not fix bloat and creates two
-divergent substrates); autonomous mutation / auto-approve (violates 'each memory
-entry needs dedicated human attention'); pure-garden-only (under-serves
-engineering's need for grounding and actionability); coupling to existing
-skills' internals; garden-first build order.
-
-**Consequence**: Positive: nothing autonomous touches canonical, so the system
-is reversible by construction; the dream's mechanics can evolve freely; v1
-(disciplined ideas/ triage, validated via a ctx-remind-nagged ~15-minute review
-round) is low-stakes and validates the mechanism and author engagement cheaply.
-Negative / trade-off: no human serendipity session = no consolidation, so the
-dream's entire value is gated behind human review cadence, and the author
-historically under-runs curation; mitigated only by ctx-remind nags + targeting
-felt pain (ideas/) + a pleasure-not-chore framing. Validation of the full
-product thesis (disciplined consolidation of canonical memory for engineering
-teams) is deferred to a later test on a project where bloat actually bites. Spec
-work proceeds via /ctx-spec --brief on the brief above; key mechanics remain
-open (executor, proposal schema, ledger schema, .context/ layout).
+**Context**: We explored whether ctx should grow a scheduled, background 'dream' (a sleep-time memory process) and how it should relate to canonical memory. Felt pain: the author's ideas/ folder is too overwhelming to triage, and canonical files bloat over time (109 decisions, 151 learnings, 154 unimported sessions). The risk to avoid: a background LLM job autonomously rewriting authoritative memory and silently corrupting it (the research shows continuous LLM consolidation is lossy and non-monotonic). Full debate: .context/briefs/20260606T203414Z-ctx-dream-disciplined-consolidator.md
+
+**Decision**: ctx-dream: standalone proposing memory consolidator (Option B), human-gated via serendipity
+
+**Rationale**: Chose a NEW, standalone, PROPOSING consolidator (Option B): it writes only to its own sidecar + proposals queue + ledger + per-dream archive, never autonomously to the five canonical files; a human 'serendipity' review session is the sole bridge (accept/reject/amend) into canonical. One skill, two modes: discipline (default; grounded, structured, provenanced proposals) and creative/exploration (a safe relaxation: resurface + chance, reader-only). Principle: decouple the cognition, reuse the plumbing (own the consolidation logic; reuse import/enrich/kb-ingest via the enriched-journal data contract). Standalone so mechanics evolve independently and changes to existing curation skills can't break it, and for creative freedom (don't assume existing verbs suffice). Discipline-first because it is the hard load-bearing substrate and creative is a strict, safer relaxation of it. Grounded in ideas/ctx-dreams/research: Auto-Dreamer (2605.20616) for the architecture, 'Useful Memories Become Faulty When Continuously Updated by LLMs' (2605.12978) for the threat model, and the deep-research eval cluster for the finding that a single agreeable LLM is not an adversarial gate (it silently repairs the missing justification), which is why the gate must be human. Rejected: Option A (dream owns a parallel canonical store, which does not fix bloat and creates two divergent substrates); autonomous mutation / auto-approve (violates 'each memory entry needs dedicated human attention'); pure-garden-only (under-serves engineering's need for grounding and actionability); coupling to existing skills' internals; garden-first build order.
+
+**Consequence**: Positive: nothing autonomous touches canonical, so the system is reversible by construction; the dream's mechanics can evolve freely; v1 (disciplined ideas/ triage, validated via a ctx-remind-nagged ~15-minute review round) is low-stakes and validates the mechanism and author engagement cheaply. Negative / trade-off: no human serendipity session = no consolidation, so the dream's entire value is gated behind human review cadence, and the author historically under-runs curation; mitigated only by ctx-remind nags + targeting felt pain (ideas/) + a pleasure-not-chore framing. Validation of the full product thesis (disciplined consolidation of canonical memory for engineering teams) is deferred to a later test on a project where bloat actually bites. Spec work proceeds via /ctx-spec --brief on the brief above; key mechanics remain open (executor, proposal schema, ledger schema, .context/ layout).
 
 ---
 
@@ -591,21 +367,13 @@ open (executor, proposal schema, ledger schema, .context/ layout).
 
 **Status**: Accepted
 
-**Context**: The CLI-FIX spec specified the literal flag --json , but
---json is already a bool output-format flag across the CLI (ctx
-status/drift/doctor/bootstrap --json all mean 'emit machine-readable output').
+**Context**: The CLI-FIX spec specified the literal flag --json , but --json is already a bool output-format flag across the CLI (ctx status/drift/doctor/bootstrap --json all mean 'emit machine-readable output').
 
 **Decision**: Name the add JSON-ingest flag --json-file, not --json
 
-**Rationale**: Overloading --json as a string input-path on the add commands
-would break that cross-command convention and confuse muscle memory. --json-file
-is unambiguous, parallels the existing --file/-f source flag, and leaves -j
-free. Pushed back on the spec's literal wording rather than satisfice.
+**Rationale**: Overloading --json as a string input-path on the add commands would break that cross-command convention and confuse muscle memory. --json-file is unambiguous, parallels the existing --file/-f source flag, and leaves -j free. Pushed back on the spec's literal wording rather than satisfice.
 
-**Consequence**: The add commands intentionally diverge from the spec's literal
---json; the spec was updated to reflect --json-file. Any future JSON-input flag
-elsewhere should follow the --json-file naming, reserving --json for bool
-output.
+**Consequence**: The add commands intentionally diverge from the spec's literal --json; the spec was updated to reflect --json-file. Any future JSON-input flag elsewhere should follow the --json-file naming, reserving --json for bool output.
 
 ---
 
@@ -613,27 +381,13 @@ output.
 
 **Status**: Accepted
 
-**Context**: `check-resource` alerted DANGER at swap-used ≥ 75% / memory-used
-≥ 90% — pure occupancy. macOS swap is sticky (never recedes);
-post-hibernation swap stays >75% with idle RAM, producing false "wrap up the
-session" DANGER at session start. Memory occupancy on macOS includes reclaimable
-cache — also a poor pressure proxy.
+**Context**: `check-resource` alerted DANGER at swap-used ≥ 75% / memory-used ≥ 90% — pure occupancy. macOS swap is sticky (never recedes); post-hibernation swap stays >75% with idle RAM, producing false "wrap up the session" DANGER at session start. Memory occupancy on macOS includes reclaimable cache — also a poor pressure proxy.
 
-**Decision**: Memory pressure detection uses OS-native signals (macOS pressure
-level + Linux PSI), not occupancy
+**Decision**: Memory pressure detection uses OS-native signals (macOS pressure level + Linux PSI), not occupancy
 
-**Rationale**: Occupancy is a level; pressure is a derivative. Only the kernel's
-derivative reflects current struggle. macOS: `sysctl
-kern.memorystatus_vm_pressure_level` (1/2/4 → OK/Warning/Danger). Linux:
-`/proc/pressure/memory` (PSI) `some.avg10 ≥ 10.0` → warn, `full.avg10 ≥
-10.0` → danger. Windows: filed as an exploratory task; unsupported for now
-("other" platform falls through to `PressureSupported=false`, no alert).
+**Rationale**: Occupancy is a level; pressure is a derivative. Only the kernel's derivative reflects current struggle. macOS: `sysctl kern.memorystatus_vm_pressure_level` (1/2/4 → OK/Warning/Danger). Linux: `/proc/pressure/memory` (PSI) `some.avg10 ≥ 10.0` → warn, `full.avg10 ≥ 10.0` → danger. Windows: filed as an exploratory task; unsupported for now ("other" platform falls through to `PressureSupported=false`, no alert).
 
-**Consequence**: `MemInfo` gains `Pressure` + `PressureSupported`;
-`threshold.go` drops both occupancy `byteCheck`s and emits a single pressure
-alert. Doctor swap row removed (no longer a health signal); occupancy fields
-retained for `ctx stats` display. PSI 10.0 defaults named in `config/stats` —
-retunable in one place. `make lint` 0 issues, `make test` ok on the change.
+**Consequence**: `MemInfo` gains `Pressure` + `PressureSupported`; `threshold.go` drops both occupancy `byteCheck`s and emits a single pressure alert. Doctor swap row removed (no longer a health signal); occupancy fields retained for `ctx stats` display. PSI 10.0 defaults named in `config/stats` — retunable in one place. `make lint` 0 issues, `make test` ok on the change.
 
 ---
 
@@ -641,28 +395,13 @@ retunable in one place. `make lint` 0 issues, `make test` ok on the change.
 
 **Status**: Accepted
 
-**Context**: Adding a safety net for accidental `ctx pad rm` (and any other
-destructive pad mutation) required choosing where to insert the snapshot logic:
-per-subcommand (in each cmd//run.go), or at the persistence choke point
-(store.WriteEntriesWithIDs).
+**Context**: Adding a safety net for accidental `ctx pad rm` (and any other destructive pad mutation) required choosing where to insert the snapshot logic: per-subcommand (in each cmd//run.go), or at the persistence choke point (store.WriteEntriesWithIDs).
 
 **Decision**: Pad snapshot-on-mutate at the store.WriteEntries choke point
 
-**Rationale**: store.WriteEntriesWithIDs is invoked by every mutating pad
-subcommand (add/edit/mv/rm/merge/normalize/resolve/tag and undo itself);
-instrumenting it once gives universal coverage with one site of truth.
-Per-subcommand instrumentation would need maintenance every time a new pad
-mutation lands and is easy to forget. The snapshot itself is a byte-for-byte
-copy of the existing pad blob (no re-encryption), so plaintext and encrypted
-modes use identical logic; the existing ciphertext IS the snapshot.
+**Rationale**: store.WriteEntriesWithIDs is invoked by every mutating pad subcommand (add/edit/mv/rm/merge/normalize/resolve/tag and undo itself); instrumenting it once gives universal coverage with one site of truth. Per-subcommand instrumentation would need maintenance every time a new pad mutation lands and is easy to forget. The snapshot itself is a byte-for-byte copy of the existing pad blob (no re-encryption), so plaintext and encrypted modes use identical logic; the existing ciphertext IS the snapshot.
 
-**Consequence**: All future pad mutations get the safety net automatically
-without per-command wiring. The op label for the snapshot filename is derived
-from cmd.Name() at the call site, so the cmd parameter that already flowed in
-for diagnostic output now carries semantic weight too. New constraint: any
-future code path that bypasses WriteEntriesWithIDs to mutate the pad will
-silently bypass the safety net — a guardrail test could enforce this if/when
-that risk materializes.
+**Consequence**: All future pad mutations get the safety net automatically without per-command wiring. The op label for the snapshot filename is derived from cmd.Name() at the call site, so the cmd parameter that already flowed in for diagnostic output now carries semantic weight too. New constraint: any future code path that bypasses WriteEntriesWithIDs to mutate the pad will silently bypass the safety net — a guardrail test could enforce this if/when that risk materializes.
 
 ---
 
@@ -670,23 +409,13 @@ that risk materializes.
 
 **Status**: Accepted
 
-**Context**: Per-session, operator-specific artifacts that grow without bound
-and can leak host/internal identifiers into public
-mirrors when the project's .context/ is committed.
+**Context**: Per-session, operator-specific artifacts that grow without bound and can leak host/internal identifiers (ari, asgard, broadcom-class) into public mirrors when the project's .context/ is committed.
 
 **Decision**: Gitignore .context/handovers/; track only .gitkeep
 
-**Rationale**: Aligns with the existing per-personal-state gitignore family
-(journal, memory, state, logs, reminders.json, scratchpad.enc); the directory's
-.gitkeep keeps the read-side missing-dir gate passing on fresh clones; the rest
-of the closeout-fold pipeline already lives in .context/archive/closeouts/ which
-IS tracked.
+**Rationale**: Aligns with the existing per-personal-state gitignore family (journal, memory, state, logs, reminders.json, scratchpad.enc); the directory's .gitkeep keeps the read-side missing-dir gate passing on fresh clones; the rest of the closeout-fold pipeline already lives in .context/archive/closeouts/ which IS tracked.
 
-**Consequence**: ctx init template (internal/config/file/ignore.go) added
-.context/handovers/* and !.context/handovers/.gitkeep; existing tracked
-handovers untracked via git rm --cached but kept on disk; the 'handover is the
-sole authoritative recall artifact' phrasing in KB-RULES.md still holds — it's
-local-machine authoritative.
+**Consequence**: ctx init template (internal/config/file/ignore.go) added .context/handovers/* and !.context/handovers/.gitkeep; existing tracked handovers untracked via git rm --cached but kept on disk; the 'handover is the sole authoritative recall artifact' phrasing in KB-RULES.md still holds — it's local-machine authoritative.
 
 ---
 
@@ -701,8 +430,8 @@ already handles cross-machine knowledge persistence.
 **Decision**: Deprecate and remove ctx backup
 
 **Rationale**: Hub handles persistence, backup is env-specific, wrong layer for
-ctx to own. No external users depend on it. An internal mirror issue and the
-GVFS Linux-only dependency add maintenance burden.
+ctx to own. No external users depend on it. Broadcom mirror issue and GVFS
+Linux-only dependency add maintenance burden.
 
 **Consequence**: Need backup-strategy runbook before removal. Maintainer must
 set up replacement cron job. About 60 files to remove across CLI, config, hooks,
@@ -1647,4 +1376,3 @@ inherits it, and cleanup is automatic at test end. One line replaces the helper.
 to maintain. Pattern reusable for other subprocess tests.
 
 ---
-
diff --git a/.context/LEARNINGS.md b/.context/LEARNINGS.md
index 18d2602af..5ce72a475 100644
--- a/.context/LEARNINGS.md
+++ b/.context/LEARNINGS.md
@@ -17,8 +17,6 @@ DO NOT UPDATE FOR:
 
 | Date | Learning |
 |----|--------|
-| 2026-07-04 | Typed JSON round-trips silently drop user-owned keys |
-| 2026-07-03 | New Claude model families silently fall to the 200k default in ModelContextWindow |
 | 2026-06-07 | Pin an on-disk contract before splitting work across parallel agents |
 | 2026-06-07 | site/ is tracked build output — rebuild and bundle it with doc commits |
 | 2026-06-07 | ctx-dream is headless-first; invoking /ctx-dream interactively is debugging, not the UX |
@@ -109,79 +107,33 @@ DO NOT UPDATE FOR:
 
 ---
 
-## [2026-07-04-152957] Typed JSON round-trips silently drop user-owned keys
-
-**Context**: The init permissions merge read settings.local.json into a typed struct and re-marshaled it, so every key ctx does not model (env, a user's statusLine) vanished on re-init
-
-**Lesson**: A typed read-modify-write of a file users also edit by hand is silent data loss; unknown fields do not survive encoding/json round-trips
-
-**Application**: Mutate shared JSON via raw-map surgery (map[string]json.RawMessage), rewriting only the keys ctx owns; see internal/cli/initialize/core/merge/settings.go
-
----
-
-## [2026-07-03-182238] New Claude model families silently fall to the 200k default in ModelContextWindow
-
-**Context**: claude-fable-5 sessions warned '104 percent full' while the 1M window was 79 percent free; ModelContextWindow only recognized the [1m] suffix and the opus substring
-
-**Lesson**: Unmapped model families inherit rc.DefaultContextWindow (200k), and every EffectiveContextWindow consumer (check-context-size hook, heartbeat, nudges, provenance) misreports against the wrong window
-
-**Application**: At every model launch: add the family substring to internal/config/claude, extend TestModelContextWindow, and sanity-check against a live session's /context output before trusting hook percentages
-
----
-
 ## [2026-06-07-162840] Pin an on-disk contract before splitting work across parallel agents
 
-**Context**: The ctx-dream skill (proposal writer) and the ctx dream CLI
-(proposal reader) were built by parallel tracks; each independently invented the
-proposals layout — one per-file proposals/.json, the other a single
-proposals.json array — requiring reconciliation at integration.
+**Context**: The ctx-dream skill (proposal writer) and the ctx dream CLI (proposal reader) were built by parallel tracks; each independently invented the proposals layout — one per-file proposals/.json, the other a single proposals.json array — requiring reconciliation at integration.
 
-**Lesson**: When parallel agents share a serialized artifact (a file path +
-schema), the exact on-disk shape must be fixed in BOTH prompts up front. 'Each
-track invents it' guarantees a mismatch that only surfaces at integration.
+**Lesson**: When parallel agents share a serialized artifact (a file path + schema), the exact on-disk shape must be fixed in BOTH prompts up front. 'Each track invents it' guarantees a mismatch that only surfaces at integration.
 
-**Application**: Before fanning out producer/consumer work to parallel agents,
-write the precise file path + JSON schema into both agents' specs as a fixed
-contract, and reconcile/verify it first thing at integration.
+**Application**: Before fanning out producer/consumer work to parallel agents, write the precise file path + JSON schema into both agents' specs as a fixed contract, and reconcile/verify it first thing at integration.
 
 ---
 
 ## [2026-06-07-162840] site/ is tracked build output — rebuild and bundle it with doc commits
 
-**Context**: A docs change (docs/cli/dream.md, etc.) produced a surprise
-189-file site/ drift mid-session; site/ is tracked (zensical build via 'make
-site'), not gitignored.
+**Context**: A docs change (docs/cli/dream.md, etc.) produced a surprise 189-file site/ drift mid-session; site/ is tracked (zensical build via 'make site'), not gitignored.
 
-**Lesson**: Any change under docs/ requires regenerating site/ with 'make site'
-and committing the rebuilt site/ in the SAME commit (cf. f0f100a0, which bundled
-its site rebuild). Otherwise the built output silently drifts and shows up as a
-large untracked/modified set later.
+**Lesson**: Any change under docs/ requires regenerating site/ with 'make site' and committing the rebuilt site/ in the SAME commit (cf. f0f100a0, which bundled its site rebuild). Otherwise the built output silently drifts and shows up as a large untracked/modified set later.
 
-**Application**: After editing anything under docs/, run 'make site' and 'git
-add site/' and include it in the doc commit. Don't treat site/ as ephemeral —
-it's versioned.
+**Application**: After editing anything under docs/, run 'make site' and 'git add site/' and include it in the doc commit. Don't treat site/ as ephemeral — it's versioned.
 
 ---
 
 ## [2026-06-07-142015] ctx-dream is headless-first; invoking /ctx-dream interactively is debugging, not the UX
 
-**Context**: An end user ran /ctx-dream in their foreground terminal session and
-watched the agent hand-execute the pass (grep/cat/hash/write JSON). Their words:
-'I'm not dreaming but viewing a dream being debugged.'
+**Context**: An end user ran /ctx-dream in their foreground terminal session and watched the agent hand-execute the pass (grep/cat/hash/write JSON). Their words: 'I'm not dreaming but viewing a dream being debugged.'
 
-**Lesson**: The dream is a sleep-time/headless product: cron 'claude -p' runs
-the pass out-of-band, then the human is nagged and reviews via /ctx-serendipity.
-The /ctx-dream SKILL is the executor's instruction set, not a user command —
-driving it interactively makes the agent perform the executor's mechanical work
-visibly, which is a debugging affordance, not the end-user experience. Exposing
-/ctx-dream as a user slash-command invites exactly this confusion.
+**Lesson**: The dream is a sleep-time/headless product: cron 'claude -p' runs the pass out-of-band, then the human is nagged and reviews via /ctx-serendipity. The /ctx-dream SKILL is the executor's instruction set, not a user command — driving it interactively makes the agent perform the executor's mechanical work visibly, which is a debugging affordance, not the end-user experience. Exposing /ctx-dream as a user slash-command invites exactly this confusion.
 
-**Application**: End-user entry points are 'ctx dream' (on-demand pass that
-prints a digest) and cron (scheduled); review is /ctx-serendipity. Do NOT have
-users invoke /ctx-dream directly. Reconsider de-listing /ctx-dream from the
-user-invocable skill set, ensure 'ctx dream' gives a clean run->digest
-experience, and wire the 'serendipity round waiting' nag so the dream->review
-loop closes without the user watching a pass.
+**Application**: End-user entry points are 'ctx dream' (on-demand pass that prints a digest) and cron (scheduled); review is /ctx-serendipity. Do NOT have users invoke /ctx-dream directly. Reconsider de-listing /ctx-dream from the user-invocable skill set, ensure 'ctx dream' gives a clean run->digest experience, and wire the 'serendipity round waiting' nag so the dream->review loop closes without the user watching a pass.
 
 ---
 
@@ -189,40 +141,12 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 6 entries (2026-06-06 to 2026-06-07)
 
-- Merit/scoring rubric
-  (relevance/frequency/recency/diversity/consolidation/richness, à la Hermes
-  "Dreaming") measures ATTENTION (what to surface first), never TRUTH; use it
-  only as a ranking signal feeding ruthless self-rejection, never as an
-  autonomous promotion threshold — pair any statistical ranking with an
-  evidence/grounding gate that decides eligibility.
-- Load-bearing invariant (Option B): dream consolidation emits PROPOSALS only; a
-  human accept/reject gate sits between the dream pass and any write to the five
-  canonical files / MEMORY.md. Autonomous canonical writes are the documented
-  rot failure mode (arXiv 2605.12978); independent designs (Hermes, OpenClaw,
-  Auto-Dreamer) re-derive the sleep-phase shape but omit the gate. When
-  evaluating any external memory-consolidation design, first check: does it
-  autonomously write canonical, or only propose? Autonomous-write is a reject.
-- A single LLM asked to critique a proposal silently repairs the missing
-  justification and approves it (ReportLogic finding) — a single agreeable LLM
-  is not an adversarial gate. Robust gating needs human or independent
-  multi-critic consensus + swap-consistency. (This says a gate must EXIST; the
-  proposes-only entry says one must sit before canonical writes; together they
-  define WHO and WHETHER.)
-- Same proposals, two consumers, two interfaces: render a terse/dispositional
-  accept-reject worklist for the agent reviewer and a substance-rich,
-  semantically-generated summary for the human (no file-hunting). Same data,
-  presentation per consumer.
-- Split agent/human work by comparative advantage: the agent is the reliable
-  gardener for mechanical/verifiable hygiene (never skips the 47th file); the
-  human owns taste/serendipity — which is WHY the human is the gate, not
-  merely a safety nicety. Design the human's surface for pleasure (substance to
-  wander), not a queue to drain.
-- Don't-leak is a third safety axis alongside don't-corrupt and
-  don't-obey-injected-instructions: a summary/backup/ledger-line of a gitignored
-  source inherits its privacy class. Keep every byproduct in gitignored
-  locations; enforce structurally with `git check-ignore` on each write target
-  (refuse tracked paths), never via prompt. A deliberate human `promote` is the
-  only sanctioned boundary crossing.
+- Merit/scoring rubric (relevance/frequency/recency/diversity/consolidation/richness, à la Hermes "Dreaming") measures ATTENTION (what to surface first), never TRUTH; use it only as a ranking signal feeding ruthless self-rejection, never as an autonomous promotion threshold — pair any statistical ranking with an evidence/grounding gate that decides eligibility.
+- Load-bearing invariant (Option B): dream consolidation emits PROPOSALS only; a human accept/reject gate sits between the dream pass and any write to the five canonical files / MEMORY.md. Autonomous canonical writes are the documented rot failure mode (arXiv 2605.12978); independent designs (Hermes, OpenClaw, Auto-Dreamer) re-derive the sleep-phase shape but omit the gate. When evaluating any external memory-consolidation design, first check: does it autonomously write canonical, or only propose? Autonomous-write is a reject.
+- A single LLM asked to critique a proposal silently repairs the missing justification and approves it (ReportLogic finding) — a single agreeable LLM is not an adversarial gate. Robust gating needs human or independent multi-critic consensus + swap-consistency. (This says a gate must EXIST; the proposes-only entry says one must sit before canonical writes; together they define WHO and WHETHER.)
+- Same proposals, two consumers, two interfaces: render a terse/dispositional accept-reject worklist for the agent reviewer and a substance-rich, semantically-generated summary for the human (no file-hunting). Same data, presentation per consumer.
+- Split agent/human work by comparative advantage: the agent is the reliable gardener for mechanical/verifiable hygiene (never skips the 47th file); the human owns taste/serendipity — which is WHY the human is the gate, not merely a safety nicety. Design the human's surface for pleasure (substance to wander), not a queue to drain.
+- Don't-leak is a third safety axis alongside don't-corrupt and don't-obey-injected-instructions: a summary/backup/ledger-line of a gitignored source inherits its privacy class. Keep every byproduct in gitignored locations; enforce structurally with `git check-ignore` on each write target (refuse tracked paths), never via prompt. A deliberate human `promote` is the only sanctioned boundary crossing.
 
 ---
 
@@ -230,45 +154,12 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 6 entries (2026-03-15 to 2026-05-30)
 
-- New exported types must live in types.go: TestTypeFileConvention permits types
-  outside types.go only in pure-type files (defs+methods, no standalone funcs)
-  or exempt packages; a file mixing structs with standalone funcs fails. Put
-  type defs in a dedicated types.go from the start.
-- internal/assets/tpl is on the magic-strings exempt list, so template-path
-  literals are sanctioned THERE — but render data passed from non-exempt
-  callers must be a typed struct (tpl.ObsidianData{...}), never map[string]any
-  with literal keys, which trips the audit at the call site.
-- Full gate catalog for a new package/CLI command (none surfaced by `go
-  build`/`golangci-lint` — run `go test ./internal/audit/
-  ./internal/compliance/`): TestNoMixedVisibility (split unexported helpers into
-  _internal.go), TestNoMagicStrings/Values (named consts in
-  internal/config/warn/ for warn formats; named const for bare ints),
-  TestDocCommentStructure (Parameters/Returns on every helper, exported or not),
-  TestNoCmdPrintOutsideWrite (route output through internal/write//),
-  TestNoNakedErrors, TestTypeFileConvention, TestCmdDirPurity (no helpers in
-  cmd/ — use core//), TestNoLiteralMdExtension (file.ExtMarkdown),
-  TestDocGoSubcommandDrift (parent doc.go lists every subcommand),
-  TestDescKeyYAMLLinkage, TestNoLiteralWhitespace (token.NewlineCRLF/LF),
-  TestRegistryCount (bump on registry.yaml additions). staticcheck QF1012 vs
-  TestNoUncheckedFmtWrite: build with fmt.Sprintf then b.WriteString.
-- naked_errors audit flags every fmt.Errorf/errors.New outside internal/err/**
-  — call-site wrapping does NOT satisfy it. Error constructors live in
-  domain-scoped internal/err// pulling format strings from
-  internal/config// or desc.Text. Pattern: `var ErrX =
-  errors.New(cfgArea.ErrMsgX)` (sentinel); `func X(args, cause) error { return
-  fmt.Errorf(cfgArea.FormatX, …) }` (wrapper). Budget ~3 files/area for any
-  new error surface.
-- Pre-emptive constants are dead exports: TestNoDeadExports is
-  symbol-graph-strict — any exported const/var/func without an internal reader
-  fails. Land constants in the same commit (or strict precursor) as their
-  caller; never scaffold config ahead of consumers. Genuine future-use goes in a
-  TASKS.md line, not a config file.
-- Dead-code detection: packages can build+test green while unreachable — check
-  bootstrap registration, not build success (e.g. internal/cli/recall/ had
-  tests, never wired). Files created by `ctx init` with no agent/hook/skill
-  reader are dead on arrival. When touching legacy compat code, first ask if the
-  legacy path has real users; if not, delete rather than improve (MigrateKeyFile
-  had 5 callers, zero users).
+- New exported types must live in types.go: TestTypeFileConvention permits types outside types.go only in pure-type files (defs+methods, no standalone funcs) or exempt packages; a file mixing structs with standalone funcs fails. Put type defs in a dedicated types.go from the start.
+- internal/assets/tpl is on the magic-strings exempt list, so template-path literals are sanctioned THERE — but render data passed from non-exempt callers must be a typed struct (tpl.ObsidianData{...}), never map[string]any with literal keys, which trips the audit at the call site.
+- Full gate catalog for a new package/CLI command (none surfaced by `go build`/`golangci-lint` — run `go test ./internal/audit/ ./internal/compliance/`): TestNoMixedVisibility (split unexported helpers into _internal.go), TestNoMagicStrings/Values (named consts in internal/config/warn/ for warn formats; named const for bare ints), TestDocCommentStructure (Parameters/Returns on every helper, exported or not), TestNoCmdPrintOutsideWrite (route output through internal/write//), TestNoNakedErrors, TestTypeFileConvention, TestCmdDirPurity (no helpers in cmd/ — use core//), TestNoLiteralMdExtension (file.ExtMarkdown), TestDocGoSubcommandDrift (parent doc.go lists every subcommand), TestDescKeyYAMLLinkage, TestNoLiteralWhitespace (token.NewlineCRLF/LF), TestRegistryCount (bump on registry.yaml additions). staticcheck QF1012 vs TestNoUncheckedFmtWrite: build with fmt.Sprintf then b.WriteString.
+- naked_errors audit flags every fmt.Errorf/errors.New outside internal/err/** — call-site wrapping does NOT satisfy it. Error constructors live in domain-scoped internal/err// pulling format strings from internal/config// or desc.Text. Pattern: `var ErrX = errors.New(cfgArea.ErrMsgX)` (sentinel); `func X(args, cause) error { return fmt.Errorf(cfgArea.FormatX, …) }` (wrapper). Budget ~3 files/area for any new error surface.
+- Pre-emptive constants are dead exports: TestNoDeadExports is symbol-graph-strict — any exported const/var/func without an internal reader fails. Land constants in the same commit (or strict precursor) as their caller; never scaffold config ahead of consumers. Genuine future-use goes in a TASKS.md line, not a config file.
+- Dead-code detection: packages can build+test green while unreachable — check bootstrap registration, not build success (e.g. internal/cli/recall/ had tests, never wired). Files created by `ctx init` with no agent/hook/skill reader are dead on arrival. When touching legacy compat code, first ask if the legacy path has real users; if not, delete rather than improve (MigrateKeyFile had 5 callers, zero users).
 
 ---
 
@@ -276,35 +167,12 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 6 entries (2026-03-06 to 2026-06-02)
 
-- os.IsNotExist does NOT unwrap — it is false on any fmt.Errorf("…%w…")
-  error; prefer errors.Is(err, os.ErrNotExist). But errors.Is only holds if the
-  wrap carries %w at runtime, and a wrap whose format string comes from the
-  text/i18n registry only carries %w when that registry is initialized (so it
-  behaves differently in prod vs a bare test binary; go vet can't see it). To
-  detect file absence reliably, stat directly: os.Stat returns an unwrapped
-  *fs.PathError so errors.Is(statErr, os.ErrNotExist) is dependable everywhere.
-- An error-discard catalogue (grep + name/regex classification) is an inventory
-  of candidates, not findings. Name-inference produces false positives (a
-  discarded bool mistaken for an error; a value type that can't nil-deref; an
-  already-failed cleanup-close path). Read the callee signature and enclosing
-  control flow before assigning return-error vs logWarn vs annotate.
-- Canonical sentinel shape: a typed zero-data struct (or fielded struct for
-  parameterised errors) whose Error() resolves text via
-  desc.Text(text.DescKey…) lazily at call time — never `var ErrX =
-  errors.New("english")` and never an ErrMsg* string-const layer. Empty-struct
-  values are comparable and errors.Is finds them through %w wraps. Reference:
-  internal/err/context/context.go.
-- fmt.Fprintf to strings.Builder silently discards errors (Write never fails) so
-  errcheck allows it, but project convention forbids any silent discard —
-  TestNoUncheckedFmtWrite enforces `if _, err := fmt.Fprintf(...)`.
-- A path-returning (string, error) function must never return ('', nil):
-  filepath.Join('', rel) yields rel as a CWD-relative path, causing orphan
-  writes at project root. Sentinel errors force callers to gate. Audit any
-  path-returner with a historic ('', nil) shortcut (fixed: state.Dir,
-  rc.ContextDir).
-- Package-local err.go files in CLI packages invite agents to duplicate error
-  constructors (errFileWrite, errMkdir repeated). Centralize in internal/err; no
-  err.go files in CLI packages.
+- os.IsNotExist does NOT unwrap — it is false on any fmt.Errorf("…%w…") error; prefer errors.Is(err, os.ErrNotExist). But errors.Is only holds if the wrap carries %w at runtime, and a wrap whose format string comes from the text/i18n registry only carries %w when that registry is initialized (so it behaves differently in prod vs a bare test binary; go vet can't see it). To detect file absence reliably, stat directly: os.Stat returns an unwrapped *fs.PathError so errors.Is(statErr, os.ErrNotExist) is dependable everywhere.
+- An error-discard catalogue (grep + name/regex classification) is an inventory of candidates, not findings. Name-inference produces false positives (a discarded bool mistaken for an error; a value type that can't nil-deref; an already-failed cleanup-close path). Read the callee signature and enclosing control flow before assigning return-error vs logWarn vs annotate.
+- Canonical sentinel shape: a typed zero-data struct (or fielded struct for parameterised errors) whose Error() resolves text via desc.Text(text.DescKey…) lazily at call time — never `var ErrX = errors.New("english")` and never an ErrMsg* string-const layer. Empty-struct values are comparable and errors.Is finds them through %w wraps. Reference: internal/err/context/context.go.
+- fmt.Fprintf to strings.Builder silently discards errors (Write never fails) so errcheck allows it, but project convention forbids any silent discard — TestNoUncheckedFmtWrite enforces `if _, err := fmt.Fprintf(...)`.
+- A path-returning (string, error) function must never return ('', nil): filepath.Join('', rel) yields rel as a CWD-relative path, causing orphan writes at project root. Sentinel errors force callers to gate. Audit any path-returner with a historic ('', nil) shortcut (fixed: state.Dir, rc.ContextDir).
+- Package-local err.go files in CLI packages invite agents to duplicate error constructors (errFileWrite, errMkdir repeated). Centralize in internal/err; no err.go files in CLI packages.
 
 ---
 
@@ -312,25 +180,10 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 4 entries (2026-03-24 to 2026-05-22)
 
-- `git rev-parse` exits 0 on an unknown long-flag and echoes the literal arg
-  back as its only stdout line (treats it as a candidate revision name). A
-  non-zero-exit guard never trips, so `--show-current` shipped verbatim into
-  handover frontmatter. Validate the OUTPUT shape (length, no `--` prefix,
-  hex-ness for SHAs) when wrapping rev-parse, not just the exit code.
-  (`--show-current` is a `git branch` flag, not rev-parse.)
-- Group git flag constants by the subcommand whose argv they're valid in (//
-  Branch subcommand flags, // Rev-parse flags), not by "loose CLI flags" — the
-  group comment is informal type info; mis-grouping enables wrong-subcommand
-  bugs. Genuinely-spanning flags (-C, --) go under an explicit Cross-subcommand
-  group.
-- `git describe --tags --abbrev=0` follows reachability from HEAD, not the
-  global tag list (diffed against v0.3.0 instead of v0.6.0 on a diverged release
-  branch). For "latest release globally" use `git tag --sort=-v:refname | head
-  -1`.
-- A trailing regex word boundary \b does NOT exclude hyphenated continuations
-  (\bgit commit\b matches `git commit-tree`). For porcelain with hyphenated
-  cousins (commit-tree, commit-graph, for-each-ref) append a (?!-) negative
-  lookahead.
+- `git rev-parse` exits 0 on an unknown long-flag and echoes the literal arg back as its only stdout line (treats it as a candidate revision name). A non-zero-exit guard never trips, so `--show-current` shipped verbatim into handover frontmatter. Validate the OUTPUT shape (length, no `--` prefix, hex-ness for SHAs) when wrapping rev-parse, not just the exit code. (`--show-current` is a `git branch` flag, not rev-parse.)
+- Group git flag constants by the subcommand whose argv they're valid in (// Branch subcommand flags, // Rev-parse flags), not by "loose CLI flags" — the group comment is informal type info; mis-grouping enables wrong-subcommand bugs. Genuinely-spanning flags (-C, --) go under an explicit Cross-subcommand group.
+- `git describe --tags --abbrev=0` follows reachability from HEAD, not the global tag list (diffed against v0.3.0 instead of v0.6.0 on a diverged release branch). For "latest release globally" use `git tag --sort=-v:refname | head -1`.
+- A trailing regex word boundary \b does NOT exclude hyphenated continuations (\bgit commit\b matches `git commit-tree`). For porcelain with hyphenated cousins (commit-tree, commit-graph, for-each-ref) append a (?!-) negative lookahead.
 
 ---
 
@@ -338,30 +191,10 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 4 entries (2026-05-11 to 2026-05-22)
 
-- Removing/renaming any cross-language contract (env channel, feature flag) is a
-  FOUR-surface cleanup, not three: (1) Go build+lint+test, (2) audit/compliance
-  tests, (3) asset templates (CLAUDE.md, AGENT_PLAYBOOK, hooks.json), (4)
-  TypeScript-typed integrations (opencode plugin, vscode extension). The TS
-  surface is invisible to `go test ./...` by design; tsc --noEmit only runs in
-  CI unless invoked from tools/typecheck/opencode/ or editors/vscode/. Want: a
-  `make typecheck` target wrapping both, in pre-commit + release checklist.
-- tsc resolves node_modules by walking up from each SOURCE file's location, not
-  the tsconfig's location. For a cross-tree setup (tsconfig in dir A, include
-  points at dir B), add explicit baseUrl + paths (+ typeRoots) to the tsconfig
-  so node_modules can live with the tooling.
-- vitest's vi.mock() does NOT preserve Node's async-deferral guarantees: a
-  mocked execFile (or fs.readFile, dns.lookup, http.request) can fire its
-  callback synchronously, TDZ-trapping a closure that's provably safe by Node's
-  contract. When a linter suggests tightening let→const on a var captured
-  through an async callback, verify under the test runner; the safe form is
-  `let` + an eslint-disable naming the mock constraint.
-- A test suite excluded from BOTH typecheck and execution rots compounding:
-  re-enable cost = sum of ALL drift since last green (named 2 breakages, found
-  18 more on first run), not just the named bug. expect.anything()/expect.any()
-  pass typecheck so only execution catches the drift. When adding any tooling
-  exclude (tsconfig glob, vitest ignore, pytest --ignore), file an immediate
-  follow-up whose acceptance criterion is removal; budget 5–20× the named
-  scope on re-enable.
+- Removing/renaming any cross-language contract (env channel, feature flag) is a FOUR-surface cleanup, not three: (1) Go build+lint+test, (2) audit/compliance tests, (3) asset templates (CLAUDE.md, AGENT_PLAYBOOK, hooks.json), (4) TypeScript-typed integrations (opencode plugin, vscode extension). The TS surface is invisible to `go test ./...` by design; tsc --noEmit only runs in CI unless invoked from tools/typecheck/opencode/ or editors/vscode/. Want: a `make typecheck` target wrapping both, in pre-commit + release checklist.
+- tsc resolves node_modules by walking up from each SOURCE file's location, not the tsconfig's location. For a cross-tree setup (tsconfig in dir A, include points at dir B), add explicit baseUrl + paths (+ typeRoots) to the tsconfig so node_modules can live with the tooling.
+- vitest's vi.mock() does NOT preserve Node's async-deferral guarantees: a mocked execFile (or fs.readFile, dns.lookup, http.request) can fire its callback synchronously, TDZ-trapping a closure that's provably safe by Node's contract. When a linter suggests tightening let→const on a var captured through an async callback, verify under the test runner; the safe form is `let` + an eslint-disable naming the mock constraint.
+- A test suite excluded from BOTH typecheck and execution rots compounding: re-enable cost = sum of ALL drift since last green (named 2 breakages, found 18 more on first run), not just the named bug. expect.anything()/expect.any() pass typecheck so only execution catches the drift. When adding any tooling exclude (tsconfig glob, vitest ignore, pytest --ignore), file an immediate follow-up whose acceptance criterion is removal; budget 5–20× the named scope on re-enable.
 
 ---
 
@@ -369,30 +202,11 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 5 entries (all 2026-05-10)
 
-- An ongoing user paying concrete workaround tax (disabled skills, hand-typed
-  closeouts, colliding root constitution files) is the strongest validation
-  evidence — beats user research, N=2 discussion, "seems useful." Use the
-  workaround details as the inverse-spec; ship the shape they hand-rolled and
-  use their project as the regression corpus.
-- When lifting from a battle-tested external design, lift the renames and
-  disambiguation moves alongside the features: intentional renames encode
-  resolved conflicts (KB-RULES.md not CONSTITUTION.md; domain-decisions.md not
-  DECISIONS.md). Treating them as cosmetic re-litigates the underlying fight.
-- KB epistemology: a knowledge base has no "decide" moment — only
-  evidence-capture events with confidence bands (>0.9 = decided by contract).
-  Even NL assertions ("anchor on this") are evidence-capture, not
-  decision-capture. So a parallel /ctx-kb-decide skill is the wrong shape; the
-  pipeline-only-writer model is ontologically correct. General check: "I chose
-  between alternatives" vs "I learned about the world."
-- Recursive composability eliminates feature classes: a KB of KBs is a KB
-  (source-map kind: kb + the standard ingest pipeline covers federation; no v1
-  schema lockout). Ask whether the standard pipeline pointed at its own output
-  covers a "thing-of-things" before designing a new mechanism.
-- The LLM is the migration tool: every category of being-wrong about a schema
-  (ID renumbering, taxonomy reshuffle, band remapping, path renames) is cheap
-  because LLM cleanup absorbs the migration. Commit to the readable, opinionated
-  v1 schema instead of hedging with abstract types; surface dirty state via
-  doctor advisories so the agent has a work surface.
+- An ongoing user paying concrete workaround tax (disabled skills, hand-typed closeouts, colliding root constitution files) is the strongest validation evidence — beats user research, N=2 discussion, "seems useful." Use the workaround details as the inverse-spec; ship the shape they hand-rolled and use their project as the regression corpus.
+- When lifting from a battle-tested external design, lift the renames and disambiguation moves alongside the features: intentional renames encode resolved conflicts (KB-RULES.md not CONSTITUTION.md; domain-decisions.md not DECISIONS.md). Treating them as cosmetic re-litigates the underlying fight.
+- KB epistemology: a knowledge base has no "decide" moment — only evidence-capture events with confidence bands (>0.9 = decided by contract). Even NL assertions ("anchor on this") are evidence-capture, not decision-capture. So a parallel /ctx-kb-decide skill is the wrong shape; the pipeline-only-writer model is ontologically correct. General check: "I chose between alternatives" vs "I learned about the world."
+- Recursive composability eliminates feature classes: a KB of KBs is a KB (source-map kind: kb + the standard ingest pipeline covers federation; no v1 schema lockout). Ask whether the standard pipeline pointed at its own output covers a "thing-of-things" before designing a new mechanism.
+- The LLM is the migration tool: every category of being-wrong about a schema (ID renumbering, taxonomy reshuffle, band remapping, path renames) is cheap because LLM cleanup absorbs the migration. Commit to the readable, opinionated v1 schema instead of hedging with abstract types; surface dirty state via doctor advisories so the agent has a work surface.
 
 ---
 
@@ -400,29 +214,11 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 6 entries (2026-02-24 to 2026-04-01)
 
-- Exhaustive lists/counts in architecture docs (package lists, command tables,
-  skill counts) drift silently because nobody re-counts (23 listed vs 31
-  actual). Add `` markers; run
-  /ctx-architecture after adding packages/commands (/ctx-drift catches stale
-  paths but not missing entries).
-- Template changes are invisible to existing projects until `ctx init --force`;
-  non-destructive init never re-syncs. checkTemplateHeaders was added to `ctx
-  drift`.
-- Any content duplicated in two locations without a sync mechanism drifts
-  silently (Copilot CLI skills as condensed ctx skills; assets/why/ vs docs/).
-  Wire freshness checks as build PREREQUISITES, not optional audit steps (make
-  sync-copilot-skills, make sync-why must be build deps).
-- Machine-generated CLAUDE.md content (GitNexus injected 121 lines / 61%)
-  consumes per-turn budget without proportional value. Auto-generated content
-  belongs in on-demand skills; prefer a one-line pointer over inline content.
-  Audit CLAUDE.md periodically.
-- CLI reference docs outpace implementation (ctx remind had no CLI, recall sync
-  no Cobra wiring) — verify with `ctx  --help` before releasing docs.
-  Agent style-violation sweeps are unreliable (8 found vs 48+ actual); follow
-  with targeted grep + manual classification. Documentation audits must compare
-  against known-good examples for the COMPLETE standard, not mere presence. New
-  audit concerns (e.g. dead links) belong in an existing audit skill's checklist
-  before becoming standalone.
+- Exhaustive lists/counts in architecture docs (package lists, command tables, skill counts) drift silently because nobody re-counts (23 listed vs 31 actual). Add `` markers; run /ctx-architecture after adding packages/commands (/ctx-drift catches stale paths but not missing entries).
+- Template changes are invisible to existing projects until `ctx init --force`; non-destructive init never re-syncs. checkTemplateHeaders was added to `ctx drift`.
+- Any content duplicated in two locations without a sync mechanism drifts silently (Copilot CLI skills as condensed ctx skills; assets/why/ vs docs/). Wire freshness checks as build PREREQUISITES, not optional audit steps (make sync-copilot-skills, make sync-why must be build deps).
+- Machine-generated CLAUDE.md content (GitNexus injected 121 lines / 61%) consumes per-turn budget without proportional value. Auto-generated content belongs in on-demand skills; prefer a one-line pointer over inline content. Audit CLAUDE.md periodically.
+- CLI reference docs outpace implementation (ctx remind had no CLI, recall sync no Cobra wiring) — verify with `ctx  --help` before releasing docs. Agent style-violation sweeps are unreliable (8 found vs 48+ actual); follow with targeted grep + manual classification. Documentation audits must compare against known-good examples for the COMPLETE standard, not mere presence. New audit concerns (e.g. dead links) belong in an existing audit skill's checklist before becoming standalone.
 
 ---
 
@@ -430,20 +226,10 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 4 entries (2026-03-14 to 2026-04-04)
 
-- Any string containing English words alongside format directives ("%d entries
-  checked") is user-facing text belonging in YAML assets — the format-verb
-  (and URL-scheme, HTML-entity, err/) exemptions were removed from
-  TestNoMagicStrings.
-- Any string reaching the user, including stderr warnings, routes through
-  assets.TextDesc() for i18n readiness; create text.yaml entries and asset keys
-  first.
-- Magic-string cleanup is fractal: each fix puts adjacent code under scrutiny (4
-  Fprintf calls → over-tokenized formats, magic hex perms, TOML tokens,
-  missing docstrings). Budget 2–3× the initial estimate; commit per layer.
-- Naming a constant _alt and hardcoding one non-English language as a built-in
-  default is implicit language favoritism that doesn't scale (alt_2? alt_3?).
-  Use configurable lists from the start; default to a single canonical value,
-  all extensions user-configured equally.
+- Any string containing English words alongside format directives ("%d entries checked") is user-facing text belonging in YAML assets — the format-verb (and URL-scheme, HTML-entity, err/) exemptions were removed from TestNoMagicStrings.
+- Any string reaching the user, including stderr warnings, routes through assets.TextDesc() for i18n readiness; create text.yaml entries and asset keys first.
+- Magic-string cleanup is fractal: each fix puts adjacent code under scrutiny (4 Fprintf calls → over-tokenized formats, magic hex perms, TOML tokens, missing docstrings). Budget 2–3× the initial estimate; commit per layer.
+- Naming a constant _alt and hardcoding one non-English language as a built-in default is implicit language favoritism that doesn't scale (alt_2? alt_3?). Use configurable lists from the start; default to a single canonical value, all extensions user-configured equally.
 
 ---
 
@@ -451,24 +237,12 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 6 entries (2026-03-07 to 2026-03-23)
 
-- A constant used by only one domain (agent scoring, budget %, cooldowns)
-  belongs in that domain's config package, not a god-object file.go. Check
-  callers before placing.
-- Before adding any constant to internal/config, grep by VALUE (".jsonl") not
-  just name — camelCase vs ALLCAPS variants hide duplicates (ExtJsonl vs
-  existing ExtJSONL).
-- Project-root files created by `ctx init` (Makefile) are scaffolding
-  (config/file), NOT context files loaded via ReadOrder (config/ctx). Check
-  ReadOrder membership before moving a file constant.
-- SafeReadFile / validation.SafeReadFile take (baseDir, filename) separately —
-  split full paths with filepath.Dir + filepath.Base when adapting os.ReadFile
-  calls.
-- One-liner method wrappers that just forward a struct field to a stdlib/pkg
-  function (checkBoundary → validation.ValidateBoundary with h.ContextDir)
-  obscure the real dependency — inline them.
-- A param-struct field that is a function pointer where all callers pass thin
-  wrappers varying only by a text key (MergeParams.UpdateFn) is "data in
-  disguise" — replace the callback with the key and let the consumer dispatch.
+- A constant used by only one domain (agent scoring, budget %, cooldowns) belongs in that domain's config package, not a god-object file.go. Check callers before placing.
+- Before adding any constant to internal/config, grep by VALUE (".jsonl") not just name — camelCase vs ALLCAPS variants hide duplicates (ExtJsonl vs existing ExtJSONL).
+- Project-root files created by `ctx init` (Makefile) are scaffolding (config/file), NOT context files loaded via ReadOrder (config/ctx). Check ReadOrder membership before moving a file constant.
+- SafeReadFile / validation.SafeReadFile take (baseDir, filename) separately — split full paths with filepath.Dir + filepath.Base when adapting os.ReadFile calls.
+- One-liner method wrappers that just forward a struct field to a stdlib/pkg function (checkBoundary → validation.ValidateBoundary with h.ContextDir) obscure the real dependency — inline them.
+- A param-struct field that is a function pointer where all callers pass thin wrappers varying only by a text key (MergeParams.UpdateFn) is "data in disguise" — replace the callback with the key and let the consumer dispatch.
 
 ---
 
@@ -476,28 +250,11 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 6 entries (2026-03-16 to 2026-04-14)
 
-- System-level brevity instructions outcompete context-injected conventions;
-  memory shifts probability (~40%→~70%) but doesn't create invariants. Invest
-  in linter/PreToolUse gates for mechanically-checkable conventions; reserve
-  behavioral nudges for judgment calls.
-- Force-loaded behavioral prose (AGENT_PLAYBOOK at ~14k tokens) gets skipped
-  when the user's first message is a concrete task; action-gating hooks
-  (qa-reminder, specs-nudge) are followed because they fire at the moment of
-  violation. More injected content = less attention per token. Prefer
-  action-gating hooks; reserve force-injection for hard rules + distilled
-  checklists.
-- Any docstring/comment/documentation-formatting task is convention-sensitive:
-  read CONVENTIONS.md (Documentation section) + LEARNINGS.md for known gaps
-  FIRST, and audit all functions in scope against the template, not just diffed
-  ones.
-- AST audit tests must default to scanning ALL documented functions (use
-  opt-outs not exported-only opt-ins) — TestDocCommentStructure missed
-  unexported helpers (84 violations fixed). And the stutter test
-  (TestNoStutteryFunctions) walks *ast.FuncDecl only, not GenDecl — stuttery
-  const/var/type names slip through until the audit is extended.
-- Every exemption map/allowlist in audit tests is a tempting agent shortcut: add
-  DO-NOT-widen guard comments to every exemption data structure (10 across 7
-  files) and review PRs for drive-by allowlist additions.
+- System-level brevity instructions outcompete context-injected conventions; memory shifts probability (~40%→~70%) but doesn't create invariants. Invest in linter/PreToolUse gates for mechanically-checkable conventions; reserve behavioral nudges for judgment calls.
+- Force-loaded behavioral prose (AGENT_PLAYBOOK at ~14k tokens) gets skipped when the user's first message is a concrete task; action-gating hooks (qa-reminder, specs-nudge) are followed because they fire at the moment of violation. More injected content = less attention per token. Prefer action-gating hooks; reserve force-injection for hard rules + distilled checklists.
+- Any docstring/comment/documentation-formatting task is convention-sensitive: read CONVENTIONS.md (Documentation section) + LEARNINGS.md for known gaps FIRST, and audit all functions in scope against the template, not just diffed ones.
+- AST audit tests must default to scanning ALL documented functions (use opt-outs not exported-only opt-ins) — TestDocCommentStructure missed unexported helpers (84 violations fixed). And the stutter test (TestNoStutteryFunctions) walks *ast.FuncDecl only, not GenDecl — stuttery const/var/type names slip through until the audit is extended.
+- Every exemption map/allowlist in audit tests is a tempting agent shortcut: add DO-NOT-widen guard comments to every exemption data structure (10 across 7 files) and review PRs for drive-by allowlist additions.
 
 ---
 
@@ -505,24 +262,11 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 5 entries (2026-03-16 to 2026-05-10)
 
-- gofmt strips bare `//` padding lines as unnecessary whitespace, so
-  programmatic Go generation must produce substantive content lines; always run
-  gofmt after any scripted Go-file generation.
-- Agents reliably introduce gofmt issues during bulk renames (75+ files, 12
-  broken); run `gofmt -l` (then `-w`) as a standard step after any agent-driven
-  bulk edit before trusting the build.
-- The "compile version X does not match go tool version Y" error comes from the
-  CACHED toolchain (~/go/pkg/mod/golang.org/toolchain@…), not the system Go
-  — reinstalling Go does nothing. Diagnose via `go env GOROOT`; fix by
-  deleting the cached dir, bumping go.mod, or GOTOOLCHAIN=go. `go clean
-  -cache` and GOTOOLCHAIN=local don't help.
-- `make test` exit code is unreliable: the -cover flag can fail with "no such
-  tool covdata" even when every package passes. Fall back to `go test ./...` (no
-  -cover) and tally ^ok/^FAIL.
-- AST checks via go/packages only see files matching the current GOOS —
-  darwin-only (_darwin.go) violations are invisible on Linux. Fix violations
-  regardless; note coverage is platform-dependent (need multi-GOOS CI or a
-  go/parser fallback).
+- gofmt strips bare `//` padding lines as unnecessary whitespace, so programmatic Go generation must produce substantive content lines; always run gofmt after any scripted Go-file generation.
+- Agents reliably introduce gofmt issues during bulk renames (75+ files, 12 broken); run `gofmt -l` (then `-w`) as a standard step after any agent-driven bulk edit before trusting the build.
+- The "compile version X does not match go tool version Y" error comes from the CACHED toolchain (~/go/pkg/mod/golang.org/toolchain@…), not the system Go — reinstalling Go does nothing. Diagnose via `go env GOROOT`; fix by deleting the cached dir, bumping go.mod, or GOTOOLCHAIN=go. `go clean -cache` and GOTOOLCHAIN=local don't help.
+- `make test` exit code is unreliable: the -cover flag can fail with "no such tool covdata" even when every package passes. Fall back to `go test ./...` (no -cover) and tally ^ok/^FAIL.
+- AST checks via go/packages only see files matching the current GOOS — darwin-only (_darwin.go) violations are invisible on Linux. Fix violations regardless; note coverage is platform-dependent (need multi-GOOS CI or a go/parser fallback).
 
 ---
 
@@ -530,25 +274,10 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 4 entries (2026-03-01 to 2026-05-23)
 
-- Stale TASKS.md items often describe work already done in code but not asserted
-  in tests — the task stayed open because nothing pinned the behavior. Triage
-  older items by grep/git-blame on the named symbols; if implemented, close by
-  writing the regression test (often one function). Applies to behavior-named
-  tasks more than feature-named ones.
-- Tasks can be stale in reverse: implementation completed but task not marked
-  done (recall sync was fully wired despite a "not registered" description). Run
-  `ctx  --help` before assuming work remains.
-- Grep for callers must cover the ENTIRE working tree before deleting functions
-  — with unstaged changes from a prior session, grep hits only
-  committed+staged code. Always `make build` after deleting functions even when
-  grep shows zero callers.
-- Spec-trailer improvisation is heuristic drift: when no on-topic spec exists,
-  the path of least resistance cites the most-recent spec from context,
-  satisfying the syntactic gate but defeating truthful traceability — and
-  session-scoped "I'll be careful" commitments don't survive across sessions, so
-  the fix must live in persistent context. Correct responses: scaffold a fresh
-  spec, bundle into the next functional commit, or cite specs/meta/chores.md.
-  (See specs/spec-trailer-discipline.md; AGENT_PLAYBOOK Spec Verification Step.)
+- Stale TASKS.md items often describe work already done in code but not asserted in tests — the task stayed open because nothing pinned the behavior. Triage older items by grep/git-blame on the named symbols; if implemented, close by writing the regression test (often one function). Applies to behavior-named tasks more than feature-named ones.
+- Tasks can be stale in reverse: implementation completed but task not marked done (recall sync was fully wired despite a "not registered" description). Run `ctx  --help` before assuming work remains.
+- Grep for callers must cover the ENTIRE working tree before deleting functions — with unstaged changes from a prior session, grep hits only committed+staged code. Always `make build` after deleting functions even when grep shows zero callers.
+- Spec-trailer improvisation is heuristic drift: when no on-topic spec exists, the path of least resistance cites the most-recent spec from context, satisfying the syntactic gate but defeating truthful traceability — and session-scoped "I'll be careful" commitments don't survive across sessions, so the fix must live in persistent context. Correct responses: scaffold a fresh spec, bundle into the next functional commit, or cite specs/meta/chores.md. (See specs/spec-trailer-discipline.md; AGENT_PLAYBOOK Spec Verification Step.)
 
 ---
 
@@ -556,32 +285,12 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 6 entries (2026-02-19 to 2026-05-30)
 
-- Behavior-preserving refactors of formatting/rendering code: capture golden
-  fixtures from the LIVE legacy path before deleting it (throwaway test writes
-  testdata/*.golden), then assert byte-equality after — avoids silent drift
-  from hand-transcribing expected output.
-- Removing a sentinel (ErrDirNotDeclared) cascades through ~10 errors.Is
-  consumers and ~30 test fixtures; spec-level step boundaries that separate
-  "swap resolver" from "remove guard" don't survive when the second references
-  the soon-deleted sentinel. Plan the merged commit at spec time; do the
-  compile-surface analysis then.
-- Subagent parallelism shines for well-bounded mechanical refactor WITH a
-  canonical worked example on disk and an explicit fix-or-fail-with-a-blocker
-  instruction (invoke the no-deferral rule). Do one worked example in the
-  orchestrator, then dispatch subagents pointing at it.
-- Subagents reliably exceed scope (rename funcs, change signatures, restructure
-  files even for em-dash fixes) and create new files without deleting originals.
-  After any agent refactor: `git diff --stat`, `git diff --name-only HEAD`,
-  revert out-of-scope changes, check for stale package decls/duplicate
-  defs/orphaned imports, run gofmt + `go test ./...`.
-- Splitting a flat core/ package into subpackages exposes duplicated logic,
-  misplaced types, and function-pointer smuggling invisible in the flat layout;
-  circular-dep resolution during the split IS the design work that reveals the
-  right structure.
-- Cross-cutting change ripple: path/asset/feature changes ripple across 15+ doc
-  files + multiple layers (embed directive, accessors, callers, tests, config
-  consts, build targets, docs). Grep broadly (not just code); a feature without
-  docs (feature page, cli-reference, recipes, nav) is invisible.
+- Behavior-preserving refactors of formatting/rendering code: capture golden fixtures from the LIVE legacy path before deleting it (throwaway test writes testdata/*.golden), then assert byte-equality after — avoids silent drift from hand-transcribing expected output.
+- Removing a sentinel (ErrDirNotDeclared) cascades through ~10 errors.Is consumers and ~30 test fixtures; spec-level step boundaries that separate "swap resolver" from "remove guard" don't survive when the second references the soon-deleted sentinel. Plan the merged commit at spec time; do the compile-surface analysis then.
+- Subagent parallelism shines for well-bounded mechanical refactor WITH a canonical worked example on disk and an explicit fix-or-fail-with-a-blocker instruction (invoke the no-deferral rule). Do one worked example in the orchestrator, then dispatch subagents pointing at it.
+- Subagents reliably exceed scope (rename funcs, change signatures, restructure files even for em-dash fixes) and create new files without deleting originals. After any agent refactor: `git diff --stat`, `git diff --name-only HEAD`, revert out-of-scope changes, check for stale package decls/duplicate defs/orphaned imports, run gofmt + `go test ./...`.
+- Splitting a flat core/ package into subpackages exposes duplicated logic, misplaced types, and function-pointer smuggling invisible in the flat layout; circular-dep resolution during the split IS the design work that reveals the right structure.
+- Cross-cutting change ripple: path/asset/feature changes ripple across 15+ doc files + multiple layers (embed directive, accessors, callers, tests, config consts, build targets, docs). Grep broadly (not just code); a feature without docs (feature page, cli-reference, recipes, nav) is invisible.
 
 ---
 
@@ -589,26 +298,10 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 4 entries (2026-01-25 to 2026-04-03)
 
-- Full pre-commit gate, every time: (1) CGO_ENABLED=0 go build ./cmd/ctx, (2)
-  golangci-lint run, (3) CGO_ENABLED=0 go test. Own the codebase — fix
-  pre-existing lint issues you didn't introduce.
-- gosec permissions: 0o600 for files (incl. tests — G306 flags 0644 even in
-  test code), 0o750 for dirs (G301); G304 file-inclusion is safe to
-  //nolint:gosec in tests using t.TempDir(). Prefer renaming constants to avoid
-  G101 false positives (Tokens→Usage, Passed→OK) over nolint/nosec/path
-  exclusions, which break on file reorg.
-- Suppression anti-patterns: nolint:goconst normalizes magic strings (use config
-  consts); nolint:errcheck in tests teaches agents to spread the pattern to
-  production (use t.Fatal for setup, `defer func(){ _ = f.Close() }()` for
-  cleanup); golangci-lint v2 ignores inline nolint for some linters — use
-  config-level exclusions.rules for gosec, fix the code for errcheck. Use
-  cmd.Printf/Println in Cobra commands instead of fmt.Fprintf. `defer
-  os.Chdir(x)` fails errcheck — wrap in `defer func(){ _ = os.Chdir(x) }()`.
-  CI Go-version mismatch: install-mode goinstall.
-- Chokepoint migrations have cascading benefits: centralizing file I/O into
-  internal/io/ (already using config/fs consts) zeroed out TestNoRawPermissions
-  for free. Prioritize chokepoint migrations (io, exec, write, err) before
-  smaller dependent checks.
+- Full pre-commit gate, every time: (1) CGO_ENABLED=0 go build ./cmd/ctx, (2) golangci-lint run, (3) CGO_ENABLED=0 go test. Own the codebase — fix pre-existing lint issues you didn't introduce.
+- gosec permissions: 0o600 for files (incl. tests — G306 flags 0644 even in test code), 0o750 for dirs (G301); G304 file-inclusion is safe to //nolint:gosec in tests using t.TempDir(). Prefer renaming constants to avoid G101 false positives (Tokens→Usage, Passed→OK) over nolint/nosec/path exclusions, which break on file reorg.
+- Suppression anti-patterns: nolint:goconst normalizes magic strings (use config consts); nolint:errcheck in tests teaches agents to spread the pattern to production (use t.Fatal for setup, `defer func(){ _ = f.Close() }()` for cleanup); golangci-lint v2 ignores inline nolint for some linters — use config-level exclusions.rules for gosec, fix the code for errcheck. Use cmd.Printf/Println in Cobra commands instead of fmt.Fprintf. `defer os.Chdir(x)` fails errcheck — wrap in `defer func(){ _ = os.Chdir(x) }()`. CI Go-version mismatch: install-mode goinstall.
+- Chokepoint migrations have cascading benefits: centralizing file I/O into internal/io/ (already using config/fs consts) zeroed out TestNoRawPermissions for free. Prioritize chokepoint migrations (io, exec, write, err) before smaller dependent checks.
 
 ---
 
@@ -616,41 +309,11 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 5 entries (2026-01-25 to 2026-04-06)
 
-- Hook scripts receive JSON via stdin (HOOK_INPUT=$(cat) then jq), not env vars;
-  key names are case-sensitive (PreToolUse, SessionEnd); use
-  $CLAUDE_PROJECT_DIR, never hardcode paths; anchor regex to command-start
-  `(^|;|&&|\|\|)\s*` ('ctx' binary vs dir); grep matches inside quoted args
-  (test with blocked words); scripts silently lose execute permission (verify ls
-  -la).
-- Output routing: plain-text hook stdout is silently ignored — Claude Code
-  parses stdout starting with `{` as JSON directives; return JSON via
-  printHookContext(). For UserPromptSubmit specifically, stdout is prepended as
-  AI context (not user-visible), stderr+exit0 is swallowed, user-visible output
-  requires {"systemMessage":"…"} or exit 2 (blocks); there is NO non-blocking
-  user-visible channel. Two-tier severity is sufficient: unprefixed (agent
-  context, may relay) and "IMPORTANT: Relay VERBATIM" (guaranteed); don't add
-  more prefixes.
-- Agents only relay content with explicit display instructions: a
-  system-reminder line with no "Display this line verbatim" is invisible to the
-  user even when correct. IMPORTANT: signals internal priority, not user-facing
-  output.
-- Compliance: soft instructions have a ~75–85% ceiling because "don't apply
-  judgment" is itself judgment; for 100% compliance inject via additionalContext
-  rather than instruct. Hook compliance degrades on narrow mid-session tasks
-  (~15–25% skip) because CLAUDE.md's "may or may not be relevant" competes
-  with hook authority — fix by elevating hook authority explicitly; the
-  mandatory checkpoint relay block is the compliance canary. No reliable
-  agent-side before-session-end event exists (SessionEnd fires after the agent
-  is gone) — mid-session nudges + explicit /ctx-wrap-up are the only reliable
-  persistence. Repeated injection causes repetition fatigue — gate with
-  --session $PPID --cooldown and pair with a readback instruction.
-- Context-budget injection strategy: once ~7K tokens are auto-injected (fait
-  accompli), the agent's rationalization inverts from "skip to save effort" to
-  "marginal cost is trivial." Front-load highest-value content as injection,
-  then leverage sunk cost for on-demand reads. Verbal summaries + linked diagram
-  files cut ARCHITECTURE.md ~12K→3.8K (extract diagrams outside FileReadOrder;
-  the 4-chars/token estimator is accurate — optimize content not the
-  estimator).
+- Hook scripts receive JSON via stdin (HOOK_INPUT=$(cat) then jq), not env vars; key names are case-sensitive (PreToolUse, SessionEnd); use $CLAUDE_PROJECT_DIR, never hardcode paths; anchor regex to command-start `(^|;|&&|\|\|)\s*` ('ctx' binary vs dir); grep matches inside quoted args (test with blocked words); scripts silently lose execute permission (verify ls -la).
+- Output routing: plain-text hook stdout is silently ignored — Claude Code parses stdout starting with `{` as JSON directives; return JSON via printHookContext(). For UserPromptSubmit specifically, stdout is prepended as AI context (not user-visible), stderr+exit0 is swallowed, user-visible output requires {"systemMessage":"…"} or exit 2 (blocks); there is NO non-blocking user-visible channel. Two-tier severity is sufficient: unprefixed (agent context, may relay) and "IMPORTANT: Relay VERBATIM" (guaranteed); don't add more prefixes.
+- Agents only relay content with explicit display instructions: a system-reminder line with no "Display this line verbatim" is invisible to the user even when correct. IMPORTANT: signals internal priority, not user-facing output.
+- Compliance: soft instructions have a ~75–85% ceiling because "don't apply judgment" is itself judgment; for 100% compliance inject via additionalContext rather than instruct. Hook compliance degrades on narrow mid-session tasks (~15–25% skip) because CLAUDE.md's "may or may not be relevant" competes with hook authority — fix by elevating hook authority explicitly; the mandatory checkpoint relay block is the compliance canary. No reliable agent-side before-session-end event exists (SessionEnd fires after the agent is gone) — mid-session nudges + explicit /ctx-wrap-up are the only reliable persistence. Repeated injection causes repetition fatigue — gate with --session $PPID --cooldown and pair with a readback instruction.
+- Context-budget injection strategy: once ~7K tokens are auto-injected (fait accompli), the agent's rationalization inverts from "skip to save effort" to "marginal cost is trivial." Front-load highest-value content as injection, then leverage sunk cost for on-demand reads. Verbal summaries + linked diagram files cut ARCHITECTURE.md ~12K→3.8K (extract diagrams outside FileReadOrder; the 4-chars/token estimator is accurate — optimize content not the estimator).
 
 ---
 
@@ -658,31 +321,12 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 6 entries (2026-02-11 to 2026-03-06)
 
-- Permission drift is distinct from code drift — settings.local.json is
-  gitignored so no review catches stale entries; it accumulates session debris
-  (run /sanitize-permissions + /ctx-drift). Skill() permissions don't support
-  name-prefix globs (list each); wildcard trusted binaries (Bash(ctx:*),
-  Bash(make:*)) but keep git granular (never Bash(git:*)).
-- Gitignored directories are invisible to git status — stale artifacts persist
-  indefinitely (periodically ls them). Add editor artifacts (*.swp,*.swo,*~) to
-  .gitignore from day one. Gitignore entries for sensitive paths are security
-  controls, not documentation — never remove during cleanup.
-- The state directory accumulates write-only session tombstones and grows
-  unbounded without auto-prune (234 files found); autoPrune(7) now runs once per
-  session at startup via context-load-gate (manual `ctx system prune` still
-  available).
-- A session-scoped tombstone must include the session ID in its filename, else
-  it suppresses hooks across ALL concurrent and future sessions (memory-drift
-  fixed; backup-reminded, ceremony-reminded, check-knowledge, journal-reminded,
-  version-checked, ctx-wrapped-up still carry this bug). Use the UUID pattern so
-  prune can clean them.
-- New log sinks must follow the established rotation pattern (size-based, single
-  previous generation): eventlog rotated at 1MB but logMessage() in state.go was
-  append-only with no size check.
-- If a directory is recreated (auto-prune), an SSH shell holding the old inode
-  won't see new files (ls returns "no such file" though cat with the full path
-  works elsewhere); after `ctx system prune` or any state recreation, SSH
-  sessions need cd-. or re-login.
+- Permission drift is distinct from code drift — settings.local.json is gitignored so no review catches stale entries; it accumulates session debris (run /sanitize-permissions + /ctx-drift). Skill() permissions don't support name-prefix globs (list each); wildcard trusted binaries (Bash(ctx:*), Bash(make:*)) but keep git granular (never Bash(git:*)).
+- Gitignored directories are invisible to git status — stale artifacts persist indefinitely (periodically ls them). Add editor artifacts (*.swp,*.swo,*~) to .gitignore from day one. Gitignore entries for sensitive paths are security controls, not documentation — never remove during cleanup.
+- The state directory accumulates write-only session tombstones and grows unbounded without auto-prune (234 files found); autoPrune(7) now runs once per session at startup via context-load-gate (manual `ctx system prune` still available).
+- A session-scoped tombstone must include the session ID in its filename, else it suppresses hooks across ALL concurrent and future sessions (memory-drift fixed; backup-reminded, ceremony-reminded, check-knowledge, journal-reminded, version-checked, ctx-wrapped-up still carry this bug). Use the UUID pattern so prune can clean them.
+- New log sinks must follow the established rotation pattern (size-based, single previous generation): eventlog rotated at 1MB but logMessage() in state.go was append-only with no size check.
+- If a directory is recreated (auto-prune), an SSH shell holding the old inode won't see new files (ls returns "no such file" though cat with the full path works elsewhere); after `ctx system prune` or any state recreation, SSH sessions need cd-. or re-login.
 
 ---
 
@@ -690,18 +334,8 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 2 entries (2026-04-13 to 2026-05-28)
 
-- Swap occupancy is NOT memory pressure: macOS/Windows swap proactively and
-  occupancy is a sticky high-water mark that doesn't recede when pressure ends,
-  so any alert keyed on SwapUsed/SwapTotal ≥ X% false-positives at session
-  start (e.g. after hibernation). Key on OS-native pressure derivatives instead:
-  macOS kern.memorystatus_vm_pressure_level (1/2/4 → OK/Warning/Danger), Linux
-  PSI /proc/pressure/memory some.avg10/full.avg10; fall back to swap-out RATE
-  gated on low available memory, never occupancy.
-- Load average measures a queue (runnable + uninterruptible-sleep), not CPU
-  utilization — high load with low CPU% means many short-lived/I/O-bound
-  processes (e.g. go test spawning hundreds of binaries). For automated alerts
-  prefer the 5-minute average over the reactive 1-minute, which fires on normal
-  build/test activity.
+- Swap occupancy is NOT memory pressure: macOS/Windows swap proactively and occupancy is a sticky high-water mark that doesn't recede when pressure ends, so any alert keyed on SwapUsed/SwapTotal ≥ X% false-positives at session start (e.g. after hibernation). Key on OS-native pressure derivatives instead: macOS kern.memorystatus_vm_pressure_level (1/2/4 → OK/Warning/Danger), Linux PSI /proc/pressure/memory some.avg10/full.avg10; fall back to swap-out RATE gated on low available memory, never occupancy.
+- Load average measures a queue (runnable + uninterruptible-sleep), not CPU utilization — high load with low CPU% means many short-lived/I/O-bound processes (e.g. go test spawning hundreds of binaries). For automated alerts prefer the 5-minute average over the reactive 1-minute, which fires on normal build/test activity.
 
 ---
 
@@ -709,44 +343,18 @@ loop closes without the user watching a pass.
 
 **Consolidated from**: 4 entries (2026-01-19 to 2026-04-25)
 
-- Any code using os.UserHomeDir() / user-level paths (~/.ctx/, ~/.config/) needs
-  t.Setenv("HOME", tmpDir) in tests — especially shared setup helpers. Under
-  parallel `make test`, fourteen test files invoking initialize.Cmd().Execute()
-  raced on read-modify-write of ~/.claude/settings.json, surfacing as flaky
-  "FAIL coverage: [no statements]"; testctx.Declare now sets HOME alongside
-  CTX_DIR (centralized fix).
-- Go testing patterns: `go build ./...` misses test-file callsite breaks —
-  always `go test ./...` after signature changes. Consume all runCmd() returns
-  (`_, _ = runCmd(...)`) for errcheck. Disable ANSI via color.NoColor=true in
-  package init for string assertions. Recall tests isolate via t.Setenv("HOME",
-  tmpDir) with .claude/projects/. formatDuration takes an interface with
-  Minutes() (use a stubDuration). CI needs CTX_SKIP_PATH_CHECK=1 (init checks
-  PATH). CGO_ENABLED=0 for ARM64 Linux.
-- Converting PersistentPreRun → PersistentPreRunE changes exit behavior:
-  errors propagate through Cobra Execute() return with no os.Exit.
-  Subprocess-based tests expecting exit codes must convert to direct error
-  assertions.
+- Any code using os.UserHomeDir() / user-level paths (~/.ctx/, ~/.config/) needs t.Setenv("HOME", tmpDir) in tests — especially shared setup helpers. Under parallel `make test`, fourteen test files invoking initialize.Cmd().Execute() raced on read-modify-write of ~/.claude/settings.json, surfacing as flaky "FAIL coverage: [no statements]"; testctx.Declare now sets HOME alongside CTX_DIR (centralized fix).
+- Go testing patterns: `go build ./...` misses test-file callsite breaks — always `go test ./...` after signature changes. Consume all runCmd() returns (`_, _ = runCmd(...)`) for errcheck. Disable ANSI via color.NoColor=true in package init for string assertions. Recall tests isolate via t.Setenv("HOME", tmpDir) with .claude/projects/. formatDuration takes an interface with Minutes() (use a stubDuration). CI needs CTX_SKIP_PATH_CHECK=1 (init checks PATH). CGO_ENABLED=0 for ARM64 Linux.
+- Converting PersistentPreRun → PersistentPreRunE changes exit behavior: errors propagate through Cobra Execute() return with no os.Exit. Subprocess-based tests expecting exit codes must convert to direct error assertions.
 
 ---
 ## [2026-06-01-174927] Guard managed blocks before regenerating; don't trust the span to be machine-owned
 
-**Context**: ctx learning add silently deleted entry bodies that lived between
-INDEX:START/END markers: index.Update replaced the whole marker span with a
-regenerated table, and ParseHeaders scanning the full file made the result look
-complete, hiding the loss.
+**Context**: ctx learning add silently deleted entry bodies that lived between INDEX:START/END markers: index.Update replaced the whole marker span with a regenerated table, and ParseHeaders scanning the full file made the result look complete, hiding the loss.
 
-**Lesson**: Code that 'replaces the managed block' (index regen, KB managed
-blocks, moc.go) assumes the span between its markers is disposable and
-machine-owned. That assumption breaks the moment user content drifts inside the
-markers, and the regenerated output looks correct so the loss is invisible. The
-fix is a precondition guard that refuses to mutate when regeneration would lose
-data — not smarter parsing of the trapped content.
+**Lesson**: Code that 'replaces the managed block' (index regen, KB managed blocks, moc.go) assumes the span between its markers is disposable and machine-owned. That assumption breaks the moment user content drifts inside the markers, and the regenerated output looks correct so the loss is invisible. The fix is a precondition guard that refuses to mutate when regeneration would lose data — not smarter parsing of the trapped content.
 
-**Application**: Before any 'replace between markers' write, validate the span:
-refuse on entry/content found where only generated output belongs, and on
-malformed/duplicated/out-of-order markers. Fail loud and leave the file
-byte-identical rather than regenerate. Run the guard at the read-before-mutate
-choke point so nothing is written on refusal.
+**Application**: Before any 'replace between markers' write, validate the span: refuse on entry/content found where only generated output belongs, and on malformed/duplicated/out-of-order markers. Fail loud and leave the file byte-identical rather than regenerate. Run the guard at the read-before-mutate choke point so nothing is written on refusal.
 
 ---
 
@@ -772,219 +380,81 @@ choke point so nothing is written on refusal.
 
 ## [2026-05-28-215214] ctx kb: single topic-enumeration site; life-stage count is consumer-side
 
-**Context**: kb reindex blanked the CTX:KB:TOPICS block for grouped kbs
-(things-wtf-dr regrouped 49 topics into folders); the task speculated a sibling
-life-stage topic-count glob was also affected.
+**Context**: kb reindex blanked the CTX:KB:TOPICS block for grouped kbs (things-wtf-dr regrouped 49 topics into folders); the task speculated a sibling life-stage topic-count glob was also affected.
 
-**Lesson**: reindex.ListTopics (internal/cli/kb/core/reindex/topic.go) is the
-ONLY topic enumeration/count in ctx, and CTX:KB:TOPICS is the only managed
-block. The life-stage concept in ctx is the ingest/closeout frontmatter field,
-unrelated to topics. Any per-life-stage topic count lives in the consumer kb,
-which ctx neither generates nor owns.
+**Lesson**: reindex.ListTopics (internal/cli/kb/core/reindex/topic.go) is the ONLY topic enumeration/count in ctx, and CTX:KB:TOPICS is the only managed block. The life-stage concept in ctx is the ingest/closeout frontmatter field, unrelated to topics. Any per-life-stage topic count lives in the consumer kb, which ctx neither generates nor owns.
 
-**Application**: Localize nested-topic fixes to ListTopics; treat
-per-group/per-life-stage topic counts as consumer territory (same recurse +
-exclude-group-landing pattern, fixed in their repo).
+**Application**: Localize nested-topic fixes to ListTopics; treat per-group/per-life-stage topic counts as consumer territory (same recurse + exclude-group-landing pattern, fixed in their repo).
 
 ---
 
 ## [2026-05-28-201400] A non-root Go module nested under the main module's path CAN import its internal/ packages
 
-**Context**: While designing the ctxctl module split, the initial spec (and a
-lot of online consensus) claimed a separate `go.mod` cannot import the parent
-module's `internal/` packages, which would have forced relocating or duplicating
-~25 foundation packages (`rc`, `desc`, `nudge`, `config/*`, …). The "obvious"
-reading made same-module the only viable option.
+**Context**: While designing the ctxctl module split, the initial spec (and a lot of online consensus) claimed a separate `go.mod` cannot import the parent module's `internal/` packages, which would have forced relocating or duplicating ~25 foundation packages (`rc`, `desc`, `nudge`, `config/*`, …). The "obvious" reading made same-module the only viable option.
 
-**Lesson**: Go's internal-import rule is **lexical on import paths, not
-module-scoped**. A separate module whose path is
-`github.com//
/tools/` CAN import -`github.com//
/internal/...` — verified by an empirical build -experiment this session. An outsider path (`example.com/...`) is rejected with -`use of internal package … not allowed`. The rule fires on the import-path -prefix relative to the `internal/` directory's parent, not on module boundaries. +**Lesson**: Go's internal-import rule is **lexical on import paths, not module-scoped**. A separate module whose path is `github.com//
/tools/` CAN import `github.com//
/internal/...` — verified by an empirical build experiment this session. An outsider path (`example.com/...`) is rejected with `use of internal package … not allowed`. The rule fires on the import-path prefix relative to the `internal/` directory's parent, not on module boundaries. -**Application**: For monorepo splits (maintainer-only tooling, isolated -experiments, ancillary CLIs), choose a module path nested under the main module -so the new module reuses the parent's foundations via the lexical-internal -allowance. Full self-containment of a maintainer module would be a DRY -catastrophe; the lexical allowance is the correct shape. Prove it with a -throwaway `go build` against a representative `internal/` import before -designing around the *wrong* constraint. +**Application**: For monorepo splits (maintainer-only tooling, isolated experiments, ancillary CLIs), choose a module path nested under the main module so the new module reuses the parent's foundations via the lexical-internal allowance. Full self-containment of a maintainer module would be a DRY catastrophe; the lexical allowance is the correct shape. Prove it with a throwaway `go build` against a representative `internal/` import before designing around the *wrong* constraint. --- ## [2026-05-28-201300] cobra's legacyArgs lets unknown subcommands silently succeed on non-root groups -**Context**: Every prompt of this session injected 52 lines of `ctx system` help -text into agent context, labeled "hook success." Investigation traced it to the -0.8.1 plugin's `hooks.json` wiring `ctx system check-anchor-drift` as the first -UserPromptSubmit hook — a command the 0.8.1 binary no longer has (the command -was deleted by the cwd-anchored migration in `fc7db228`, but the plugin's hook -config wasn't updated). The harness reported "hook success" because cobra exits -0 on the unknown subcommand. +**Context**: Every prompt of this session injected 52 lines of `ctx system` help text into agent context, labeled "hook success." Investigation traced it to the 0.8.1 plugin's `hooks.json` wiring `ctx system check-anchor-drift` as the first UserPromptSubmit hook — a command the 0.8.1 binary no longer has (the command was deleted by the cwd-anchored migration in `fc7db228`, but the plugin's hook config wasn't updated). The harness reported "hook success" because cobra exits 0 on the unknown subcommand. -**Lesson**: cobra's `legacyArgs` only raises "unknown command" for the **root** -command (`!cmd.HasParent()`); any non-root group (built with `parent.Cmd`) -treats an unknown subcommand as non-error: it falls through to `Help()` and -returns nil → exit 0. In a UserPromptSubmit hook this is **invisible** — the -harness logs "hook success" and injects the whole help text into agent context -every prompt. The 0.8.1 plugin's stale wiring of the retired -`check-anchor-drift` caused exactly this for the entire session. +**Lesson**: cobra's `legacyArgs` only raises "unknown command" for the **root** command (`!cmd.HasParent()`); any non-root group (built with `parent.Cmd`) treats an unknown subcommand as non-error: it falls through to `Help()` and returns nil → exit 0. In a UserPromptSubmit hook this is **invisible** — the harness logs "hook success" and injects the whole help text into agent context every prompt. The 0.8.1 plugin's stale wiring of the retired `check-anchor-drift` caused exactly this for the entire session. -**Application**: Non-root cobra groups must have an explicit unknown-subcommand -guard. Two routes: (a) `Args: cobra.NoArgs` so unknown subcommands error loud -(non-zero exit + "unknown command" stderr); (b) a `RunE` that emits a **verbatim -relay** — which is what actually reaches the user in a UserPromptSubmit hook -context where a non-zero exit alone is invisible. Tracked under Phase CLI-FIX as -the verbatim-relay guard on `ctx system`. +**Application**: Non-root cobra groups must have an explicit unknown-subcommand guard. Two routes: (a) `Args: cobra.NoArgs` so unknown subcommands error loud (non-zero exit + "unknown command" stderr); (b) a `RunE` that emits a **verbatim relay** — which is what actually reaches the user in a UserPromptSubmit hook context where a non-zero exit alone is invisible. Tracked under Phase CLI-FIX as the verbatim-relay guard on `ctx system`. --- ## [2026-05-25-221357] Skill shipping location: _ctx- prefix is repo-internal, internal/assets/claude/skills/ctx-* is bundled and shipped -**Context**: Created /ctx-surface-audit under internal/assets/claude/skills/ -(the shipped path), but it audits ctx's own internal/ source layout — useless -in an end-user project that installs ctx. There is an established _ctx-* family -(_ctx-command-audit, _ctx-audit, _ctx-release, _ctx-qa, etc.) in .claude/skills/ -for repo-only dev skills; the user caught the misplacement. - -**Lesson**: A skill that references ctx's own source tree (internal/, -docs/recipes/, cmd/) or dev workflow is repo-internal and must live in -.claude/skills/_/ (underscore prefix, committed to the repo but NOT -bundled). Only genuinely user-facing skills belong in -internal/assets/claude/skills/, which ctx init / ctx setup install into end-user -projects. The same ship-vs-repo-internal question applies one layer up: -user-facing CLI commands go in ctx, maintainer commands go in ctxctl; shipped -hooks live in internal/assets/claude/hooks/hooks.json and call ctx, repo-local -dev hooks live in the gitignored .claude/settings.local.json and may call -ctxctl. - -**Application**: Before creating a skill, command, or hook, ask: does this serve -a user working in their project, or a ctx maintainer working in this repo? -Maintainer-facing → _-prefixed skill in .claude/skills/ + ctxctl command + -repo-local hook. User-facing → internal/assets/claude/skills/ + ctx command + -shipped hooks.json. Putting maintainer tooling in the shipped paths taxes every -end user (e.g. a UserPromptSubmit hook firing on every prompt for a feature they -never use). +**Context**: Created /ctx-surface-audit under internal/assets/claude/skills/ (the shipped path), but it audits ctx's own internal/ source layout — useless in an end-user project that installs ctx. There is an established _ctx-* family (_ctx-command-audit, _ctx-audit, _ctx-release, _ctx-qa, etc.) in .claude/skills/ for repo-only dev skills; the user caught the misplacement. + +**Lesson**: A skill that references ctx's own source tree (internal/, docs/recipes/, cmd/) or dev workflow is repo-internal and must live in .claude/skills/_/ (underscore prefix, committed to the repo but NOT bundled). Only genuinely user-facing skills belong in internal/assets/claude/skills/, which ctx init / ctx setup install into end-user projects. The same ship-vs-repo-internal question applies one layer up: user-facing CLI commands go in ctx, maintainer commands go in ctxctl; shipped hooks live in internal/assets/claude/hooks/hooks.json and call ctx, repo-local dev hooks live in the gitignored .claude/settings.local.json and may call ctxctl. + +**Application**: Before creating a skill, command, or hook, ask: does this serve a user working in their project, or a ctx maintainer working in this repo? Maintainer-facing → _-prefixed skill in .claude/skills/ + ctxctl command + repo-local hook. User-facing → internal/assets/claude/skills/ + ctx command + shipped hooks.json. Putting maintainer tooling in the shipped paths taxes every end user (e.g. a UserPromptSubmit hook firing on every prompt for a feature they never use). --- ## [2026-05-23-001000] Unicode block separation makes diacritic-stripping surgical — no per-script handling needed for Arabic/Indic/Hebrew/CJK -**Context**: While building `i18n.MatchKey` (commit 978582f5) for -diacritic-insensitive placeholder matching, the natural reflex was "this is -going to need per-script special cases — CJK doesn't have case, Arabic has -shadda/fatha that are meaning-changing, Bengali vowel signs are -script-essential, Hebrew niqqud distinguishes words." I sized the work assuming -we'd need a script-aware policy, possibly with a locale config or an opt-in flag -for "strip all combining marks" vs "strip only Latin-style decoration". -Empirical test across Turkish/German/French/Spanish/Catalan/Czech/Vietnamese -(should collapse) and Arabic/Bengali/Devanagari/Hindi/Hebrew/Chinese/Korean -(should preserve) showed the entire policy fits in one numeric range: -U+0300..U+036F. - -**Lesson**: Unicode pre-separated combining marks by intent at the codepoint -level. The "Combining Diacritical Marks" block (U+0300–U+036F) holds -Latin/general decorative marks: acute, grave, diaeresis, tilde, cedilla, caron, -the Turkish combining dot, the Vietnamese horn, etc. Script-essential marks live -in separate blocks per script: Arabic in U+0610–U+06ED, Bengali in -U+0980–U+09FF, Devanagari in U+0900–U+097F, Hebrew niqqud in -U+0591–U+05C7, and so on. The block boundaries are not coincidental — they -encode the same distinction a reasonable design would want to make. So a narrow -byte-range strip is exactly the right primitive: it expresses "remove -decoration, keep structural marks" in one comparison, without needing to know -anything about the input's script. - -**Application**: When designing comparison/normalization primitives for -international input, check the Unicode block boundaries before reaching for -per-script special cases or a config field. Often the standardization committee -already drew the line you want, and an arithmetic range check (`r >= 0x0300 && r -<= 0x036F`) does the work. Verify empirically across the scripts you care about -— but expect the answer to be cleaner than your initial sizing. The general -rule: when Unicode has put related characters in their own block, treat that -block as a meaningful unit of policy. (For ctx, this is now -`cfgI18n.CombiningMarksLatinStart`/`End` and the `MatchKey` implementation in -`internal/i18n/matchkey.go`.) +**Context**: While building `i18n.MatchKey` (commit 978582f5) for diacritic-insensitive placeholder matching, the natural reflex was "this is going to need per-script special cases — CJK doesn't have case, Arabic has shadda/fatha that are meaning-changing, Bengali vowel signs are script-essential, Hebrew niqqud distinguishes words." I sized the work assuming we'd need a script-aware policy, possibly with a locale config or an opt-in flag for "strip all combining marks" vs "strip only Latin-style decoration". Empirical test across Turkish/German/French/Spanish/Catalan/Czech/Vietnamese (should collapse) and Arabic/Bengali/Devanagari/Hindi/Hebrew/Chinese/Korean (should preserve) showed the entire policy fits in one numeric range: U+0300..U+036F. + +**Lesson**: Unicode pre-separated combining marks by intent at the codepoint level. The "Combining Diacritical Marks" block (U+0300–U+036F) holds Latin/general decorative marks: acute, grave, diaeresis, tilde, cedilla, caron, the Turkish combining dot, the Vietnamese horn, etc. Script-essential marks live in separate blocks per script: Arabic in U+0610–U+06ED, Bengali in U+0980–U+09FF, Devanagari in U+0900–U+097F, Hebrew niqqud in U+0591–U+05C7, and so on. The block boundaries are not coincidental — they encode the same distinction a reasonable design would want to make. So a narrow byte-range strip is exactly the right primitive: it expresses "remove decoration, keep structural marks" in one comparison, without needing to know anything about the input's script. + +**Application**: When designing comparison/normalization primitives for international input, check the Unicode block boundaries before reaching for per-script special cases or a config field. Often the standardization committee already drew the line you want, and an arithmetic range check (`r >= 0x0300 && r <= 0x036F`) does the work. Verify empirically across the scripts you care about — but expect the answer to be cleaner than your initial sizing. The general rule: when Unicode has put related characters in their own block, treat that block as a meaningful unit of policy. (For ctx, this is now `cfgI18n.CombiningMarksLatinStart`/`End` and the `MatchKey` implementation in `internal/i18n/matchkey.go`.) --- ## [2026-05-20-214839] macOS /var symlink trips path-equality; use EvalSymlinks with parent-resolution fallback -**Context**: TestRunInit_EnvCwdMatch_Succeeds in -internal/cli/initialize/init_test.go failed on first run despite a deliberate -setup where the env path and cwd candidate matched. Diagnosis: t.TempDir() -returns paths like /var/folders/..., os.Getwd() after t.Chdir() returns the -canonical /private/var/folders/... (because macOS's /var is a symlink to -/private/var). filepath.Clean preserves the symlink form; equality fails. +**Context**: TestRunInit_EnvCwdMatch_Succeeds in internal/cli/initialize/init_test.go failed on first run despite a deliberate setup where the env path and cwd candidate matched. Diagnosis: t.TempDir() returns paths like /var/folders/..., os.Getwd() after t.Chdir() returns the canonical /private/var/folders/... (because macOS's /var is a symlink to /private/var). filepath.Clean preserves the symlink form; equality fails. -**Lesson**: filepath.Clean alone is insufficient for path equality on macOS (and -other systems with symlinked top-level dirs). filepath.EvalSymlinks resolves the -symlinks but fails when the target path does not yet exist — common case for -/Users/volkan/Desktop/WORKSPACE/ctx/.context BEFORE ctx init runs. The right -pattern is a layered fallback: try EvalSymlinks(full), then EvalSymlinks(parent) -+ rejoin basename, then filepath.Clean as last resort. +**Lesson**: filepath.Clean alone is insufficient for path equality on macOS (and other systems with symlinked top-level dirs). filepath.EvalSymlinks resolves the symlinks but fails when the target path does not yet exist — common case for /Users/volkan/Desktop/WORKSPACE/ctx/.context BEFORE ctx init runs. The right pattern is a layered fallback: try EvalSymlinks(full), then EvalSymlinks(parent) + rejoin basename, then filepath.Clean as last resort. -**Application**: Encapsulated as -internal/cli/initialize/core/envmatch/{envmatch.go,internal.go}. The Same(a, b) -public function calls resolve() on each side; resolve() tries EvalSymlinks on -the full path, falls back to EvalSymlinks on the parent (rejoining the -basename), and falls through to filepath.Clean if both fail. Reusable for any -future env-vs-cwd-style equality check. The package is per-feature -(core/envmatch/) per the cmd/core/ purity rule enforced by -internal/compliance/TestCmdDirPurity. +**Application**: Encapsulated as internal/cli/initialize/core/envmatch/{envmatch.go,internal.go}. The Same(a, b) public function calls resolve() on each side; resolve() tries EvalSymlinks on the full path, falls back to EvalSymlinks on the parent (rejoining the basename), and falls through to filepath.Clean if both fail. Reusable for any future env-vs-cwd-style equality check. The package is per-feature (core/envmatch/) per the cmd/core/ purity rule enforced by internal/compliance/TestCmdDirPurity. --- ## [2026-05-20-214830] Handover filenames are archaeology; parse by generated-at, not filename -**Context**: User observed three coexisting handover filename shapes: -.context/HANDOVER-2026-04-22.md (pre-skill root file), -.context/handovers/YYYY-MM-DD-HHMMSS-slug.md (skill-era pre-CLI), -.context/handovers/-slug.md (current CLI). User asked whether -this was a regression or a skill-interpretation problem. +**Context**: User observed three coexisting handover filename shapes: .context/HANDOVER-2026-04-22.md (pre-skill root file), .context/handovers/YYYY-MM-DD-HHMMSS-slug.md (skill-era pre-CLI), .context/handovers/-slug.md (current CLI). User asked whether this was a regression or a skill-interpretation problem. -**Lesson**: Neither. The .context/HANDOVER-* root file predates the handovers/ -directory contract entirely (the body even said 'delete this file after -reading'). The YYYY-MM-DD-HHMMSS shape was an earlier skill iteration writing -free-form before ctx handover write existed (commit 60543e46, 2026-05-17, -introduced the CLI as sole writer per the anti-pattern note in /ctx-handover -SKILL.md). The current parser at internal/write/handover/parse.go:75-107 keys on -the 'generated-at' YAML frontmatter, not the filename — so legacy shapes still -sort correctly via LatestHandoverCursor. Only files without frontmatter (the -root April file) are invisible. +**Lesson**: Neither. The .context/HANDOVER-* root file predates the handovers/ directory contract entirely (the body even said 'delete this file after reading'). The YYYY-MM-DD-HHMMSS shape was an earlier skill iteration writing free-form before ctx handover write existed (commit 60543e46, 2026-05-17, introduced the CLI as sole writer per the anti-pattern note in /ctx-handover SKILL.md). The current parser at internal/write/handover/parse.go:75-107 keys on the 'generated-at' YAML frontmatter, not the filename — so legacy shapes still sort correctly via LatestHandoverCursor. Only files without frontmatter (the root April file) are invisible. -**Application**: When unifying filename shapes across history, use git mv to -preserve rename detection. Derive the canonical timestamp from the file's own -generated-at frontmatter rather than from the filename — that's the source of -truth the parser uses anyway. If a handover predates frontmatter entirely (rare, -pre-skill era), it's safe to delete because the parser never read it. +**Application**: When unifying filename shapes across history, use git mv to preserve rename detection. Derive the canonical timestamp from the file's own generated-at frontmatter rather than from the filename — that's the source of truth the parser uses anyway. If a handover predates frontmatter entirely (rare, pre-skill era), it's safe to delete because the parser never read it. --- ## [2026-05-20-214821] /ctx-plan is named after its input, not its output -**Context**: Agent (and apparently other agents in prior sessions per user -observation) repeatedly inverted the canonical chain, treating /ctx-spec as the -entry point and /ctx-plan as a post-spec step. The skill description starts -'stress-test a plan' (implying user brings a plan IN) while line 44 of the body -says 'the deliverable is a debated brief, not a task list' (the OUTPUT is a -brief, not a plan). - -**Lesson**: Skill names that reference their INPUT bias the agent toward the -wrong canonical position. The /ctx-plan skill takes a plan and produces a brief; -the natural mental model when scanning the name is 'plan = output', which makes -the agent place it AFTER spec instead of before. Also: /ctx-spec's 'When to Use' -section listed /ctx-brainstorm as a predecessor but never /ctx-plan, so an agent -skimming the top of the skill never learned the full chain. - -**Application**: Made the canonical chain explicit at the top of both /ctx-plan -and /ctx-spec skills (Canonical Chain block with the brainstorm → plan → -spec → implement diagram) and in AGENT_PLAYBOOK_GATE Planning Work section. -/ctx-spec When-to-Use now lists /ctx-plan as a predecessor; When-NOT-to-Use says -'when the bet is contested but not yet stress-tested, use /ctx-plan first'. -/ctx-plan description now ends with '; produces a debated brief at -.context/briefs/-.md that /ctx-spec --brief consumes'. +**Context**: Agent (and apparently other agents in prior sessions per user observation) repeatedly inverted the canonical chain, treating /ctx-spec as the entry point and /ctx-plan as a post-spec step. The skill description starts 'stress-test a plan' (implying user brings a plan IN) while line 44 of the body says 'the deliverable is a debated brief, not a task list' (the OUTPUT is a brief, not a plan). + +**Lesson**: Skill names that reference their INPUT bias the agent toward the wrong canonical position. The /ctx-plan skill takes a plan and produces a brief; the natural mental model when scanning the name is 'plan = output', which makes the agent place it AFTER spec instead of before. Also: /ctx-spec's 'When to Use' section listed /ctx-brainstorm as a predecessor but never /ctx-plan, so an agent skimming the top of the skill never learned the full chain. + +**Application**: Made the canonical chain explicit at the top of both /ctx-plan and /ctx-spec skills (Canonical Chain block with the brainstorm → plan → spec → implement diagram) and in AGENT_PLAYBOOK_GATE Planning Work section. /ctx-spec When-to-Use now lists /ctx-plan as a predecessor; When-NOT-to-Use says 'when the bet is contested but not yet stress-tested, use /ctx-plan first'. /ctx-plan description now ends with '; produces a debated brief at .context/briefs/-.md that /ctx-spec --brief consumes'. --- diff --git a/.context/TASKS.md b/.context/TASKS.md index 704521d89..f43f77667 100644 --- a/.context/TASKS.md +++ b/.context/TASKS.md @@ -32,6 +32,181 @@ TASK STATUS LABELS: `--phase` flag too, and we can have a auditor/normalizer for the current task document; or a skill that does a semantic pass, or both too. +## Phase AI-A: `ctx ai` Backend Foundation + +Spec: `specs/ctx-ai-backend.md`. Read the spec before starting any AI-A task. +Tracks GitHub issue #92. + +- [x] Decide the AI command CLI namespace: `ctx ai ` (new top-level) + vs. flags on existing commands (`--use-ai`, `--emit`, etc.). Record the + call as a `.context/DECISIONS.md` entry naming the chosen shape and the + rejected alternative with rationale. Blocks every other task in this group. + Spec: `specs/ctx-ai-backend.md` Open Question #1. #priority:medium + #added:2026-06-19 #completed:2026-06-19 + +- [x] Implement the backend contract and registry: new `internal/backend/` + package with `Backend` interface (`Name`, `Ping`, `Complete`), + `Request`/`Response` types, and a `Registry` (`Register`, `Resolve`, + `Default`). No per-backend implementations yet; this is the abstraction + surface that later tasks plug into. Unit tests cover single, multiple, + default, and missing backend resolution. Spec: `specs/ctx-ai-backend.md` + §Implementation. #priority:medium #added:2026-06-19 + #completed:2026-06-19 + Shipped: added `internal/backend/` with zero-value-safe registry, public + `SetDefault`, `Register`, `Resolve`, and `Default`; `Config`, `Request`, + `Response`, `Backend`, and `Factory` types; typed errors under + `internal/err/backend`; and structural error text constants under + `internal/config/backend`. Tests cover single default resolution, ambiguous + multiple-backend default, explicit default, missing default, empty registry, + missing backend, duplicate registration, and factory-error wrapping. Verified: + `go test ./internal/backend ./internal/err/backend ./internal/config/backend`, + `go test ./internal/audit`, and `git diff --check`. + +- [x] Extend `internal/rc/` to parse and validate the `.ctxrc` `backends:` + YAML mapping per the spec's Configuration section: per-backend `endpoint`, + `api_key_env`, `timeout`, `default_model`, plus optional + `backends.default`. Refuse malformed mappings with a clear parse error + naming the offending key. Add fixtures and round-trip tests. Spec: + `specs/ctx-ai-backend.md` §Configuration. #priority:medium + #added:2026-06-19 + #completed:2026-06-19 + Shipped: added `BackendsRC` / `BackendRC` parsing for mixed YAML mapping shape + (`backends.default` plus named backend definitions), strict backend-field + decoding, semantic validation for missing endpoint and default references, + and config constants for backend rc keys/messages. Multiple backends without a + default intentionally parse successfully because dispatch owns that error. + Tests cover well-formed config, missing endpoint, malformed shape, missing + default target, multiple without default, unknown nested fields, and empty + backends. Verified: `go test ./internal/rc ./internal/audit`, + `go test ./internal/backend ./internal/err/backend ./internal/config/backend`, + and `git diff --check`. + +- [x] Implement the minimum viable backend set: `vllm` (canonical local) and + generic `openai-compatible` (the contract floor) in + `internal/backend/vllm.go` and `internal/backend/openaicompat.go`. Both must + implement `Ping` (HTTP GET on `/v1/models`) and `Complete` (POST + `/v1/chat/completions`). Fail closed on unreachable, 4xx, 5xx, and timeout; + never retry with a different model and never fall back to deterministic + behavior. Spec: `specs/ctx-ai-backend.md` §Approach and §Edge Cases. + #priority:medium #added:2026-06-19 + #completed:2026-06-19 + Shipped: added generic OpenAI-compatible HTTP backend and vLLM wrapper over the + same contract. `Ping` calls `/v1/models`; `Complete` posts to + `/v1/chat/completions`, applies default model fallback / request model + override, optionally reads `api_key_env` for a bearer token, validates HTTP(S) + endpoints, uses configured timeout with a safe default, and fails closed on + transport, timeout, 4xx, 5xx, decode, and request errors. Tests cover ping, + completion, upstream body propagation, unreachable server, timeout, invalid + endpoint scheme, model fallback/override, auth header, and vLLM naming. Factory + functions remain private until a real cross-package caller lands, per the dead + export audit. Verified: `go test ./internal/backend ./internal/err/backend + ./internal/config/backend ./internal/rc ./internal/audit` and + `git diff --check`. + +- [x] Add the named-backend implementations: `openai`, `anthropic`, `ollama`, + `lmstudio` in `internal/backend/`. Each is a thin wrapper over + `openaicompat` with backend-specific defaults (endpoint, auth header shape, + env-var name). Anthropic uses the Messages API endpoint where supported but + inherits the OpenAI-compatible floor for `/v1/chat/completions`. Spec: + `specs/ctx-ai-backend.md` §Approach. #priority:medium #added:2026-06-19 + #completed:2026-06-19 + Shipped: added unexported named factories for `openai`, `anthropic`, `ollama`, + `lmstudio`, plus vLLM default endpoint handling. Each factory returns the + OpenAI-compatible implementation with backend-specific name, default endpoint, + and default API key env var where applicable. Anthropic is explicitly a floor + implementation for now; Messages API specialization waits for capability + detection. Factories remain private until real registry wiring lands to avoid + dead exports. Tests cover each factory's name/default behavior and preservation + of configured endpoint/env overrides. Verified: `go test ./internal/backend + ./internal/config/backend ./internal/err/backend ./internal/audit`, + `go test ./internal/rc`, and `git diff --check`. + +- [x] Extend the `ctx setup` family with `--backend ` as a distinct setup + mode that can run without the existing `` positional argument: + templates endpoint + auth wiring into `.ctxrc` and, where applicable, + downstream AI-tool configs (`ANTHROPIC_BASE_URL`, `OPENAI_BASE_URL`). Honour + existing env-var values: warn but do not overwrite. Lives in new + `internal/cli/setup/core/backend/` subpackage. Spec: + `specs/ctx-ai-backend.md` §Implementation. #priority:medium + #added:2026-06-19 + #completed:2026-06-19 + Shipped: `ctx setup --backend ` now runs without a positional tool, + supports dry-run YAML output, and writes/merges `.ctxrc` with `--write` while + preserving unrelated YAML fields. Added `--endpoint`, `--api-key-env`, + `--model`, and `--timeout` setup flags; backend name validation; backend mode + precedence when a positional tool is also present; default endpoint/env values; + and env-var conflict warnings. Tests cover no-arg backend mode, missing backend + rejection, existing tool compatibility, backend-mode precedence, unsupported + backend rejection, dry-run output, `.ctxrc` creation, unrelated-field + preservation, and env warning. Verified: `go test ./internal/cli/setup/... + ./internal/rc ./internal/backend ./internal/audit` and `git diff --check`. + +- [x] Build the `ctx ai` command surface. Minimum verbs: `ping` (reachability + + first model listed) plus `propose` as the Block A validation-only generic + proposer. All AI commands honour `--backend` flag (falling back to + `backends.default`), fail closed when no backend is configured, fail closed + when no backend is reachable, require explicit selection when multiple + backends are configured without a default, and surface upstream errors + verbatim. Spec: `specs/ctx-ai-backend.md` §Interface. #priority:medium + #added:2026-06-19 + #completed:2026-06-19 + Shipped: added the `ctx ai` command group with `ping` and `propose`, backend + dispatch through `.ctxrc` `backends:`, `--backend` selection, fail-closed empty + and ambiguous backend handling, built-in backend registration, and command / flag + assets. `ctx ai ping` reports the resolved backend, defaulted endpoint, and + first listed model from `/v1/models`. Verified: `go test ./internal/cli/ai/... + ./internal/backend ./internal/rc ./internal/audit ./internal/compliance` and + `git diff --check`. + +- [x] Add the deterministic-core boundary guard: a unit test or lint check that + fails if `internal/cli/agent/`, `internal/cli/status/`, or any + deterministic-ceremony hook imports or invokes `internal/backend/` or `ctx ai`. + This structurally enforces that `ctx status`, `ctx agent`, ceremonies, and + hooks remain additive-only and keep working with no backend configured. Spec: + `specs/ctx-ai-backend.md` §Validation Rules and §Testing. #priority:medium + #added:2026-06-19 + #completed:2026-06-19 + Shipped: added `internal/compliance/ai_boundary_test.go`, which scans + non-test Go files under `internal/cli/agent/`, `internal/cli/status/`, and + `internal/cli/hook/` and fails on `internal/backend` imports or `ctx ai` + invocation/documentation. Verified: `go test ./internal/compliance + ./internal/audit`. + +- [x] Ship the Block A validation consumer: `ctx ai propose --emit + decisions,learnings,tasks,open-questions`. This is a validation-only generic + proposer and must not foreclose later `ctx ai compact` or `ctx ai ingest` + command taxonomy. It performs schema-constrained dispatch through the backend, + validates JSON, and writes one proposed-patch JSON artifact to + `.context/proposals/ai/` with backend, model, input reference, emit kinds, + proposed rows, source spans/citations when available, and status metadata. + It must never directly mutate `.context/*.md`. Integration test confirms the + round-trip against a fake OpenAI-compatible `httptest` server and confirms + `.context/*.md` files are unchanged. Spec: `specs/ctx-ai-backend.md` §Testing + and Open Question #5. #priority:medium #added:2026-06-19 + #completed:2026-06-19 + Shipped: `ctx ai propose` reads a user input file, sends a schema-constrained + JSON request through the selected backend, validates the response as JSON, and + writes one proposed-patch artifact under `.context/proposals/ai/` with backend, + model, input reference, emit kinds, status, and decoded response payload. Tests + confirm the fake OpenAI-compatible round-trip and that `.context/*.md` remains + unchanged. Verified with the Phase 6 command-surface test set above. + +- [x] Write the documentation deliverables: one new recipe + (`docs/recipes/local-inference-with-vllm.md` or + `docs/recipes/ai-backend-setup.md`) covering the + `ctx setup --backend vllm` flow end-to-end, plus a CLI reference page under + `docs/cli/` for `ctx ai`. Also update command assets/examples and the agent + playbook note listed in the spec. The recipe is one file, not a recipe-surface + rework. Spec: `specs/ctx-ai-backend.md` §Non-Goals. #priority:medium + #added:2026-06-19 + #completed:2026-06-19 + Shipped: added `docs/cli/ai.md`, updated `docs/cli/setup.md`, added `ctx ai` + and `backends:` coverage to `docs/cli/index.md`, added + `docs/recipes/local-inference-with-vllm.md` and linked it from the recipes + index, and documented optional/fail-closed AI backend usage in + `.context/AGENT_PLAYBOOK.md`. Verified: `go test ./internal/audit + ./internal/compliance`. + ## Phase CLI-FIX: CLI Infrastructure Fixes These have priority because other knowledge ingestion projects depend on them. @@ -40,30 +215,25 @@ These have priority because other knowledge ingestion projects depend on them. `LEARNINGS.md`. When the `INDEX:START/END` block uses the dash-bullet format (what `ctx init` produces) rather than the pipe-table format, `ctx learning add` (1) rewrites the index as a table, (2) **duplicates** the - `` marker, and (3) **drops every existing learning body** - — + `` marker, and (3) **drops every existing learning body** — keeping only the newly added one. Observed live in `things-wtf-hub` (session aa32f065): a `LEARNINGS.md` with 4 bodies collapsed to 1 (a -44-line commit, 2dc4d1a); recovered via `git show :.context/LEARNINGS.md`. - `ctx decision add` is UNAFFECTED because that repo's `DECISIONS.md` was - already - table-format — so the bug is specifically the learning-add path's handling - of + `ctx decision add` is UNAFFECTED because that repo's `DECISIONS.md` was already + table-format — so the bug is specifically the learning-add path's handling of the dash-bullet index variant (likely it can't parse dash-bullet entries, so it treats the file as empty and regenerates from only the new entry). - Repro: `ctx init` a repo, confirm `LEARNINGS.md` index is dash-bullet (`- entry`), add 2+ learnings by hand in that format, then run - `ctx learning add "x" --context … --lesson … --application …`. - Expect: the + `ctx learning add "x" --context … --lesson … --application …`. Expect: the hand-authored bodies vanish + a duplicated INDEX:START marker. - Likely fix: detect the existing index format (dash-bullet vs table) and preserve it round-trip, OR parse dash-bullet entries before regenerating; never emit a second INDEX:START; never drop bodies the parser didn't recognize (fail loud instead of silently regenerating). - Guard: a round-trip test for BOTH index formats (dash-bullet + table) that - asserts existing bodies survive an add and exactly one marker pair - remains. -- Severity: HIGH — silent destruction of persisted memory, the one thing ctx + asserts existing bodies survive an add and exactly one marker pair remains. + - Severity: HIGH — silent destruction of persisted memory, the one thing ctx promises to protect; only git made it recoverable. - Provenance: things-wtf-hub session aa32f065 wrap-up; full write-up in that repo's LEARNINGS.md ("`ctx learning add` clobbers a dash-bullet-format @@ -74,15 +244,12 @@ These have priority because other knowledge ingestion projects depend on them. between the markers, or markers that are missing/duplicated/out-of-order. Wired into the two read-before-mutate choke points (`entry.Write` and `index.Reindex`), so add and all reindex commands fail loud and leave the - file byte-identical instead of clobbering it. `index.Update`'s signature - is - untouched (kept the CRITICAL blast radius stable). New - `internal/err/index` + file byte-identical instead of clobbering it. `index.Update`'s signature is + untouched (kept the CRITICAL blast radius stable). New `internal/err/index` package + i18n messages. Verified: the real repro now errors with the file unchanged; well-formed adds still preserve all bodies and one marker pair. Tests: `index.TestValidate` (7 shapes) + `entry` round-trip - (refused-untouched + well-formed-preserved). Chosen behavior is fail-loud - + + (refused-untouched + well-formed-preserved). Chosen behavior is fail-loud + manual fix; auto-repair (`reindex --repair`) considered and declined. Spec: specs/fix-learning-add-index-data-loss.md. @@ -135,16 +302,14 @@ These have priority because other knowledge ingestion projects depend on them. the ctx command's schema gates and INDEX:START/END maintenance. - Shape: `ctx decision add --json /path/to/payload.json` where the JSON is - `{"title":"…","context":"…","rationale":"…","consequence":"…"}`. - The flag + `{"title":"…","context":"…","rationale":"…","consequence":"…"}`. The flag supersedes individual content flags. Provenance (--session-id/--branch/--commit) can stay on the command line OR be folded into the JSON envelope ({" - provenance":{"session_id":"…","branch":"…","commit":"…"}}). - Complements + provenance":{"session_id":"…","branch":"…","commit":"…"}}). Complements the existing `--file` (which only replaces the title/body positional). -- Phase 2 (optional): array form `[{...},{...}]` for batch persists — useful + - Phase 2 (optional): array form `[{...},{...}]` for batch persists — useful for `/ctx-wrap-up` writing N decisions+learnings in one call instead of N separate invocations. - Mirror per command: same shape applies to `ctx learning add --json …` ( @@ -165,8 +330,7 @@ These have priority because other knowledge ingestion projects depend on them. `PressureSupported=false` → no memory alert. - Explore the Windows-native signal: Memory Resource Notifications API ( `CreateMemoryResourceNotification`/ - `QueryMemoryResourceNotification` → `LowMemoryResourceNotification`), - perf + `QueryMemoryResourceNotification` → `LowMemoryResourceNotification`), perf counters (`Memory\Available MBytes`, `Committed Bytes`/`Commit Limit`), or `GlobalMemoryStatusEx.dwMemoryLoad`. - Open question: Windows aggressively manages working-set/commit and @@ -206,15 +370,14 @@ These have priority because other knowledge ingestion projects depend on them. half-migrated package must not ship again. Pairs with the verbatim-relay guard task above — that one makes a future skew fail LOUD; this one closes the current gap. -- #in-progress 2026-05-28 (branch feat/hooks-wiring-guard, session 0066d49b): + - #in-progress 2026-05-28 (branch feat/hooks-wiring-guard, session 0066d49b): Recurrence guard SHIPPED — `TestShippedHooksResolveToRegisteredCommands` in internal/compliance walks every `ctx <…>` invocation in the shipped hooks.json against the assembled cobra tree; a wired-but-unregistered verb fails `go test`. Proven both ways (passes clean, fails on a reintroduced `check-anchor-drift`). Spec: specs/hooks-wiring-guard.md. Implemented as a Go test, not a hack/release.sh step (cross-platform, no bash, runs in CI). - STILL OPEN: the live fix — cut/republish a release where plugin - hooks.json + STILL OPEN: the live fix — cut/republish a release where plugin hooks.json and binary share a post-fc7db228 commit, then reinstall for skewed users (a tag+publish action, maintainer-owned). CORRECTION to the Fix bullet above: shipped hooks must NOT "include @@ -241,8 +404,7 @@ These have priority because other knowledge ingestion projects depend on them. cobra `legacyArgs` only raises "unknown command" for the ROOT command, never a non-root group). In a UserPromptSubmit hook a non-zero exit alone is - swallowed by the harness — "loud via exit code" is dead in the water; - the + swallowed by the harness — "loud via exit code" is dead in the water; the user never sees it. - Fix: route unknown `ctx system` subcommands through the existing nudge/verbatim-relay path (same mechanism the @@ -268,35 +430,27 @@ These have priority because other knowledge ingestion projects depend on them. Approach used: add a RunE on system.Cmd() only (legacyArgs lets the leftover args reach the group's RunE for non-root); on unknown verb emit a message.NudgeBox to stdout, set SilenceUsage (else cobra re-dumps the help - we're killing), exit non-zero. system is Hidden so RootCmd - PersistentPreRunE + we're killing), exit non-zero. system is Hidden so RootCmd PersistentPreRunE early-returns — no context/git preconditions. Decisions settled with user: (1) DO fire the event-log + webhook relay leg (nudge.Relay), gated on a real session ID read best-effort from stdin via - session.ReadID (TTY-safe, timeout-guarded → IDUnknown means skip the - leg); + session.ReadID (TTY-safe, timeout-guarded → IDUnknown means skip the leg); (2) scoped to ctx system only, parent.Cmd untouched. - Follow-up surfaced: ctx hook (and any parent.Cmd group) has the same - latent - exit-0-on-unknown behavior — not wired into hooks.json so out of scope - here; + Follow-up surfaced: ctx hook (and any parent.Cmd group) has the same latent + exit-0-on-unknown behavior — not wired into hooks.json so out of scope here; capture as its own task if it ever gets hook-wired. - [x] Generalize the unknown-subcommand guard beyond `ctx system` (deferred from the #5 work above). `ctx hook` and any future `parent.Cmd` group still print - help + exit 0 on an unknown subcommand — the same latent pollution #5 fixed - for + help + exit 0 on an unknown subcommand — the same latent pollution #5 fixed for `ctx system`. Low priority while no other group is wired into hooks.json; the build-time wiring guard (specs/hooks-wiring-guard.md) only checks `ctx system` - + `ctx agent` today. If a `ctx hook ` ever gets hook-wired, either - extend + + `ctx agent` today. If a `ctx hook ` ever gets hook-wired, either extend the guard's coverage or fold a reusable opt-in into `parent.Cmd` (an optional unknown-subcommand handler groups opt into). #priority:low #added:2026-05-28 DONE 2026-05-30 (branch feat/add-json-file-ingest, session 53db2521). - Rationale refined: the real justification is not the every-prompt - amplification - (unique to hooks.json-wired groups) but making CLI drift LOUD — `ctx hook` - is + Rationale refined: the real justification is not the every-prompt amplification + (unique to hooks.json-wired groups) but making CLI drift LOUD — `ctx hook` is consumed by name from skills/loops (`ctx hook notify|event|pause|...`), and a drifted verb silently returns help+exit-0 (agent misreads; for `notify` the human is never told). Lifted the handler from `system/core/unknown` into a @@ -305,8 +459,7 @@ These have priority because other knowledge ingestion projects depend on them. user-facing (not Hidden) and previously rode the no-RunE PreRunE exemption, so it needed AnnotationSkipInit to stay reachable without an initialized context/git (bootstrap regression test added). Did NOT fold into `parent.Cmd` - (would widen every group's deps). Skill/loop `ctx hook ` build-time - guard + (would widen every group's deps). Skill/loop `ctx hook ` build-time guard left out of scope. Spec: specs/unknown-subcommand-relay-generalization.md. ## Important @@ -465,18 +618,7 @@ Important things that agent (or human) yeeted to the future. ### Phase CT: Companion Tool Integration -- [ ] Add a 'make strip-gitnexus' target (backed by a hack/ script) that - mechanically removes the GitNexus auto-injected block — delimited by / markers — from AGENTS.md and - CLAUDE.md. Marker-bounded delete (sed range or awk between markers). Must: (1) - leave AGENTS.md as the redirect stub and CLAUDE.md ending at its Companion - Tools / GITNEXUS.md pointer; (2) NOT touch GITNEXUS.md (the intended managed - home for that content); (3) be idempotent (no-op when markers absent). Run it - after 'npx gitnexus analyze'. Upstream-preferred guard is 'analyze - --skip-agents-md'; this script is the belt-and-suspenders cleanup when analyze - runs without that flag. Manual removal was done in 8da165a3; this automates - it. #priority:medium #session:74c94e3a #branch:fix/notify-resolution-hardening - #commit:8da165a3 #added:2026-06-02-085625 +- [ ] Add a 'make strip-gitnexus' target (backed by a hack/ script) that mechanically removes the GitNexus auto-injected block — delimited by / markers — from AGENTS.md and CLAUDE.md. Marker-bounded delete (sed range or awk between markers). Must: (1) leave AGENTS.md as the redirect stub and CLAUDE.md ending at its Companion Tools / GITNEXUS.md pointer; (2) NOT touch GITNEXUS.md (the intended managed home for that content); (3) be idempotent (no-op when markers absent). Run it after 'npx gitnexus analyze'. Upstream-preferred guard is 'analyze --skip-agents-md'; this script is the belt-and-suspenders cleanup when analyze runs without that flag. Manual removal was done in 8da165a3; this automates it. #priority:medium #session:74c94e3a #branch:fix/notify-resolution-hardening #commit:8da165a3 #added:2026-06-02-085625 Session-start checks, suppressibility, and registry for companion MCP tools. @@ -2112,8 +2254,7 @@ adjacent tool joins the list. two artifacts: - **Time-series** at `~/.ctx/state/skill-usage.jsonl`: append-only, one row per invocation, fields - `{ts, project, session_id, skill_name, source: - "claude-code"|"opencode"|...}`. + `{ts, project, session_id, skill_name, source: "claude-code"|"opencode"|...}`. - **Aggregate** at `~/.ctx/state/skill-usage.json`: derived rollup, `{skill_name → {count, first_used, last_used, projects[]}}`. Stays in `~/.ctx/state/` (user-global), not per-project, so @@ -2223,8 +2364,7 @@ the zensical shell-out pattern (recommended). journal-corpus semantic recall (`ctx journal search ""` shape). ### Phase EVA: -`ctx kb ev append` helper — eliminate Edit-anchor brittleness for append-only -structured rows +`ctx kb ev append` helper — eliminate Edit-anchor brittleness for append-only structured rows `#priority:medium #added:2026-05-23` @@ -2407,121 +2547,34 @@ DR-kb session a5736210 closeouts under ### Phase CLI-FIX: CLI Infrastructure Fixes -- [ ] Reindex grouped-emit (ctx-side): RenderBlock should emit the CTX:KB:TOPICS - managed block grouped by parent folder (### headings) instead of one - flat sorted list, for grouped kbs like things-wtf-dr (49 topics). ListTopics - already returns slashed group/slug slugs (PR #106, spec - specs/kb-reindex-nesting.md) so only RenderBlock + the consumer-facing - block-format contract change; must still handle ungrouped/flat top-level - topics. Deferred from the kb-reindex fix (managed-block format change). - #priority:high active dependent work in the hub/other workstream; natural - owner is ctx-side (ListTopics already recursive). #session:cf14dd25 - #branch:main #commit:aae42fe8 #added:2026-05-28-215308 +- [ ] Reindex grouped-emit (ctx-side): RenderBlock should emit the CTX:KB:TOPICS managed block grouped by parent folder (### headings) instead of one flat sorted list, for grouped kbs like things-wtf-dr (49 topics). ListTopics already returns slashed group/slug slugs (PR #106, spec specs/kb-reindex-nesting.md) so only RenderBlock + the consumer-facing block-format contract change; must still handle ungrouped/flat top-level topics. Deferred from the kb-reindex fix (managed-block format change). #priority:high active dependent work in the hub/other workstream; natural owner is ctx-side (ListTopics already recursive). #session:cf14dd25 #branch:main #commit:aae42fe8 #added:2026-05-28-215308 ### ctx-dream v1 > **STATUS (2026-06-20): NOT DONE.** The dream→serendipity *engine* has landed -> (triage, review CLI, executor contract, enablement docs — all `[x]` below), -but -> the workstream is incomplete. **Next up: the end-user dream UX loop** (the -first -> `[ ]` task) — making `ctx dream` a clean run→digest experience and wiring -the +> (triage, review CLI, executor contract, enablement docs — all `[x]` below), but +> the workstream is incomplete. **Next up: the end-user dream UX loop** (the first +> `[ ]` task) — making `ctx dream` a clean run→digest experience and wiring the > serendipity nag. The `dream-guard` consolidation is the second open item. > Baseline is intentionally being frozen here for a controlled snapshot-VM -> experiment (SDD / spec-kit alignment); do not assume this phase is -shipped. - -- [ ] Close the end-user dream UX loop: invoking /ctx-dream interactively is a - debug-crawl, not a dream. (1) Reconsider de-listing /ctx-dream as a - user-invocable slash-command — it's the headless executor's instruction set, - not a user command; the user surfaces are 'ctx dream' (on-demand) + cron + - /ctx-serendipity. (2) Make 'ctx dream' a clean run->digest experience for the - terminal user. (3) Wire the 'ctx remind' nag ('a serendipity round is - waiting') so dream->nag->review closes without the user watching a pass. - #priority:high #session:2263caef #branch:main #commit:a1624af5 - #added:2026-06-07-142015 - -- [ ] Replace skills/ctx-dream/guard.sh with a 'ctx system dream-guard' - subcommand (convention: hook scripts are ctx system subcommands — cf. - block-non-path-ctx). It reads the PreToolUse tool-call JSON on stdin and - applies internal/dream.WriteScope + Leak as the SINGLE source of truth - (eliminating the current Go-vs-shell guard duplication/drift), emitting the - hook block decision. Then rewire the PreToolUse settings in - docs/recipes/run-the-dream.md and docs/reference/dream-executor-contract.md to - call 'ctx system dream-guard', and delete guard.sh. #priority:medium - #session:2263caef #branch:main #commit:a1624af5 #added:2026-06-07-140456 - -- [x] Docs: executor-contract reference for non-Claude-Code harnesses — - bounded pass, structural guard enforcement, fail-loud, - proposals-only-into-dreams/ #priority:medium #session:2263caef - #branch:fix/notify-resolution-hardening #commit:ef59aeea - #added:2026-06-07-112233 - -- [x] Docs: Claude Code dream enablement guide — opt-in (.ctxrc - dream.enabled), cron entry, guard hook wiring, ctx remind cadence - #priority:medium #session:2263caef #branch:fix/notify-resolution-hardening - #commit:ef59aeea #added:2026-06-07-112233 - -- [x] Tests: git check-ignore guard refuses tracked path; ledger - dedup-against-seen; crash-resume; 2605.12978 corrupted-artifact regression - fixture #priority:medium #session:977ff594 - #branch:fix/notify-resolution-hardening #commit:03a24cf0 - #added:2026-06-06-162238 - -- [x] Build ctx dream review CLI (accept/reject/amend) plus serendipity skill; - mechanical applies instantly, generative drops to agent; backup-before-mutate; - ctx remind cadence #priority:medium #session:977ff594 - #branch:fix/notify-resolution-hardening #commit:03a24cf0 - #added:2026-06-06-162238 - -- [x] Implement disciplined ideas triage: classify, ground against code and - specs, semantic dedup; emit atomic provenanced proposals #priority:medium - #session:977ff594 #branch:fix/notify-resolution-hardening #commit:03a24cf0 - #added:2026-06-06-162238 - -- [x] Build proposal/ledger/state machinery: per-source state record, - append-only ledger recording rejections, two-clocks read model #priority:high - #session:977ff594 #branch:fix/notify-resolution-hardening #commit:03a24cf0 - #added:2026-06-06-162238 - -- [x] Build the three structural guards: write-scope, sources-as-data, dont-leak - (git check-ignore refuses tracked paths) #priority:high #session:977ff594 - #branch:fix/notify-resolution-hardening #commit:03a24cf0 - #added:2026-06-06-162238 - -- [x] Settle executor: cron claude -p bounded scheduled pass; safety invariants - structural not prompt-level #priority:high #session:977ff594 - #branch:fix/notify-resolution-hardening #commit:03a24cf0 - #added:2026-06-06-162238 - -### Misc - -- [x] Implement ctx system statusline per specs/statusline.md: stdin-JSON render (model, ctx%, cost), .ctxrc statusline block, setup merge with backup/restore. Informational only; no gating (spec records why) #priority:medium #session:a31b3e67 #branch:main #commit:687bbd59 #added:2026-07-04-140249 - -- [x] Companion-tool feature-delta analysis; borrow/skip verdicts recorded in gitignored inbox/ notes (local only) #session:a31b3e67 #branch:main #commit:687bbd59 #added:2026-07-04-135227 - -- [x] Add ctx-humanize plugin skill (SKILL.md + references/pattern-catalog.md, docs entry) with progressive disclosure and voice guardrails. Spec: specs/ctx-humanize.md #session:a31b3e67 #branch:main #commit:687bbd59 #added:2026-07-04-134612 - -- [x] Add hack/check-tools.sh tooling dependency checker (manifest: hack/tool-versions.txt, make check-tools) — spec: specs/check-tools.md #session:a31b3e67 #branch:main #commit:687bbd59 #added:2026-07-04-132852 - -- [ ] Recipe: the full design-to-implementation pipeline from the operator's seat (new 'spec-driven-development.md' or a major fold into design-before-coding.md). Must cover, for a newcomer with zero tribal knowledge: (1) the 5-step chain INCLUDING /ctx-plan — design-before-coding.md's TL;DR currently omits the debated-brief step entirely; (2) altitude: the bet is debated once and the spec covers ALL milestones — briefs are per-bet, never per-milestone; (3) plans are just-in-time per milestone behind the rolling-wave gate (tasking distant milestones produces fiction); (4) blocking-TBD gates as the replacement for per-milestone debates — each task-out run forces exactly the decisions that milestone embeds, into DECISIONS.md; (5) two surfaces, one truth: plan = execution ledger (st column), TASKS.md epics = one-way projections over disjoint id ranges; DoD is measurement/Board-confirmed, never derived; (6) when a NEW brief happens: new bet (e.g. deferred machinery returning) or evidence falsifying the committed bet — never relitigating from below; (7) a worked multi-milestone example, not a one-session feature. Origin: zhc/os session a63353a3 (2026-07-03) — the operator had to reverse-engineer all seven from skill texts and agent explanations #priority:high #session:a63353a3 #branch:main #commit:511a609a #added:2026-07-03-232251 - -- [ ] Tighten /ctx-spec (and /ctx-implement) skills to bake in spec-kit's one - good discipline without adopting spec-kit: every /ctx-spec must end with (a) - explicit, testable acceptance criteria and (b) a derived, dependency-ordered - task breakdown into TASKS.md; and the spec is FROZEN once /ctx-implement - begins — changes go through a new decision record, not a silent edit. - Rationale + full ctx-vs-spec-kit analysis in - inbox/2026-06-27-ctx-vs-spec-kit-sdd-analysis.md (keep ctx's edge: persistent - memory + adversarial /ctx-plan; avoid two-constitutions double-bookkeeping). - #priority:medium #session:210b77dd #branch:main #commit:6b0d0107 - #added:2026-06-27-222130 - -### Future - -- [ ] Hub curation: immutable promotion ledger (who accepted what, when, why) + mechanical validate floor for shared knowledge; revisit when ctx hub grows team-curation workflows #priority:low #session:a31b3e67 #branch:main #commit:d800734c #added:2026-07-04-153004 - -- [ ] ctx-spec-views skill: manager-facing read-models (execution plan, spec briefs, task breakdowns) generated FROM specs/, never source of truth; spec it when someone actually needs the leadership view #priority:low #session:a31b3e67 #branch:main #commit:d800734c #added:2026-07-04-153004 - -- [ ] KB convention: pinned upstream corpus for grounding — document a snapshot mode (dated local copy of high-churn upstream docs as the citable byte-stream) in KB rules; no code needed #priority:low #session:a31b3e67 #branch:main #commit:d800734c #added:2026-07-04-153004 +> experiment (anchor SDD / spec-kit alignment); do not assume this phase is shipped. + +- [ ] Close the end-user dream UX loop: invoking /ctx-dream interactively is a debug-crawl, not a dream. (1) Reconsider de-listing /ctx-dream as a user-invocable slash-command — it's the headless executor's instruction set, not a user command; the user surfaces are 'ctx dream' (on-demand) + cron + /ctx-serendipity. (2) Make 'ctx dream' a clean run->digest experience for the terminal user. (3) Wire the 'ctx remind' nag ('a serendipity round is waiting') so dream->nag->review closes without the user watching a pass. #priority:high #session:2263caef #branch:main #commit:a1624af5 #added:2026-06-07-142015 + +- [ ] Replace skills/ctx-dream/guard.sh with a 'ctx system dream-guard' subcommand (convention: hook scripts are ctx system subcommands — cf. block-non-path-ctx). It reads the PreToolUse tool-call JSON on stdin and applies internal/dream.WriteScope + Leak as the SINGLE source of truth (eliminating the current Go-vs-shell guard duplication/drift), emitting the hook block decision. Then rewire the PreToolUse settings in docs/recipes/run-the-dream.md and docs/reference/dream-executor-contract.md to call 'ctx system dream-guard', and delete guard.sh. #priority:medium #session:2263caef #branch:main #commit:a1624af5 #added:2026-06-07-140456 + +- [x] Docs: executor-contract reference for non-Claude-Code harnesses — bounded pass, structural guard enforcement, fail-loud, proposals-only-into-dreams/ #priority:medium #session:2263caef #branch:fix/notify-resolution-hardening #commit:ef59aeea #added:2026-06-07-112233 + +- [x] Docs: Claude Code dream enablement guide — opt-in (.ctxrc dream.enabled), cron entry, guard hook wiring, ctx remind cadence #priority:medium #session:2263caef #branch:fix/notify-resolution-hardening #commit:ef59aeea #added:2026-06-07-112233 + +- [x] Tests: git check-ignore guard refuses tracked path; ledger dedup-against-seen; crash-resume; 2605.12978 corrupted-artifact regression fixture #priority:medium #session:977ff594 #branch:fix/notify-resolution-hardening #commit:03a24cf0 #added:2026-06-06-162238 + +- [x] Build ctx dream review CLI (accept/reject/amend) plus serendipity skill; mechanical applies instantly, generative drops to agent; backup-before-mutate; ctx remind cadence #priority:medium #session:977ff594 #branch:fix/notify-resolution-hardening #commit:03a24cf0 #added:2026-06-06-162238 + +- [x] Implement disciplined ideas triage: classify, ground against code and specs, semantic dedup; emit atomic provenanced proposals #priority:medium #session:977ff594 #branch:fix/notify-resolution-hardening #commit:03a24cf0 #added:2026-06-06-162238 + +- [x] Build proposal/ledger/state machinery: per-source state record, append-only ledger recording rejections, two-clocks read model #priority:high #session:977ff594 #branch:fix/notify-resolution-hardening #commit:03a24cf0 #added:2026-06-06-162238 + +- [x] Build the three structural guards: write-scope, sources-as-data, dont-leak (git check-ignore refuses tracked paths) #priority:high #session:977ff594 #branch:fix/notify-resolution-hardening #commit:03a24cf0 #added:2026-06-06-162238 + +- [x] Settle executor: cron claude -p bounded scheduled pass; safety invariants structural not prompt-level #priority:high #session:977ff594 #branch:fix/notify-resolution-hardening #commit:03a24cf0 #added:2026-06-06-162238 diff --git a/.gitignore b/.gitignore index 329e0b5e7..7865d1570 100644 --- a/.gitignore +++ b/.gitignore @@ -89,8 +89,6 @@ tools/typecheck/opencode/node_modules/ # Some ideas are best kept hidden. ideas -inbox -outbox # The dream's notebook about ideas/ — derived summaries, per-source # state, ledger, per-run digests, and pre-mutation backups. Inherits # ideas/'s privacy class; the don't-leak guard double-checks at write @@ -105,6 +103,3 @@ dreams # Generated skills .claude/skills/generated .claude/skills/gitnexus - -# GitNexus code-graph index (local, do not commit) -.gitnexus/ diff --git a/.golangci.yml b/.golangci.yml index 78eaf855f..311985090 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -38,6 +38,22 @@ linters: - linters: [gosec] text: "G101" path: "internal/config/embed/text/" + # FlagDescKey constants are CLI flag description keys, not credentials + - linters: [gosec] + text: "G101" + path: "internal/config/embed/flag/" + # Flag name constants are CLI flag identifiers, not credentials + - linters: [gosec] + text: "G101" + path: "internal/config/flag/" + # RC key constants are YAML config key names, not credentials + - linters: [gosec] + text: "G101" + path: "internal/config/rc/" + # Default env var name constants are identifiers, not credentials + - linters: [gosec] + text: "G101" + path: "internal/config/backend/" run: timeout: 5m diff --git a/Makefile b/Makefile index ba0006906..6681813df 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ .PHONY: build ctxctl test vet fmt fmt-context lint lint-style lint-drift lint-shellcheck lint-powershell \ clean all release build-all help \ test-coverage smoke site site-feed site-serve site-serve-lan site-setup audit check plugin-reload \ -journal journal-serve journal-serve-lan gpg-fix gpg-test register-mcp reinstall check-tools \ +journal journal-serve journal-serve-lan gpg-fix gpg-test register-mcp reinstall \ sync-version check-version-sync sync-why check-why sync-copilot-skills check-copilot-skills sync-steering check-steering gemini-search \ gitnexus-version gitnexus-update install-ctxctl reinstall-ctxctl @@ -276,10 +276,6 @@ gpg-fix: gpg-test: ./hack/gpg-fix.sh --test -## check-tools: Verify tooling dependency versions (Go, Node, GitNexus, MCP servers, ...) -check-tools: - @./hack/check-tools.sh - ## register-mcp: Register all MCP servers (gemini-search, gitnexus) with Claude Code register-mcp: @./hack/register-gemini-search.sh diff --git a/README.md b/README.md index 53296e8b0..e9a364578 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ vendor lock-in. `ctx` is infrastructure for preserving intent under scale. Without durable context, intelligence resets. With `ctx`, creation compounds. -Read the full **[Manifesto](MANIFESTO.md)** | **[ctx.ist](https://ctx.ist/)** +Read the full **[Manifesto](MANIFESTO.md)** | **[ctx.ist/manifesto](https://ctx.ist/manifesto/)** ## The Thesis @@ -36,7 +36,7 @@ Read the full **[Thesis](https://ctx.ist/thesis/)** | Document | Context | |-------------------------------------------------------------------|-----------------------------------------------------| -| [Manifesto](https://ctx.ist/) | Philosophy: creation, context, verification | +| [Manifesto](https://ctx.ist/manifesto/) | Philosophy: creation, context, verification | | [The Thesis](https://ctx.ist/thesis/) | Whitepaper: context as deterministic state | | [Design Invariants](https://ctx.ist/reference/design-invariants/) | System properties that must always hold | | [Tool Comparison](https://ctx.ist/reference/comparison/) | How `ctx` differs from .cursorrules, Aider, Copilot | @@ -165,9 +165,9 @@ recipes are the right next stop. |-------------------------------------------------|----------------------------------------| | [Getting Started](https://ctx.ist) | Installation, quick start, first steps | | [Recipes](https://ctx.ist/recipes/) | Practical workflow guides | -| [CLI Reference](https://ctx.ist/cli/) | All commands and options | -| [Context Files](https://ctx.ist/home/context-files/) | File formats and structure | -| [Integrations](https://ctx.ist/operations/integrations/) | Claude Code, Cursor, Aider setup | +| [CLI Reference](https://ctx.ist/cli-reference/) | All commands and options | +| [Context Files](https://ctx.ist/context-files/) | File formats and structure | +| [Integrations](https://ctx.ist/integrations/) | Claude Code, Cursor, Aider setup | | [Operations](https://ctx.ist/operations/) | Runbooks, day-to-day, hub deployment | | [Security](https://ctx.ist/security/) | Trust model, audit trail, permissions | diff --git a/ctx-desktop/package-lock.json b/ctx-desktop/package-lock.json index 90527b361..1690ef220 100644 --- a/ctx-desktop/package-lock.json +++ b/ctx-desktop/package-lock.json @@ -22,7 +22,7 @@ "@vitejs/plugin-react": "^4.6.0", "tailwindcss": "^4.3.0", "typescript": "~5.8.3", - "vite": "^7.3.6" + "vite": "^7.0.4" } }, "node_modules/@babel/code-frame": { @@ -1379,72 +1379,6 @@ "node": ">=14.0.0" } }, - "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { - "version": "1.10.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { - "version": "1.10.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { - "version": "2.8.1", - "dev": true, - "inBundle": true, - "license": "0BSD", - "optional": true - }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz", @@ -2660,13 +2594,13 @@ } }, "node_modules/vite": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", - "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.3.tgz", + "integrity": "sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.27.0 || ^0.28.0", + "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", diff --git a/ctx-desktop/package.json b/ctx-desktop/package.json index 568d405a7..ee35c459b 100644 --- a/ctx-desktop/package.json +++ b/ctx-desktop/package.json @@ -24,6 +24,6 @@ "@vitejs/plugin-react": "^4.6.0", "tailwindcss": "^4.3.0", "typescript": "~5.8.3", - "vite": "^7.3.6" + "vite": "^7.0.4" } } diff --git a/docs/blog/2026-01-27-building-ctx-using-ctx.md b/docs/blog/2026-01-27-building-ctx-using-ctx.md index 5237c015d..b7ee3c4bb 100644 --- a/docs/blog/2026-01-27-building-ctx-using-ctx.md +++ b/docs/blog/2026-01-27-building-ctx-using-ctx.md @@ -82,7 +82,7 @@ The core idea was simple: [**Ralph Loop**][ralph] (*An iterative AI development workflow*) had produced a working CLI: -[ralph]: https://ctx.ist/operations/autonomous-loop/ "Autonomous Loop" +[ralph]: https://ctx.ist/autonomous-loop/ "Autonomous Loop" ``` feat(cli): implement amem init command diff --git a/docs/blog/2026-02-01-ctx-v0.2.0-the-archaeology-release.md b/docs/blog/2026-02-01-ctx-v0.2.0-the-archaeology-release.md index eb9c40f6c..11f4043b1 100644 --- a/docs/blog/2026-02-01-ctx-v0.2.0-the-archaeology-release.md +++ b/docs/blog/2026-02-01-ctx-v0.2.0-the-archaeology-release.md @@ -264,7 +264,7 @@ The same structure serves two very different readers. ## The Configuration: `.contextrc` [Projects can now customize `ctx` behavior -via `.contextrc`](../home/configuration.md). +via `.contextrc`](../cli/system.md#contextrc). This makes `ctx` usable in real teams, not just personal projects. diff --git a/docs/blog/2026-02-15-why-zensical.md b/docs/blog/2026-02-15-why-zensical.md index 1730016a7..b52852fde 100644 --- a/docs/blog/2026-02-15-why-zensical.md +++ b/docs/blog/2026-02-15-why-zensical.md @@ -222,7 +222,7 @@ We discovered this firsthand: `pip install zensical` often fails on MacOS with the correct Python version automatically. That kind of friction is typical for young Python tooling, and it is documented -in the [Common Workflows guide](../home/common-workflows.md#journal-site). +in the [Getting Started guide](../home/getting-started.md#journal-site). And `3,000` stars at `v0.0.21` is **strong** early traction, but it's still **early**: The community is small. When something breaks, you're reading diff --git a/docs/cli/ai.md b/docs/cli/ai.md new file mode 100644 index 000000000..a1ec37337 --- /dev/null +++ b/docs/cli/ai.md @@ -0,0 +1,58 @@ +--- +# / ctx: https://ctx.ist +# ,'`./ do you remember? +# `.,'\ +# \ Copyright 2026-present Context contributors. +# SPDX-License-Identifier: Apache-2.0 + +title: AI Backends +icon: lucide/brain-circuit +--- + +![ctx](../images/ctx-banner.png) + +## `ctx ai` + +Optional AI backend commands. These commands are additive: deterministic +commands such as `ctx status`, `ctx agent`, and hooks do not require a backend. + +Configure a backend first: + +```bash +ctx setup --backend vllm --endpoint http://localhost:8000 --write +``` + +### `ctx ai ping` + +Check the selected backend by reading `/v1/models`. + +```bash +ctx ai ping [--backend ] +``` + +Output includes the resolved backend name, endpoint, and first model listed. + +### `ctx ai propose` + +Send an input file to the selected backend and write a reviewable proposal +artifact. It never edits `.context/*.md` directly. + +```bash +ctx ai propose --emit decisions,learnings,tasks,open-questions \ + [--backend ] +``` + +Artifacts are written under `.context/proposals/ai/` as JSON proposed-patch +records with backend, model, input, emit kinds, status, and the decoded response. + +### Backend selection + +`ctx ai` uses this order: + +1. `--backend ` +2. `.ctxrc` `backends.default` +3. the only configured backend, if exactly one exists + +If multiple backends exist and none is selected, the command fails closed. +If no backend is configured or the backend is unreachable, the command fails +closed; non-AI commands are unaffected. diff --git a/docs/cli/hub.md b/docs/cli/hub.md index 5f071347c..e8e0dc6fa 100644 --- a/docs/cli/hub.md +++ b/docs/cli/hub.md @@ -41,7 +41,7 @@ ctx hub start --data-dir /srv/ctx-hub # Custom data directory On first run, generates an **admin token** and prints it to stdout. Save this token; it's required for -[`ctx connection register`](connection.md#ctx-connection-register) in +[`ctx connection register`](connection.md#ctx-connect-register) in client projects. Subsequent runs reuse the stored token from `/admin.token`. diff --git a/docs/cli/index.md b/docs/cli/index.md index 5a9cf2ff2..2959546ae 100644 --- a/docs/cli/index.md +++ b/docs/cli/index.md @@ -54,8 +54,8 @@ have been initialized by `ctx init` (otherwise commands return | Command | Description | |-----------------------------------------------|----------------------------------------------------------| -| [`ctx load`](init-status.md#ctx-load) | Output assembled context in read order | -| [`ctx agent`](init-status.md#ctx-agent) | Print token-budgeted context packet for AI consumption | +| [`ctx load`](context.md#ctx-load) | Output assembled context in read order | +| [`ctx agent`](context.md#ctx-agent) | Print token-budgeted context packet for AI consumption | | [`ctx sync`](context.md#ctx-sync) | Reconcile context with codebase state | | [`ctx drift`](context.md#ctx-drift) | Detect stale paths, secrets, missing files | | [`ctx compact`](context.md#ctx-compact) | Archive completed tasks, clean up files | @@ -63,7 +63,7 @@ have been initialized by `ctx init` (otherwise commands return | [`ctx task`](context.md#ctx-task) | Add tasks, mark complete, archive, snapshot | | [`ctx decision`](context.md#ctx-decision) | Add decisions and reindex `DECISIONS.md` | | [`ctx learning`](context.md#ctx-learning) | Add learnings and reindex `LEARNINGS.md` | -| [`ctx convention`](context.md#adding-entries) | Add conventions to `CONVENTIONS.md` | +| [`ctx convention`](context.md#ctx-convention) | Add conventions to `CONVENTIONS.md` | | [`ctx reindex`](context.md#ctx-reindex) | Regenerate indices for `DECISIONS.md` and `LEARNINGS.md` | | [`ctx permission`](context.md#ctx-permission) | Permission snapshots (golden image) | | [`ctx change`](change.md#ctx-change) | Show what changed since last session | @@ -87,6 +87,7 @@ have been initialized by `ctx init` (otherwise commands return | Command | Description | |-----------------------------------------------|----------------------------------------------------------| +| [`ctx ai`](ai.md#ctx-ai) | Optional AI backend ping and proposal commands | | [`ctx setup`](setup.md#ctx-setup) | Generate AI tool integration configs | | [`ctx steering`](steering.md#ctx-steering) | Manage steering files (behavioral rules for AI tools) | | [`ctx trigger`](trigger.md#ctx-trigger) | Manage lifecycle triggers (scripts for automation) | @@ -94,7 +95,7 @@ have been initialized by `ctx init` (otherwise commands return | [`ctx mcp`](mcp.md#ctx-mcp) | MCP server for AI tool integration (stdin/stdout) | | [`ctx hook notify`](notify.md) | Webhook notifications (setup, test, send) | | [`ctx loop`](loop.md#ctx-loop) | Generate autonomous loop script | -| [`ctx connection`](connection.md) | Client-side commands for connecting to a `ctx` Hub | +| [`ctx connection`](connection.md#ctx-connection) | Client-side commands for connecting to a `ctx` Hub | | [`ctx hub`](hub.md#ctx-hub) | Operate a `ctx` Hub server or cluster | | [`ctx serve`](serve.md#ctx-serve) | Serve a static site locally via zensical | | [`ctx site`](site.md#ctx-site) | Site management (feed generation) | @@ -198,6 +199,15 @@ dream: # ctx-dream config (opt-in; off by default) budget: 40 # Step/token ceiling per pass model: "" # Executor model ("" = session default) executor: "" # Executor command ("" = claude -p reference) +backends: # Optional ctx ai backend definitions + default: vllm # Used when --backend is omitted + vllm: + endpoint: http://localhost:8000 + timeout: 30s + default_model: Qwen/Qwen2.5-Coder-7B-Instruct + openai: + api_key_env: OPENAI_API_KEY + default_model: gpt-4.1-mini ``` | Field | Type | Default | Description | @@ -226,6 +236,13 @@ dream: # ctx-dream config (opt-in; off by default) | `hooks.dir` | `string` | `.context/hooks` | Hook scripts directory | | `hooks.timeout` | `int` | `10` | Per-hook execution timeout in seconds | | `hooks.enabled` | `bool` | `true` | Whether hook execution is enabled | +| `backends` | `object` | *(none)* | Optional backend definitions for `ctx ai` commands | +| `backends.default` | `string` | *(empty)* | Backend selected when `ctx ai` omits `--backend` | +| `type` | `string` | backend name | Backend implementation when a named entry should use a different implementation | +| `endpoint` | `string` | backend default| OpenAI-compatible endpoint URL | +| `api_key_env` | `string` | backend default| Environment variable containing the API key | +| `timeout` | `string` | `30s` | Backend request timeout duration | +| `default_model` | `string` | *(empty)* | Model used when an AI request omits a model | **Priority order:** CLI flags > Environment variables > `.ctxrc` > Defaults diff --git a/docs/cli/setup.md b/docs/cli/setup.md index 5f1ce8edd..dfaaedc02 100644 --- a/docs/cli/setup.md +++ b/docs/cli/setup.md @@ -17,13 +17,19 @@ Generate AI tool integration configuration. ```bash ctx setup [flags] +ctx setup --backend [flags] ``` **Flags**: -| Flag | Short | Description | -|-----------|-------|-----------------------------------------------------------------------------| -| `--write` | `-w` | Write the generated config to disk (e.g. `.github/copilot-instructions.md`) | +| Flag | Short | Description | +|-----------------|-------|-----------------------------------------------------------------------------| +| `--write` | `-w` | Write the generated config to disk (e.g. `.github/copilot-instructions.md`) | +| `--backend` | | Configure a `ctx ai` backend in `.ctxrc` | +| `--endpoint` | | Backend endpoint URL | +| `--api-key-env` | | Environment variable that contains the backend API key | +| `--model` | | Default model for backend requests | +| `--timeout` | | Backend request timeout duration | **Supported tools**: @@ -38,6 +44,17 @@ ctx setup [flags] | `opencode` | OpenCode (terminal-first AI coding agent) | | `windsurf` | Windsurf IDE | +**Supported backends**: + +| Backend | Description | +|-----------------------|--------------------------------------------------| +| `vllm` | Local vLLM OpenAI-compatible server | +| `openai-compatible` | Generic OpenAI-compatible HTTP backend | +| `openai` | OpenAI-compatible backend with OpenAI defaults | +| `anthropic` | Anthropic backend using the compatibility floor | +| `ollama` | Local Ollama OpenAI-compatible endpoint defaults | +| `lmstudio` | Local LM Studio endpoint defaults | + !!! note "Claude Code Uses the Plugin System" Claude Code integration is now provided via the `ctx` plugin. Running `ctx setup claude-code` prints plugin install instructions. @@ -59,4 +76,13 @@ ctx setup cline --write # Generate OpenCode plugin, skills, AGENTS.md, and global MCP config ctx setup opencode --write + +# Configure a local vLLM backend for ctx ai commands +ctx setup --backend vllm --endpoint http://localhost:8000 --write + +# Preview an OpenAI-compatible backend config without writing +ctx setup --backend openai-compatible \ + --endpoint https://llm.example.com \ + --api-key-env OPENAI_API_KEY \ + --model gpt-4.1-mini ``` diff --git a/docs/cli/system.md b/docs/cli/system.md index 0b61c00cd..419200603 100644 --- a/docs/cli/system.md +++ b/docs/cli/system.md @@ -102,38 +102,6 @@ ctx system session-event --type start --caller vscode ctx system session-event --type end --caller vscode ``` -#### `ctx system statusline` - -Renders the Claude Code status line. Claude Code pipes a JSON -payload to the configured statusLine command after each assistant -message; this command turns it into one line: - -``` -user@host ~/project | Opus | ctx: 42% | $1.23 -``` - -`ctx init` wires it into `.claude/settings.local.json`, backing up -any pre-existing statusLine entry to -`.context/state/previous-statusline.json` (restored when -`statusline.enabled: false` is set in `.ctxrc`; a statusLine that -is not ctx's is never removed). - -Missing payload fields drop their segment. Output is sanitized to -bounded printable ASCII, and the command always exits zero: a -non-zero exit would blank the status line. The line is -informational only; there is no cost gating and no model-switch -nudging (see `specs/statusline.md` for the rationale). - -```bash -ctx system statusline < payload.json -``` - -Config (`.ctxrc`): `statusline.enabled` (default `true`) and -`statusline.show_cost` (render the `$` segment, default `true`; -disable for screen-sharing or demos). Setting `enabled: false` -blanks the rendered line immediately; the settings entry itself -is restored/removed the next time the init merge runs. - ## Hook Subcommands Hidden Claude Code hook handlers implementing the hook contract: read diff --git a/docs/home/common-workflows.md b/docs/home/common-workflows.md index a2f459d0c..9504843da 100644 --- a/docs/home/common-workflows.md +++ b/docs/home/common-workflows.md @@ -257,7 +257,7 @@ ctx system bootstrap This prints the resolved context directory, the files in it, and the operating rules. The `CLAUDE.md` template instructs the agent to run this -automatically. See [CLI Reference: bootstrap](../cli/bootstrap.md#ctx-system-bootstrap). +automatically. See [CLI Reference: bootstrap](../cli/system.md#ctx-system-bootstrap). ## The Two Skills You Should Always Use @@ -355,7 +355,6 @@ These have no CLI equivalent. They require the agent's reasoning. | `/ctx-prompt-audit` | Analyze prompting patterns for improvement | | `/ctx-plan` | Stress-test an existing plan through adversarial interview | | `/ctx-plan-import` | Import Claude Code plan files into project specs | -| `/ctx-task-out` | Decompose a committed spec into a per-milestone implementation plan | | `/ctx-implement` | Execute a plan step-by-step with verification | | `/ctx-worktree` | Manage parallel agent worktrees | | `/ctx-journal-enrich` | Add metadata, tags, and summaries to journal entries | diff --git a/docs/home/configuration.md b/docs/home/configuration.md index 0448e5b6c..faf713c07 100644 --- a/docs/home/configuration.md +++ b/docs/home/configuration.md @@ -63,7 +63,7 @@ A commented `.ctxrc` showing all options and their defaults: ```yaml # .ctxrc: ctx runtime configuration -# https://ctx.ist/home/configuration/ +# https://ctx.ist/configuration/ # # All settings are optional. Missing values use defaults. # Priority: CLI flags > environment variables > .ctxrc > defaults @@ -102,10 +102,6 @@ A commented `.ctxrc` showing all options and their defaults: # timeout: 10 # enabled: true # -# statusline: # Claude Code status line (informational only) -# enabled: true # Deploy statusLine via ctx init -# show_cost: true # Render the $ session-cost segment -# # provenance_required: # Relax provenance flags for ctx add # session_id: true # Require --session-id (default: true) # branch: true # Require --branch (default: true) @@ -150,8 +146,6 @@ A commented `.ctxrc` showing all options and their defaults: | `hooks.dir` | `string` | `.context/hooks` | Hook scripts directory | | `hooks.timeout` | `int` | `10` | Per-hook execution timeout in seconds | | `hooks.enabled` | `bool` | `true` | Whether hook execution is enabled | -| `statusline.enabled` | `bool` | `true` | Whether `ctx init` deploys the Claude Code status line (`ctx system statusline`) | -| `statusline.show_cost` | `bool` | `true` | Whether the status line renders the session-cost (`$`) segment | | `provenance_required.session_id` | `bool` | `true` | Require `--session-id` on `ctx add` for tasks, decisions, learnings | | `provenance_required.branch` | `bool` | `true` | Require `--branch` on `ctx add` for tasks, decisions, learnings | | `provenance_required.commit` | `bool` | `true` | Require `--commit` on `ctx add` for tasks, decisions, learnings | @@ -386,7 +380,7 @@ throughout the session. This replaces the previous approach of hardcoding `.context/` paths in agent instructions. -See [CLI Reference: bootstrap](../cli/bootstrap.md#ctx-system-bootstrap) +See [CLI Reference: bootstrap](../cli/system.md#ctx-system-bootstrap) for full details. --- diff --git a/docs/operations/integrations.md b/docs/operations/integrations.md index 309c98b5c..5dc1a64d1 100644 --- a/docs/operations/integrations.md +++ b/docs/operations/integrations.md @@ -321,7 +321,6 @@ These are invoked in Claude Code with `/skill-name`. | Skill | Description | |---------------------|--------------------------------------------------| | `/ctx-loop` | Generate a Ralph Loop iteration script | -| `/ctx-task-out` | Decompose a committed spec into a milestone plan | | `/ctx-implement` | Execute a plan step-by-step with checks | | `/ctx-plan-import` | Import Claude Code plan files into project specs | | `/ctx-worktree` | Manage git worktrees for parallel agents | diff --git a/docs/recipes/design-before-coding.md b/docs/recipes/design-before-coding.md index f19043431..9826a348d 100644 --- a/docs/recipes/design-before-coding.md +++ b/docs/recipes/design-before-coding.md @@ -23,25 +23,22 @@ the next session has no idea why things are shaped this way. ```text /ctx-brainstorm # explore the design space /ctx-spec # write the spec document -/ctx-task-out # decompose into a milestone plan +/ctx-task-add # break it into tasks /ctx-implement # execute step-by-step ``` Four skills, used in sequence. Each produces an artifact that feeds -the next. For specs small enough to implement in one session, the -spec doubles as the plan: skip `/ctx-task-out` and break the work -into TASKS.md entries with `/ctx-task-add` instead. +the next. ## Commands and Skills Used -| Tool | Type | Purpose | -|---------------------|-------|----------------------------------------------------| -| `/ctx-brainstorm` | Skill | Structured design dialogue: explore approaches | -| `/ctx-spec` | Skill | Scaffold and fill out a spec from the template | -| `/ctx-task-out` | Skill | Decompose a spec into `specs/plans/.md` | -| `/ctx-task-add` | Skill | Add implementation tasks to TASKS.md | -| `/ctx-implement` | Skill | Execute a plan step-by-step with verification | -| `/ctx-decision-add` | Skill | Record design choices made during brainstorming | +| Tool | Type | Purpose | +|---------------------|-------|-------------------------------------------------| +| `/ctx-brainstorm` | Skill | Structured design dialogue: explore approaches | +| `/ctx-spec` | Skill | Scaffold and fill out a spec from the template | +| `/ctx-task-add` | Skill | Add implementation tasks to TASKS.md | +| `/ctx-implement` | Skill | Execute a plan step-by-step with verification | +| `/ctx-decision-add` | Skill | Record design choices made during brainstorming | ## The Workflow @@ -112,10 +109,9 @@ and won't accept "none" without a challenge. Sections that don't apply can be skipped. The result is a complete spec at `specs/{feature-name}.md`. -### Step 3: Task Out the Work +### Step 3: Break into Tasks -After the spec is written, the skill routes by size. A small, -single-session spec gets tasks in TASKS.md directly: +After the spec is written, the skill offers to create tasks: ```text Agent: "Spec written to specs/rss-feed.md. Want me to break this @@ -137,37 +133,11 @@ Each task is independently completable and references the spec via You can also invoke `/ctx-task-add` directly at any point to add individual tasks. -A spec that spans multiple milestones (or more than about one -session of implementation) gets `/ctx-task-out` instead: - -```text -You: /ctx-task-out --spec specs/v1-substrate.md --milestone m0a - -Agent: "Open questions check: D-001 (language choice) is blocking - for m0a — three tasks would embed an assumption about its - answer. Resolve it before I decompose." - -You: [resolves D-001 in the spec] - -Agent: [writes specs/plans/m0a.md: data model, contracts, test - matrix, 24 tasks with falsifiable acceptance criteria] - "Plan written. TASKS.md gained 4 epic anchors, each - annotated Plan: specs/plans/m0a.md." -``` - -The plan document owns the fine-grained tasks; TASKS.md carries -epic-level anchors only. Two hard gates apply: decomposition -refuses to run past a blocking open question in the spec, and -milestone N+1 is not tasked out while milestone N's definition of -done is unmet. - ### Step 4: Implement Step-by-Step -Pick up the work with `/ctx-implement`. The skill loads the plan — -`specs/plans/.md` when `/ctx-task-out` produced one, the -spec itself for small features — breaks it into atomic steps, and -checkpoints after every 3-5 steps with a build and test -verification: +Pick up tasks with `/ctx-implement`. The skill loads the spec, breaks +work into atomic steps, and checkpoints after every 3-5 steps with +a build and test verification: ```text You: /ctx-implement (specs/rss-feed.md) @@ -194,7 +164,7 @@ Not every feature needs all four steps. Use your judgment: |----------------------------------------|--------------------| | Vague idea, multiple valid approaches | Step 1: Brainstorm | | Clear approach, need to document it | Step 2: Spec | -| Spec already exists, need to plan work | Step 3: Task out | +| Spec already exists, need to plan work | Step 3: Tasks | | Tasks exist, ready to code | Step 4: Implement | A brainstorm without a spec is fine for small decisions. A spec without @@ -210,7 +180,6 @@ You don't need skill names. Natural language works: | "Let's think through this feature" | `/ctx-brainstorm` | | "Spec this out" | `/ctx-spec` | | "Write a design doc for..." | `/ctx-spec` | -| "Task this out" | `/ctx-task-out` | | "Break this into tasks" | `/ctx-task-add` | | "Implement the spec" | `/ctx-implement` | | "Let's design before we build" | Starts at brainstorm | @@ -240,12 +209,8 @@ You don't need skill names. Natural language works: structured design dialogue * [Skills Reference: /ctx-spec](../reference/skills.md#ctx-spec): spec scaffolding from template -* [Skills Reference: /ctx-task-out](../reference/skills.md#ctx-task-out): - spec decomposition into a per-milestone plan * [Skills Reference: /ctx-implement](../reference/skills.md#ctx-implement): step-by-step execution with verification -* [Scrutinizing a Plan](scrutinizing-a-plan.md): the adversarial - interview that belongs between brainstorm and spec * [Tracking Work Across Sessions](task-management.md): task lifecycle and archival * [Importing Claude Code Plans](import-plans.md): turning ephemeral plans diff --git a/docs/recipes/index.md b/docs/recipes/index.md index 746ed752a..d03d286b5 100644 --- a/docs/recipes/index.md +++ b/docs/recipes/index.md @@ -30,6 +30,15 @@ Aider, Copilot, or Windsurf. Includes **shell completion**, --- +### [Local Inference with vLLM](local-inference-with-vllm.md) + +Configure a local OpenAI-compatible vLLM server for optional `ctx ai` ping and +proposal commands without making deterministic ctx commands depend on AI. + +**Uses**: `ctx setup --backend`, `ctx ai ping`, `ctx ai propose` + +--- + ### [Multilingual Session Parsing](multilingual-sessions.md) Parse session journal entries written in **other languages**. @@ -355,11 +364,11 @@ optionally create tasks referencing each imported spec. ### [Design Before Coding](design-before-coding.md) Front-load design with a four-skill chain: **brainstorm** the approach, -**spec** the design, **task out** the work, **implement** step-by-step. +**spec** the design, **task** the work, **implement** step-by-step. Each step produces an artifact that feeds the next. -**Uses**: `/ctx-brainstorm`, `/ctx-spec`, `/ctx-task-out`, -`/ctx-task-add`, `/ctx-implement`, `/ctx-decision-add` +**Uses**: `/ctx-brainstorm`, `/ctx-spec`, `/ctx-task-add`, +`/ctx-implement`, `/ctx-decision-add` --- @@ -543,4 +552,3 @@ stepdown, and the Raft-lite durability caveat. **Uses**: `ctx hub start --peers`, `ctx hub status`, `ctx hub peer add/remove`, `ctx hub stepdown` - diff --git a/docs/recipes/local-inference-with-vllm.md b/docs/recipes/local-inference-with-vllm.md new file mode 100644 index 000000000..df47de3c1 --- /dev/null +++ b/docs/recipes/local-inference-with-vllm.md @@ -0,0 +1,72 @@ +--- +# / ctx: https://ctx.ist +# ,'`./ do you remember? +# `.,'\ +# \ Copyright 2026-present Context contributors. +# SPDX-License-Identifier: Apache-2.0 + +title: Local Inference with vLLM +icon: lucide/server +--- + +![ctx](../images/ctx-banner.png) + +Use a local vLLM OpenAI-compatible server for optional `ctx ai` commands. +This does not change deterministic ctx behavior: `ctx status`, `ctx agent`, +and hooks keep working when no backend is configured or reachable. + +## 1. Start vLLM + +Run vLLM with its OpenAI-compatible API enabled. The exact model is your choice; +ctx only needs `/v1/models` and `/v1/chat/completions`. + +## 2. Configure ctx + +From the project root: + +```bash +ctx setup --backend vllm --endpoint http://localhost:8000 --write +``` + +This writes a `.ctxrc` `backends:` block similar to: + +```yaml +backends: + default: vllm + vllm: + endpoint: http://localhost:8000 +``` + +Add a model or timeout if needed: + +```yaml +backends: + default: vllm + vllm: + endpoint: http://localhost:8000 + default_model: Qwen/Qwen2.5-Coder-7B-Instruct + timeout: 30s +``` + +## 3. Verify reachability + +```bash +ctx ai ping +``` + +Expected output names the backend, endpoint, and first model listed by vLLM. + +## 4. Write a reviewable proposal + +```bash +ctx ai propose notes.md --emit decisions,learnings,tasks,open-questions +``` + +ctx writes one JSON proposed-patch artifact under `.context/proposals/ai/`. +Review it before changing canonical `.context/*.md` files. + +## Failure behavior + +AI commands fail closed when no backend is configured, multiple backends are +ambiguous, the backend is unreachable, or the upstream response is invalid. +They do not fall back to a different model and do not affect non-AI commands. diff --git a/docs/recipes/scrutinizing-a-plan.md b/docs/recipes/scrutinizing-a-plan.md index e4d251359..c5a555819 100644 --- a/docs/recipes/scrutinizing-a-plan.md +++ b/docs/recipes/scrutinizing-a-plan.md @@ -78,16 +78,10 @@ alternatives have a recall trigger. ## Output -`/ctx-plan` concludes by offering to write a *debated brief* to -`.context/briefs/-.md`: the bet, the rejections, the -failure modes, the validation route, and the unwind cost, in your -words. It deliberately does **not** produce an implementation plan -or a task list — decomposition happens after the spec, via -`/ctx-task-out`. Feed the interview's conclusions forward via: - -- **`/ctx-spec --brief `** to absorb the brief into a - committed spec; multi-milestone specs then flow to - `/ctx-task-out` for decomposition. +`/ctx-plan` produces a clearer plan, not a document. Persist the +deltas via: + +- **`/ctx-spec`** if the conclusions belong in a feature spec. - **`/ctx-decision-add`** if a tradeoff resolved into an architectural decision. - **`/ctx-learning-add`** if you discovered a project-specific diff --git a/docs/reference/skills.md b/docs/reference/skills.md index 80067b44d..8e449d756 100644 --- a/docs/reference/skills.md +++ b/docs/reference/skills.md @@ -57,16 +57,14 @@ opinionated behavior on top. | [`/ctx-journal-enrich-all`](#ctx-journal-enrich-all) | Full journal pipeline: export if needed, then batch-enrich | user-invocable | | [`/ctx-blog`](#ctx-blog) | Generate blog post draft from project activity | user-invocable | | [`/ctx-blog-changelog`](#ctx-blog-changelog) | Generate themed blog post from a commit range | user-invocable | -| [`/ctx-humanize`](#ctx-humanize) | Remove formulaic LLM writing patterns from human-facing prose | user-invocable | | [`/ctx-consolidate`](#ctx-consolidate) | Consolidate redundant learnings or decisions | user-invocable | | [`/ctx-drift`](#ctx-drift) | Detect and fix context drift | user-invocable | +| [`/ctx-prompt`](#ctx-prompt) | Apply, list, and manage saved prompt templates | user-invocable | | [`/ctx-prompt-audit`](#ctx-prompt-audit) | Analyze prompting patterns for improvement | user-invocable | | [`/ctx-link-check`](#ctx-link-check) | Audit docs for dead internal and external links | user-invocable | | [`/ctx-permission-sanitize`](#ctx-permission-sanitize) | Audit Claude Code permissions for security risks | user-invocable | | [`/ctx-brainstorm`](#ctx-brainstorm) | Structured design dialogue before implementation | user-invocable | -| [`/ctx-plan`](#ctx-plan) | Stress-test a plan through adversarial interview | user-invocable | | [`/ctx-spec`](#ctx-spec) | Scaffold a feature spec from a project template | user-invocable | -| [`/ctx-task-out`](#ctx-task-out) | Decompose a committed spec into a per-milestone plan | user-invocable | | [`/ctx-plan-import`](#ctx-plan-import) | Import Claude Code plan files into project specs | user-invocable | | [`/ctx-implement`](#ctx-implement) | Execute a plan step-by-step with verification | user-invocable | | [`/ctx-loop`](#ctx-loop) | Generate autonomous loop script | user-invocable | @@ -352,23 +350,6 @@ that period. --- -### `/ctx-humanize` - -Review, rewrite, or edit human-facing prose (blog posts, docs, -READMEs, announcements) to remove formulaic LLM writing -patterns: significance inflation, brochure language, forced -triplets, chatbot residue, em-dash typography. Preserves -meaning, certainty, and voice; invents nothing. Defaults to -review mode and only edits files when asked. - -**Wraps**: a 28-pattern catalog adapted from Wikipedia's "Signs -of AI writing"; verifies typography mechanically before -returning - -**See also**: [Turning Activity into Content](../recipes/publishing.md) - ---- - ## Auditing & Health Skills for detecting drift, auditing alignment, and improving @@ -496,33 +477,6 @@ stress-test the chosen approach, and present the detailed design. "before we build", "what approach should we take?" **See also**: -[`/ctx-plan`](#ctx-plan), -[`/ctx-spec`](#ctx-spec) - ---- - -### `/ctx-plan` - -Stress-test a plan through an adversarial interview before it becomes -a spec. Asks one question at a time across scope, failure modes, -rejected alternatives, sequencing, reversibility, and hidden -assumptions — pushing back rather than validating. Stops when the -user can articulate the bet, the rejections, the top failure modes, -the cheapest validation, and the unwind cost. Concludes by offering -to write a *debated brief* to `.context/briefs/-.md`, the -canonical input for `/ctx-spec --brief`. Deliberately does **not** -produce an implementation plan or task list — that happens two steps -later, at [`/ctx-task-out`](#ctx-task-out). - -**Wraps**: reads code and context files; -writes `.context/briefs/-.md` - -**Trigger phrases**: "attack this plan", "poke holes in this", -"stress-test my plan", "scrutinize this before I commit" - -**See also**: -[Scrutinizing a Plan](../recipes/scrutinizing-a-plan.md), -[`/ctx-brainstorm`](#ctx-brainstorm), [`/ctx-spec`](#ctx-spec) --- @@ -563,58 +517,13 @@ filling the gap from inference. If the brief contradicts a frozen contract, the contradiction is surfaced to the user rather than silently followed. -Both flows end with a **tasking handoff**: specs that span -multiple milestones (or more than roughly one session of -implementation) are routed to [`/ctx-task-out`](#ctx-task-out) -for decomposition; small specs go straight to -[`/ctx-implement`](#ctx-implement). - **See also**: [`/ctx-brainstorm`](#ctx-brainstorm), [`/ctx-plan`](#ctx-plan), -[`/ctx-task-out`](#ctx-task-out), [`/ctx-plan-import`](#ctx-plan-import) --- -### `/ctx-task-out` - -Decompose a committed spec into a per-milestone implementation plan -at `specs/plans/.md` — data model, contracts, an -invariant-test matrix, and typically 15-40 tasks, each with a -**falsifiable acceptance criterion** (a command to run, a test that -must pass, an observable behavior). The plan is the document -[`/ctx-implement`](#ctx-implement) executes. The skill is a -decomposer, not a designer: disagreements with the spec route back -through [`/ctx-plan`](#ctx-plan) instead of being relitigated here. - -Two **hard gates** refuse rather than degrade: - -1. **Blocking-TBD gate**: the spec's open questions are classified - as blocking or deferrable for the target milestone; decomposition - refuses to proceed past a blocking TBD (a task that would embed - an assumption about its answer). -2. **Rolling-wave gate**: milestone N+1 is not decomposed while - milestone N's definition of done is unmet, unless the user - overrides explicitly (recorded in the plan header). - -TASKS.md receives **epic-level anchors only**, each annotated -`Plan: specs/plans/.md` — the plan owns the fine-grained -tasks, one-way sync, nothing moved or deleted. Single-session specs -skip this step entirely: the spec *is* the plan. - -**Wraps**: reads the spec, TASKS.md, DECISIONS.md, CONVENTIONS.md; -writes `specs/plans/.md`, appends anchors to TASKS.md - -**Trigger phrases**: "task this out", "break down the spec", -"decompose the spec", "plan out the milestone" - -**See also**: -[`/ctx-spec`](#ctx-spec), -[`/ctx-implement`](#ctx-implement) - ---- - ### `/ctx-plan-import` Import Claude Code plan files (`~/.claude/plans/*.md`) into the project's @@ -634,18 +543,13 @@ optionally chains to `/ctx-task-add` ### `/ctx-implement` Execute a multi-step plan with build and test verification at each -step. The canonical input is `specs/plans/.md` as written -by [`/ctx-task-out`](#ctx-task-out), but hand-written plan files and -plans from conversation context work too. Breaks the plan into -atomic steps and checkpoints after every 3-5 steps. Handed a bare -multi-milestone spec instead of a plan, it redirects to -`/ctx-task-out` rather than decomposing on the fly. +step. Loads a plan from a file or conversation context, breaks it +into atomic steps, and checkpoints after every 3-5 steps. **Wraps**: reads plan file, runs verification commands (`go build`, `go test`, etc.) **See also**: -[`/ctx-task-out`](#ctx-task-out), [Running an Unattended AI Agent](../recipes/autonomous-loops.md) --- diff --git a/go.work.sum b/go.work.sum index 0ad5768dd..64a2b976f 100644 --- a/go.work.sum +++ b/go.work.sum @@ -85,18 +85,12 @@ go.opentelemetry.io/contrib/detectors/gcp v1.42.0/go.mod h1:W9zQ439utxymRrXsUOzZ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= -golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= -golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/telemetry v0.0.0-20260508192327-42602be52be6 h1:HjU6IWBiAgRIdAJ9/y1rwCn+UELEmwV+VsTLzj/W4sE= golang.org/x/telemetry v0.0.0-20260508192327-42602be52be6/go.mod h1:Eqhaxk/wZsWEH8CRxLwj6xzEJbz7k1EFGqx7nyCoabE= -golang.org/x/telemetry v0.0.0-20260610154732-fb80ec83bdd9 h1:FjUup8XrRy7lv+XHONi6KKUSizeF2NnVrTnz/HhbohQ= -golang.org/x/telemetry v0.0.0-20260610154732-fb80ec83bdd9/go.mod h1:3AWMyWHS+caVoiEXpiq6+tzKA40J4vQT3MYr80ZtQpc= golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= -golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= -golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= diff --git a/hack/check-tools.sh b/hack/check-tools.sh deleted file mode 100755 index dfb48aa24..000000000 --- a/hack/check-tools.sh +++ /dev/null @@ -1,208 +0,0 @@ -#!/usr/bin/env bash - -# / ctx: https://ctx.ist -# ,'`./ do you remember? -# `.,'\ -# \ Copyright 2026-present Context contributors. -# SPDX-License-Identifier: Apache-2.0 -# -# check-tools.sh — verify tooling dependency versions in one pass. -# -# Reads hack/tool-versions.txt and probes every entry: PATH binaries -# (with minimum-version enforcement), npm-installed tools (with -# registry drift detection), and MCP servers registered with the -# claude CLI. Prints one table; the answer to "is this machine ready -# to work on ctx?". -# -# Verdicts: OK, MISSING, OUTDATED, SKIP (probe impossible — no -# claude CLI, no network). Only failures of tools marked `required` -# in the manifest affect the exit code. -# -# Usage: -# ./hack/check-tools.sh # exit 1 only on required-tool failures -# ./hack/check-tools.sh --strict # optional-tool failures also fatal -# -# Spec: specs/check-tools.md - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -MANIFEST="${SCRIPT_DIR}/tool-versions.txt" - -STRICT=false -[ "${1:-}" = "--strict" ] && STRICT=true - -if [ ! -f "$MANIFEST" ]; then - echo "manifest not found: $MANIFEST" >&2 - exit 1 -fi - -# Run a command under a timeout when coreutils timeout exists -# (absent on stock macOS); otherwise run it bare. -with_timeout() { - local secs="$1" - shift - if command -v timeout >/dev/null 2>&1; then - timeout "$secs" "$@" - else - "$@" - fi -} - -# First dotted-number token in a version banner ("go1.26.3", -# "v24.18.0", "jq-1.7.1" all yield the bare number). -extract_version() { - grep -oE '[0-9]+(\.[0-9]+)+' | head -1 -} - -# True when $2 >= $1 under version ordering. -version_gte() { - [ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -1)" = "$1" ] -} - -# `claude mcp list` is slow (it health-checks every server), so run -# it at most once and only if the manifest has mcp rows. -MCP_LIST="" -MCP_LIST_STATE="unloaded" # unloaded | ok | no-cli | failed -load_mcp_list() { - [ "$MCP_LIST_STATE" != "unloaded" ] && return 0 - if ! command -v claude >/dev/null 2>&1; then - MCP_LIST_STATE="no-cli" - return 0 - fi - if MCP_LIST="$(with_timeout 30 claude mcp list 2>/dev/null)"; then - MCP_LIST_STATE="ok" - else - MCP_LIST_STATE="failed" - fi -} - -bin_version() { - local name="$1" out="" - case "$name" in - go) out="$(go version 2>/dev/null || true)" ;; - *) out="$("$name" --version 2>/dev/null || true)" ;; - esac - printf '%s' "$out" | extract_version -} - -ROWS="" -FAILED_REQUIRED=0 -FAILED_OPTIONAL=0 - -add_row() { - ROWS="${ROWS}$(printf '%s\t%s\t%s\t%s\t%s' "$1" "$2" "$3" "$4" "$5")"$'\n' -} - -fail() { - local requirement="$1" - if [ "$requirement" = "required" ]; then - FAILED_REQUIRED=$((FAILED_REQUIRED + 1)) - else - FAILED_OPTIONAL=$((FAILED_OPTIONAL + 1)) - fi -} - -check_bin() { - local name="$1" requirement="$2" min="$3" - if ! command -v "$name" >/dev/null 2>&1; then - add_row "$name" "$requirement" "MISSING" "-" "not on PATH" - fail "$requirement" - return 0 - fi - local ver - ver="$(bin_version "$name")" - if [ "$min" != "-" ] && [ -n "$ver" ] && ! version_gte "$min" "$ver"; then - add_row "$name" "$requirement" "OUTDATED" "$ver" "minimum is $min" - fail "$requirement" - return 0 - fi - local note="-" - [ "$min" != "-" ] && note="min $min" - add_row "$name" "$requirement" "OK" "${ver:-present}" "$note" -} - -check_npm() { - local name="$1" requirement="$2" - if ! command -v "$name" >/dev/null 2>&1; then - add_row "$name" "$requirement" "MISSING" "-" "npm install -g $name" - fail "$requirement" - return 0 - fi - local ver latest - ver="$(bin_version "$name")" - if ! command -v npm >/dev/null 2>&1; then - add_row "$name" "$requirement" "OK" "${ver:-present}" "no npm; drift check skipped" - return 0 - fi - latest="$(with_timeout 10 npm view "$name" version 2>/dev/null || true)" - if [ -z "$latest" ]; then - add_row "$name" "$requirement" "OK" "${ver:-present}" "registry unreachable; drift check skipped" - elif [ "$ver" = "$latest" ]; then - add_row "$name" "$requirement" "OK" "$ver" "latest" - else - add_row "$name" "$requirement" "OUTDATED" "$ver" "latest is $latest" - fail "$requirement" - fi -} - -check_mcp() { - local name="$1" requirement="$2" - load_mcp_list - case "$MCP_LIST_STATE" in - no-cli) - add_row "mcp:$name" "$requirement" "SKIP" "-" "claude CLI not on PATH" - return 0 - ;; - failed) - add_row "mcp:$name" "$requirement" "SKIP" "-" "claude mcp list failed" - return 0 - ;; - esac - if printf '%s\n' "$MCP_LIST" | grep -q "^${name}:"; then - local note="registered" - if [ "$name" = "gemini-search" ] && [ -z "${GEMINI_API_KEY:-}" ]; then - note="registered; GEMINI_API_KEY not set in this shell" - fi - add_row "mcp:$name" "$requirement" "OK" "-" "$note" - else - add_row "mcp:$name" "$requirement" "MISSING" "-" "make register-mcp" - fail "$requirement" - fi -} - -while read -r name type requirement min _; do - case "$name" in ''|\#*) continue ;; esac - case "$type" in - bin) check_bin "$name" "$requirement" "$min" ;; - npm) check_npm "$name" "$requirement" ;; - mcp) check_mcp "$name" "$requirement" ;; - *) - echo "manifest error: unknown type '$type' for '$name'" >&2 - exit 1 - ;; - esac -done < "$MANIFEST" - -printf '%s' "$ROWS" | awk -F'\t' ' -BEGIN { - printf "%-18s %-10s %-9s %-12s %s\n", "TOOL", "REQ", "STATUS", "VERSION", "NOTE" - printf "%-18s %-10s %-9s %-12s %s\n", "----", "---", "------", "-------", "----" -} -{ printf "%-18s %-10s %-9s %-12s %s\n", $1, $2, $3, $4, $5 } -' - -echo "" -if [ "$FAILED_REQUIRED" -gt 0 ]; then - echo "FAIL: $FAILED_REQUIRED required tool(s) missing or outdated." - exit 1 -fi -if [ "$FAILED_OPTIONAL" -gt 0 ]; then - echo "WARN: $FAILED_OPTIONAL optional tool(s) missing or outdated." - if [ "$STRICT" = true ]; then - echo "FAIL: --strict promotes optional failures to fatal." - exit 1 - fi - exit 0 -fi -echo "All tools OK." diff --git a/hack/tool-versions.txt b/hack/tool-versions.txt deleted file mode 100644 index 65bb343f0..000000000 --- a/hack/tool-versions.txt +++ /dev/null @@ -1,33 +0,0 @@ -# Tooling dependency manifest — read by hack/check-tools.sh. -# -# Columns (whitespace-separated): -# name tool name; bin: command on PATH, npm: package name, -# mcp: server name as registered with `claude mcp add` -# type bin | npm | mcp -# requirement required | optional (required failures fail the check) -# min minimum version, or "-" for presence-only -# -# Version minimums live here so bumps are one-line diffs. - -# Build / lint core — the check fails without these. -go bin required 1.26 -git bin required - -golangci-lint bin required - - -# Node toolchain — GitNexus and npx-launched MCP servers need it. -node bin optional 20 -npm bin optional - - -# Site builds (make site / ctx journal). -pipx bin optional - -zensical bin optional - - -# Makefile plumbing (sync-version). -jq bin optional - - -# AI tooling. -claude bin optional - -gitnexus npm optional - -gitnexus mcp optional - -gemini-search mcp optional - -# firecrawl mcp optional - (enable when FireCrawl MCP is adopted) diff --git a/internal/assets/claude/CLAUDE.md b/internal/assets/claude/CLAUDE.md index 8e832002c..e53de0b89 100644 --- a/internal/assets/claude/CLAUDE.md +++ b/internal/assets/claude/CLAUDE.md @@ -6,45 +6,17 @@ ## IMPORTANT: You Have Persistent Memory This project uses Context (`ctx`) for context persistence across sessions. -When `ctx` is installed, **your memory is NOT ephemeral**: it lives in the -context directory. - -`ctx` is an optional companion tool: helpful, but never required to build, -test, or contribute to this project. If it is not installed, offer the -setup note in "On Session Start" once, then skip every `ctx`-dependent -instruction in this file and help with the task at hand as usual. +**Your memory is NOT ephemeral**: it lives in the context directory. ## On Session Start -1. **Run `ctx system bootstrap`**: it tells you where the context - directory is. - - **If the `ctx` command is not found**: `ctx` is optional, so this is - not an error. Mention once that the user can enable persistent context - by cloning the repository and installing the plugin from the local - clone (releases are infrequent, so marketplace versions may lag behind - the repository): - - ```bash - git clone https://github.com/ActiveMemory/ctx.git ~/WORKSPACE/ctx - ``` - - Then, inside Claude Code: - - ``` - /plugin marketplace add ~/WORKSPACE/ctx - /plugin install ctx@activememory-ctx - ``` - - The `ctx` binary is installed separately; see - https://ctx.ist/home/getting-started/. Afterward, continue with the - user's task and work without persistent context until `ctx` is set up. - - **If `ctx` is installed but returns an error**: relay the error output - to the user verbatim, point them at - https://ctx.ist/home/getting-started/ for setup, and STOP. Do not try - to activate, initialize, or otherwise recover: **those are the user's - decisions**. Wait for their next instruction. +1. **Run `ctx system bootstrap`**: CRITICAL, not optional. + This tells you where the context directory is. + If it returns any error, relay the error output to the user + verbatim, point them at + https://ctx.ist/home/getting-started/ for setup, and STOP. + Do not try to activate, initialize, or otherwise recover: **those + are the user's decisions**. Wait for their next instruction. 2. **Read AGENT_PLAYBOOK.md** from the context directory: it explains how to use this system 3. **Run `ctx agent`** for a content summary diff --git a/internal/assets/claude/skills/ctx-humanize/SKILL.md b/internal/assets/claude/skills/ctx-humanize/SKILL.md deleted file mode 100644 index 726b1e870..000000000 --- a/internal/assets/claude/skills/ctx-humanize/SKILL.md +++ /dev/null @@ -1,212 +0,0 @@ ---- -name: ctx-humanize -description: "Review, rewrite, or edit human-facing prose to remove formulaic LLM writing patterns while preserving meaning, intent, and certainty. Use when the user says 'humanize this', 'this sounds like AI', 'remove the AI tells', 'de-AI this', 'make it sound human', asks whether text reads as AI-generated, or wants a blog post, doc, README, or announcement polished before publishing." -allowed-tools: Read, Write, Edit, Grep, Glob, AskUserQuestion ---- - -Make prose sound like a person wrote it, not like a model -assembled the most statistically likely version of an answer. - -This applies to human-facing prose: blog posts, essays, -user-facing docs, READMEs, PR descriptions, release -announcements, leadership summaries. It does not apply to code, -logs, structured data, test output, or machine-readable content. -In ctx projects, also leave `.context/` knowledge files, -`specs/`, and `SKILL.md` files alone unless the user explicitly -asks: they are agent-facing operational text, and "sounding -human" is not their job. - -The goal is not to make everything casual. It is to make the -writing appropriate for its audience, specific in its claims, -and free of the tells that make readers discount it. - -## Invariants - -These hold in every mode. They exist because a humanizing pass -that changes what the text *says* is worse than no pass at all. - -1. Preserve the author's meaning. -2. Preserve the author's level of certainty. Do not make weak - claims sound stronger just because the prose gets cleaner. -3. Preserve document structure unless asked to restructure. -4. Do not add facts, examples, citations, names, numbers, - anecdotes, opinions, or emotions that are not in the source. - If a rewrite needs voice, draw it from stances the author - actually expressed. Never invent a first-person reaction. -5. Do not flatten a real voice into corporate-neutral mush. -6. Prefer the smallest edit that makes the prose better. - -When the text is already good, say so and stop. Do not rewrite -to prove the skill ran. - -## Modes - -Default to **Review** unless the user asks for a rewrite or -asks you to edit a file. - -**Review**: the user wants a verdict or feedback. Report: -the main AI tells found (with locations), the highest-value -edits, and any places where rewriting would risk meaning, -voice, or precision. Do not modify files. - -**Rewrite**: the user asks to humanize, polish, or rewrite. -Return the rewritten text plus a brief summary of what changed. - -**Apply**: the user asks you to edit a file. Prefer Edit over -Write; use Write only for new files or explicit full -replacement. Afterwards report files changed, kinds of changes, -and anything intentionally left as-is. - -## Protected Content - -Improve the prose *around* these; the items themselves survive -unchanged, because their value is exactness: - -- fenced code blocks, inline code, shell commands -- file paths, URLs, package/API/function names, flags, env vars -- issue/ticket IDs, CVE IDs, commit SHAs, PR numbers -- quoted text, unless the user explicitly asks to edit a quote -- legal, compliance, or security wording where exact language - matters -- RFC-2119 keywords (MUST, SHOULD, MAY, SHALL, REQUIRED, - OPTIONAL) - -## Process - -1. Read the full input. For file targets, Read the whole file - rather than sampling it. -2. Identify *clustered* AI patterns using the index below. Read - `references/pattern-catalog.md` (from this skill's directory) - before any substantial rewrite: it has before/after examples - for every pattern and the guardrails for adding voice. -3. Pick the mode and act on it. Steps 4 through 6 apply when - you produce a rewrite (Rewrite and Apply modes); in Review - mode, report the findings those steps would have caught. -4. Draft, then ask: "what still makes this sound generated?" - and revise once more. First drafts of de-AI'd text usually - still carry essay symmetry. -5. Run the typography check (below). -6. Verify no facts were invented, no claims strengthened or - weakened, no coverage lost: if the original made five - substantive points, the rewrite still makes five. - Zero-content filler (generic optimism, throat-clearing, - chatbot residue) does not count as a substantive point; - deleting it is not a coverage loss. - -## Typography - -Many readers now treat certain typography as machine residue, -so normalize it in human-facing prose unless the user opts out: - -- smart quotes and apostrophes → ASCII quotes -- en dashes → hyphens -- em dashes → replaced *semantically*, never by blind - search-and-replace: a period when the dash starts a new - thought, a comma for a tight aside, a colon before an - explanation, parentheses for a true aside, or restructure - the sentence. Also catch ` -- ` double-hyphens used as dashes. - -The final text must contain no em or en dashes. Verify -mechanically, not by eye: Grep the result for `—`, `–`, ` -- `, -and smart-quote characters before returning. For inline -rewrites, write the draft to a scratch file and grep that. In -repos that ship `hack/detect-ai-typography.sh` (the ctx repo -does), the script runs the same check, but note it takes a -*directory* of markdown files, not a single file path. - -## Detection Guidance - -Flag clusters, not isolated hits. Clean human writing can -trip several patterns; one "additionally" or one bold phrase -is not a defect. A paragraph that stacks inflated significance -on a forced triplet on a generic conclusion is. - -Not reliable indicators on their own: perfect grammar, -consistent style, dry prose, formal vocabulary, curly quotes, -one short emphatic sentence, unsourced claims, correct or -complex formatting. - -Preserve signs of an actual human: specific hard-to-fabricate -detail, mixed feelings, unresolved tension, era-bound -references, first-person editorial choices, varied sentence -length, useful asides, parentheticals, self-corrections. These -are often the point of the piece. Do not sand them away. - -## Pattern Index - -Full catalog with before/after examples and watch lists: -`references/pattern-catalog.md`. The short version: - -| # | Pattern | Tell | -|---|---------|------| -| 1 | Inflated significance | "pivotal moment", "testament to", "broader trends" | -| 2 | Forced notability | listing media coverage instead of saying what happened | -| 3 | Superficial -ing analysis | "highlighting...", "underscoring...", "reflecting..." | -| 4 | Brochure language | "vibrant", "nestled", "seamless", "stunning" | -| 5 | Vague attribution | "experts argue", "observers have noted" | -| 6 | Challenges-and-outlook filler | "despite these challenges", "the future looks bright" | -| 7 | Forced triplets | three parallel fragments where one point would do | -| 8 | Overused AI vocabulary | "delve", "crucial", "landscape", "tapestry" clustering | -| 9 | Copula avoidance | "serves as", "boasts", "features" instead of "is"/"has" | -| 10 | Negative parallelisms | "not just X, it is Y"; tailing negations | -| 11 | Elegant variation | synonym-cycling when repetition is clearer | -| 12 | False ranges | "from X to Y" with no real scale | -| 13 | Reflexive passive voice | passives where the actor matters | -| 14 | Boldface spray | mechanically bolded phrases | -| 15 | Inline-header bullets | "**Label:** sentence" lists that should be prose | -| 16 | Mechanical headings | heading + one-line warm-up restating the heading | -| 17 | Emoji decoration | emojis as bullet/heading ornaments | -| 18 | Chatbot residue | "Great question!", "I hope this helps", "let's dive in" | -| 19 | Cutoff disclaimers / gap-filling | "as of my last update"; inventing plausible filler around missing facts | -| 20 | Sycophancy | flattering the reader instead of answering | -| 21 | Filler phrases | "in order to", "due to the fact that", "it is important to note" | -| 22 | Excessive hedging | "could potentially possibly" | -| 23 | Generic positive conclusions | "exciting times lie ahead" | -| 24 | Authority tropes | "at its core", "the real question is" | -| 25 | Diff-anchored writing | docs narrating a change instead of the current state | -| 26 | Staccato drama | chains of clipped fragments engineered for quotability | -| 27 | Aphorism formulas | "X is the Y of Z", "the currency of" | -| 28 | Theatrical openers | standalone "Honestly?", "Here's the thing" | - -## Voice Calibration - -If the user provides a writing sample, read it first. Match the -deeper rhythm (how the writer argues, how much context they -give, how directly they land claims, how much mess they allow), -not surface quirks. When editing a project's blog or docs and -no sample is given, read one or two existing published pieces -from the same directory; an established publication voice beats -the default. Absent both, write natural, direct, varied, -specific, and mildly opinionated where the content allows. - -## Example - -Before: - -> Additionally, this groundbreaking tool serves as a testament -> to the transformative potential of context persistence, -> ensuring seamless workflows and fostering collaboration -> across teams — from solo developers to large enterprises. - -After: - -> The tool keeps context across sessions. Solo developers use -> it to resume work without re-explaining; teams use it to -> share decisions. - -What changed: dropped the vocabulary cluster (pattern 8), the -copula avoidance (9), the -ing chain (3), the false range (12), -and the em dash; replaced abstractions with the two concrete -claims the original was gesturing at. Nothing new was invented. - -## Quality Checklist - -Before returning: - -- [ ] Mode honored (Review touched no files) -- [ ] Meaning, certainty, and coverage preserved -- [ ] No invented facts, opinions, or first-person emotion -- [ ] Protected content byte-identical -- [ ] Grep confirms no em/en dashes or smart quotes remain -- [ ] The text no longer reads as generated. If it was already - fine, you said so instead of editing diff --git a/internal/assets/claude/skills/ctx-humanize/references/pattern-catalog.md b/internal/assets/claude/skills/ctx-humanize/references/pattern-catalog.md deleted file mode 100644 index f59c6a041..000000000 --- a/internal/assets/claude/skills/ctx-humanize/references/pattern-catalog.md +++ /dev/null @@ -1,659 +0,0 @@ -# AI Writing Pattern Catalog - -The full reference behind the pattern index in SKILL.md. Read -this before any substantial rewrite. Each entry has the tell, -why it reads as generated, and a before/after pair. - -"Before" specimens intentionally contain the defects under -discussion. They are exhibits, not style. - -A single match is not a defect. Clusters are. Judge paragraphs, -not words. - -## Table of Contents - -- [Content Patterns](#content-patterns) (1-7) -- [Language and Grammar Patterns](#language-and-grammar-patterns) (8-13) -- [Style Patterns](#style-patterns) (14-17) -- [Communication Patterns](#communication-patterns) (18-20) -- [Filler and Hedging](#filler-and-hedging) (21-24) -- [Structure and Drama](#structure-and-drama) (25-28) -- [Adding Voice Without Inventing It](#adding-voice-without-inventing-it) -- [Full Worked Example](#full-worked-example) -- [Attribution](#attribution) - -## Content Patterns - -### 1. Inflated Significance - -Watch for: "stands as", "serves as", "is a testament to", -"pivotal moment", "underscores the importance of", "reflects -broader", "enduring legacy", "setting the stage for", "marking -a shift", "shaping the future", "deeply rooted", "load-bearing", -"focal point". - -LLM prose inflates ordinary facts into grand statements about -history, legacy, or trends. - -Before: - -> The Statistical Institute of Catalonia was officially -> established in 1989, marking a pivotal moment in the evolution -> of regional statistics in Spain. This initiative was part of a -> broader movement to decentralize administrative functions. - -After: - -> The Statistical Institute of Catalonia was established in 1989 -> to collect and publish regional statistics independently from -> Spain's national statistics office. - -### 2. Forced Notability - -Watch for: "independent coverage", "featured in major -publications", "active social media presence", "written by a -leading expert". - -The prose tries to prove importance by listing attention instead -of saying what happened. - -Before: - -> Her views have been cited in The New York Times, BBC, and The -> Hindu. She maintains an active social media presence with over -> 500,000 followers. - -After: - -> In a 2024 interview, she argued that AI regulation should -> focus on outcomes rather than methods. - -### 3. Superficial -ing Analysis - -Watch for: "highlighting", "underscoring", "emphasizing", -"ensuring", "reflecting", "symbolizing", "fostering", -"showcasing", "cultivating", "contributing to". - -Present-participle phrases tacked onto sentences simulate depth -without adding any. - -Before: - -> The temple's color palette of blue, green, and gold resonates -> with the region's natural beauty, symbolizing Texas bluebonnets -> and the Gulf of Mexico, reflecting the community's deep -> connection to the land. - -After: - -> The temple uses blue, green, and gold. The architect said the -> colors reference local bluebonnets and the Gulf coast. - -### 4. Brochure Language - -Watch for: "boasts", "vibrant", "profound", "nestled", "in the -heart of", "renowned", "breathtaking", "stunning", "seamless", -"intuitive", "powerful", "groundbreaking" (figurative), "rich" -(figurative), "commitment to", "natural beauty". - -The prose drifts into advertisement copy, especially for places, -products, and project summaries. - -Before: - -> Nestled within the breathtaking region of Gonder, Alamata Raya -> Kobo stands as a vibrant town with a rich cultural heritage and -> stunning natural beauty. - -After: - -> Alamata Raya Kobo is a town in the Gonder region of Ethiopia, -> known for its weekly market and 18th-century church. - -### 5. Vague Attribution - -Watch for: "experts argue", "observers have cited", "industry -reports", "some critics argue", "many believe", "it is widely -regarded", "publications have noted". - -Claims get attributed to authorities nobody can check. - -Before: - -> Due to its unique characteristics, the Haolai River is of -> interest to researchers. Experts believe it plays a crucial -> role in the regional ecosystem. - -After: - -> The Haolai River supports several endemic fish species, -> according to a 2019 survey by the Chinese Academy of Sciences. - -If no source exists, say less. Do not dress a guess as -consensus. And removing a fake attribution must not silently -strengthen the claim: asserting flatly what the source only -attributed to "observers" changes the certainty. Prefer saying -less, or a hedged agentless form ("tools like it are starting -to be treated as essential"), over a flat assertion. - -### 6. Challenges-and-Outlook Filler - -Watch for: "faces several challenges", "despite these -challenges", "future outlook", "looking ahead", "the road -ahead", "the future looks bright". - -A generic closing section that could be pasted under any topic. - -Before: - -> Despite its industrial prosperity, Korattur faces challenges -> typical of urban areas. Despite these challenges, with its -> strategic location, Korattur continues to thrive as an integral -> part of Chennai's growth. - -After: - -> Traffic congestion increased after 2015 when three new IT -> parks opened. The municipal corporation began a stormwater -> drainage project in 2022 to address recurring floods. - -### 7. Forced Triplets - -Watch for: three-part slogans, three parallel fragments, three -abstract nouns, three examples where one would do. - -> Not invention, not interaction, but execution. - -> The product improves speed, quality, and collaboration. - -Humans use threes too, so do not ban them. Remove them when they -feel decorative rather than load-bearing. - -Before: - -> The event features keynote sessions, panel discussions, and -> networking opportunities. Attendees can expect innovation, -> inspiration, and industry insights. - -After: - -> The event includes talks and panels, with time for informal -> networking between sessions. - -## Language and Grammar Patterns - -### 8. Overused AI Vocabulary - -Watch for clustering of: "additionally", "align with", -"crucial", "delve", "enhance", "fostering", "garner", -"highlight" (verb), "interplay", "intricate", "key" (generic -adjective), "landscape" (abstract), "pivotal", "showcase", -"tapestry" (abstract), "testament", "underscore" (verb), -"valuable", "vibrant", "enduring", "emphasizing". - -None of these words is banned. The tell is density: several in -one paragraph means the paragraph needs simplification. - -Before: - -> Additionally, a distinctive feature of Somali cuisine is the -> incorporation of camel meat. An enduring testament to Italian -> colonial influence is the widespread adoption of pasta in the -> local culinary landscape. - -After: - -> Somali cuisine also includes camel meat, which is considered a -> delicacy. Pasta dishes, introduced during Italian colonization, -> remain common, especially in the south. - -### 9. Copula Avoidance - -Watch for: "serves as", "stands as", "marks", "represents", -"boasts", "features", "offers". - -The model dodges plain "is", "are", and "has". - -Before: - -> Gallery 825 serves as LAAA's exhibition space for contemporary -> art. The gallery features four separate spaces and boasts over -> 3,000 square feet. - -After: - -> Gallery 825 is LAAA's exhibition space for contemporary art. -> The gallery has four rooms totaling 3,000 square feet. - -### 10. Negative Parallelisms and Tailing Negations - -"Not only X but Y", "not just X, it is Y", and clipped negations -bolted onto sentence ends. - -Before: - -> It is not just about the beat riding under the vocals; it is -> part of the aggression and atmosphere. It is not merely a song, -> it is a statement. - -After: - -> The heavy beat adds to the aggressive tone. - -Before: - -> The options come from the selected item, no guessing. - -After: - -> The options come from the selected item without forcing the -> user to guess. - -### 11. Elegant Variation - -Synonym-cycling to avoid repetition when repetition would be -clearer. - -Before: - -> The protagonist faces many challenges. The main character must -> overcome obstacles. The central figure eventually triumphs. The -> hero returns home. - -After: - -> The protagonist faces many challenges but eventually triumphs -> and returns home. - -### 12. False Ranges - -"From X to Y" where X and Y sit on no meaningful scale. - -Before: - -> Our journey has taken us from the singularity of the Big Bang -> to the grand cosmic web, from the birth and death of stars to -> the enigmatic dance of dark matter. - -After: - -> The book covers the Big Bang, star formation, and current -> theories about dark matter. - -### 13. Reflexive Passive Voice - -Passive voice is not automatically wrong. Keep it when the actor -is unknown, irrelevant, or deliberately omitted ("The files are -encrypted at rest"). Rewrite when the actor matters. - -Before: - -> The incident was resolved after the service was restarted. - -After: - -> The on-call engineer restarted the service and resolved the -> incident. - -## Style Patterns - -### 14. Boldface Spray - -Mechanically bolded phrases that direct emphasis nowhere. - -Before: - -> It blends **OKRs (Objectives and Key Results)**, **KPIs (Key -> Performance Indicators)**, and visual strategy tools such as -> the **Business Model Canvas (BMC)**. - -After: - -> It blends OKRs, KPIs, and visual strategy tools like the -> Business Model Canvas. - -### 15. Inline-Header Bullets - -Bullets that open with a bold label and colon when prose would -read better. - -Before: - -> * **User Experience:** The interface is significantly improved. -> * **Performance:** Performance is enhanced through optimized algorithms. -> * **Security:** Security is strengthened with end-to-end encryption. - -After: - -> The update improves the interface, speeds up load times through -> optimized algorithms, and adds end-to-end encryption. - -Keep lists when the structure genuinely helps the reader. Do not -collapse a useful checklist into prose just to dodge a pattern. - -### 16. Mechanical Headings - -Too many headings, generic heading names, or a heading followed -by a one-line warm-up that restates the heading. - -Before: - -> ## Performance -> -> Speed matters. -> -> When users hit a slow page, they leave. - -After: - -> ## Performance -> -> When users hit a slow page, they leave. - -Preserve the document's existing heading convention. Do not -impose one universal style. - -### 17. Emoji Decoration - -Emojis as ornaments on headings and bullets. Strip them from -prose that is not chat, and fold the content into sentences. - -## Communication Patterns - -### 18. Chatbot Residue - -Watch for: "I hope this helps", "Great question!", "Certainly!", -"You're absolutely right", "Would you like me to", "let me -know", "let's dive in", "let's explore", "here's what you need -to know", "without further ado". - -Chat-turn framing pasted into content. - -Before: - -> Great question! Here is an overview of the French Revolution. -> I hope this helps! Let me know if you would like me to expand -> on any section. - -After: - -> The French Revolution began in 1789 when financial crisis and -> food shortages led to widespread unrest. - -### 19. Cutoff Disclaimers and Speculative Gap-Filling - -Watch for: "as of my last update", "based on available -information", "while specific details are limited", "not -publicly available", "maintains a low profile", "likely grew -up", "it is believed that". - -Two related tells: capability disclaimers left in the prose, and -plausible filler written around missing information. - -Before: - -> While specific details about the company's founding are not -> extensively documented in readily available sources, it appears -> to have been established sometime in the 1990s. - -After: - -> The company was founded in 1994, according to its registration -> documents. - -When the fact is genuinely unavailable, state the absence in one -sentence or omit the section. Never backfill with "likely". - -### 20. Sycophancy - -Flattering the reader instead of answering. - -Before: - -> Great question! You're absolutely right that this is a complex -> topic. That's an excellent point about the economic factors. - -After: - -> The economic factors you mentioned are relevant here. - -## Filler and Hedging - -### 21. Filler Phrases - -Replace with the direct form: - -| Filler | Direct | -|--------|--------| -| in order to achieve this goal | to achieve this | -| due to the fact that | because | -| at this point in time | now | -| in the event that | if | -| has the ability to | can | -| it is important to note that | (delete it) | - -### 22. Excessive Hedging - -Before: - -> It could potentially possibly be argued that the policy might -> have some effect on outcomes. - -After: - -> The policy may affect outcomes. - -Keep honest uncertainty. Tighten it instead of deleting it. - -### 23. Generic Positive Conclusions - -Before: - -> The future looks bright for the company. Exciting times lie -> ahead as they continue their journey toward excellence. - -After: - -> The company plans to open two more locations next year. - -### 24. Authority Tropes - -Watch for: "the real question is", "at its core", "in reality", -"what really matters", "fundamentally", "the heart of the -matter". - -These promise insight; the next sentence usually restates an -ordinary point. - -Before: - -> The real question is whether teams can adapt. At its core, what -> really matters is organizational readiness. - -After: - -> The question is whether teams can adapt. That depends mostly on -> whether the organization is ready to change its habits. - -## Structure and Drama - -### 25. Diff-Anchored Writing - -Documentation that narrates a recent change instead of -describing the current system. Unless the document is a -changelog, release note, or migration guide, write current -state. - -Before: - -> This function was added to replace the previous approach of -> iterating through all items, which caused O(n²) performance. - -After: - -> This function uses a hash map for O(1) lookups, avoiding the -> O(n²) cost of naive iteration. - -### 26. Staccato Drama - -One short sentence for emphasis is fine. A chain of clipped -fragments feels engineered. - -Before: - -> Then AlphaEvolve arrived. It had no preference for symmetry. No -> aesthetic prior. No nostalgia for human taste. The old rules -> were gone. - -After: - -> AlphaEvolve changed the search because it did not favor -> symmetry or human-looking designs. That made some older -> assumptions less useful. - -### 27. Aphorism Formulas - -Watch for: "X is the Y of Z", "X becomes a trap", "the language -of", "the currency of", "the architecture of". - -Ordinary claims dressed as quotable profundity. - -Before: - -> Symmetry is the language of trust. Efficiency becomes a trap -> when teams forget the human layer. - -After: - -> Symmetric layouts often feel more predictable to users. Teams -> can over-optimize workflows and miss how people actually use -> them. - -### 28. Theatrical Openers - -Watch for standalone: "Honestly?", "Look,", "Here's the thing", -"Let's be honest", "Real talk". - -Fine mid-sentence in casual registers. The tell is the -theatrical standalone opener before an ordinary point. - -Before: - -> Is it worth the price? Honestly? It depends on how often you -> will use it. - -After: - -> Whether it is worth the price depends on how often you will -> use it. - -## Adding Voice Without Inventing It - -Removing tells is half the job; sterile prose can still read as -synthetic. Signs of soulless writing: every sentence the same -length and shape, no opinion where one would be natural, no -honest uncertainty, no specific detail, conclusions that sound -like press releases. - -Voice repair is allowed only within the invariants: - -- Vary rhythm. Short sentences are fine. So are long ones that - take their time. -- Swap inflated abstractions for the specific claims they gesture - at. -- Let useful asides and unresolved tension survive. -- First-person reactions, jokes, and editorial attitude may be - *kept* or *restored* when the author's material contains them. - They may not be *manufactured*. If the source is a neutral - report, the humanized version is a cleaner neutral report, not - a personal essay. When the piece would clearly benefit from a - stance the author never stated, flag it as a suggestion instead - of writing it in. - -Never inject personality into reference docs, legal text, -security reports, specs, or compliance material unless the -source already carries that voice. - -## Full Worked Example - -Before: - -> Great question! Here is an essay on this topic. I hope this -> helps! -> -> AI-assisted coding serves as an enduring testament to the -> transformative potential of large language models, marking a -> pivotal moment in the evolution of software development. In -> today's rapidly evolving technological landscape, these -> groundbreaking tools are reshaping how engineers ideate, -> iterate, and deliver, underscoring their vital role in modern -> workflows. -> -> Industry observers have noted that adoption has accelerated -> from hobbyist experiments to enterprise-wide rollouts, from -> solo developers to cross-functional teams. Additionally, the -> ability to generate documentation, tests, and refactors -> showcases the intricate interplay between automation and human -> judgment. -> -> * Speed: Code generation is significantly faster, reducing friction and empowering developers. -> * Quality: Output quality has been enhanced through improved training. -> * Adoption: Usage continues to grow, reflecting broader industry trends. -> -> While specific details are limited based on available -> information, it could potentially be argued that these tools -> might have some positive effect. In order to fully realize this -> potential, teams must align with best practices. -> -> In conclusion, the future looks bright. Exciting times lie -> ahead as we continue this journey toward excellence. Let me -> know if you would like me to expand on any section! - -First draft of the rewrite: - -> AI coding assistants can make some programming tasks faster. -> They are useful for boilerplate, test scaffolding, config -> files, and repetitive refactors. They are less useful when the -> problem requires product judgment, architecture, or domain -> context. -> -> The main risk is not that the tool is always wrong. The risk is -> that it can sound right while being wrong. A suggestion can -> compile, pass lint, and still miss the point. -> -> Productivity metrics are slippery. Accepted suggestions are not -> the same thing as correct suggestions, and correct suggestions -> are not always valuable. - -Then ask: what still sounds generated? The paragraphs land with -tidy essay symmetry, and "the main risk is not X, the risk is Y" -is a negative parallelism. One more pass: - -> AI coding assistants make the boring parts faster: boilerplate, -> test scaffolding, config files, repetitive refactors. They do -> not help much with architecture or product judgment, and they -> are good at sounding right while being wrong. A suggestion can -> compile, pass lint, and still miss the point. -> -> Treat the assistant as autocomplete for chores, not a -> substitute for review. The output still needs tests and a human -> who knows what the code is supposed to do. -> -> Be careful with the productivity numbers. Accepted suggestions -> are not correctness, and correctness is not always value. - -Note what the second pass did not do: it did not add first-person -anecdotes, invented statistics, or opinions absent from the -source. It tightened claims the source already made. - -## Attribution - -The pattern taxonomy draws on Wikipedia's "Signs of AI writing" -page, maintained by WikiProject AI Cleanup. Use external -references as guidance rather than text to paste, and follow the -source's license when quoting substantially. - -The underlying principle: LLM writing gravitates toward broadly -applicable, statistically likely phrasing. The cure is not "make -it messy". The cure is to make it specific, intentional, and -appropriate for the reader. diff --git a/internal/assets/claude/skills/ctx-implement/SKILL.md b/internal/assets/claude/skills/ctx-implement/SKILL.md index 9a9e0b907..fc4aa19a0 100644 --- a/internal/assets/claude/skills/ctx-implement/SKILL.md +++ b/internal/assets/claude/skills/ctx-implement/SKILL.md @@ -1,17 +1,14 @@ --- name: ctx-implement -description: "Execute a plan step-by-step with verification. Use when you have a plan document — canonically specs/plans/.md from /ctx-task-out — and need disciplined, checkpointed implementation." +description: "Execute a plan step-by-step with verification. Use when you have a plan document and need disciplined, checkpointed implementation." --- -Take a plan — canonically `specs/plans/.md` as written -by `/ctx-task-out`, though inline text, another file path, or a -plan from the conversation also work — and execute it -step-by-step with build/test verification between steps. +Take a plan (inline text, file path, or from the conversation) +and execute it step-by-step with build/test verification between +steps. ## When to Use -- After `/ctx-task-out` has decomposed a spec into - `specs/plans/.md` (the canonical input) - When the user provides a plan document or file and says "implement this" - When a multi-step task has been planned and needs disciplined @@ -23,9 +20,6 @@ step-by-step with build/test verification between steps. ## When NOT to Use - For single-step tasks: just do them directly -- When handed a bare multi-milestone spec instead of a plan: - suggest `/ctx-task-out --spec --milestone ` - first; decomposing on the fly is what it exists to prevent - When the plan is vague or incomplete: use `/ctx-brainstorm` first to refine it - When the user wants to explore or discuss, not execute @@ -35,7 +29,6 @@ step-by-step with build/test verification between steps. ```text /ctx-implement -/ctx-implement specs/plans/m0a.md /ctx-implement path/to/plan.md /ctx-implement (the plan from our discussion above) ``` @@ -45,14 +38,6 @@ step-by-step with build/test verification between steps. ### 1. Load the plan - If a file path is provided, read it -- If the file is a multi-milestone spec rather than a plan (no - task breakdown, no acceptance criteria, spans milestones), - redirect: suggest `/ctx-task-out --spec --milestone - ` and stop rather than improvising a decomposition -- If the plan's header shows `Status: Blocked`, stop: a - deferrable TBD graduated to blocking mid-milestone. Route its - resolution (a spec edit or DECISIONS.md entry) and a - `/ctx-task-out` amendment run before executing further tasks - If inline text is provided, use it directly - If neither, look back in the conversation for the most recent plan or approved design @@ -85,15 +70,13 @@ For each step: 2. **Think through** the change before writing code: what does it touch, what could break, what's the simplest correct path? 3. **Implement** the change -4. **Verify** with the appropriate check: - - Task from a task-out plan → its acceptance criterion, - verbatim (in addition to the map below) +3. **Verify** with the appropriate check: - Go code changed → `CGO_ENABLED=0 go build -o /dev/null ./cmd/ctx` - Tests affected → `CGO_ENABLED=0 go test ./...` - Config/template changed → build to verify embeds - Docs only → no verification needed -5. **Report** step result: pass or fail -6. **If failed**: stop, diagnose, fix, re-verify before +4. **Report** step result: pass or fail +5. **If failed**: stop, diagnose, fix, re-verify before moving to the next step Verify after every individual step before proceeding to the next. @@ -102,8 +85,6 @@ Verify after every individual step before proceeding to the next. After every 3-5 steps (or after a significant milestone): - Summarize what has been completed -- If executing `specs/plans/.md`, update the execution - ledger (see Ledger Duties below) - Note any deviations from the plan - Ask the user if they want to continue, adjust, or stop @@ -116,32 +97,6 @@ After all steps complete: - Note any deviations from the original plan - Suggest context to persist (decisions, learnings, tasks) -## Ledger Duties (plans from /ctx-task-out) - -A task-out plan is the execution ledger — the only record of -milestone progress. Executing one carries four bookkeeping duties: - -- **`st` is the record.** Flip a task's `st` cell to `[x]` only - when its acceptance criterion has demonstrably passed — the - command ran, the test is green, the behavior was observed. - Tasks obsoleted by amendment become `[o]`. `st` never moves - backwards silently; a regression is a deviation to report. -- **DoD is not yours to derive.** Scope & DoD checkboxes are - confirmed by measurement or by the user — never checked because - the tasks that "cover" them are done. The rolling-wave gate - reads DoD only; deriving it from task completion defeats the - gate. -- **Project epics outward.** TASKS.md epics carry disjoint - task-id ranges (`Plan: specs/plans/.md (Txx–Tyy)`). - When every task in a range is `[x]` or `[o]`, mark that epic - `[x]`. Sync is one-way, plan → TASKS.md; never track task - state in TASKS.md directly. -- **Amendments, not edits.** Never edit a task's acceptance - criterion in place; a criterion change goes back through - `/ctx-task-out` (amendment mode). When a measurement gate - fires (Risks & measurement gates), stop and route the outcome - through an amendment before executing dependent tasks. - ## Step Verification Map | Change type | Verification command | @@ -213,9 +168,6 @@ During execution, verify: - [ ] Each step is verified before moving on - [ ] Failures are fixed in place, not deferred - [ ] Checkpoints happen every 3-5 steps -- [ ] Task-out plans: `st` flipped only on demonstrated - acceptance; epics projected to TASKS.md when their range - completes; DoD boxes left to measurement or the user After completion, verify: - [ ] Final full verification passes diff --git a/internal/assets/claude/skills/ctx-plan/SKILL.md b/internal/assets/claude/skills/ctx-plan/SKILL.md index 1d94cdf61..4f050d468 100644 --- a/internal/assets/claude/skills/ctx-plan/SKILL.md +++ b/internal/assets/claude/skills/ctx-plan/SKILL.md @@ -8,8 +8,8 @@ description: "Stress-test a plan through adversarial interview; produces a debat The project's design-to-implementation pipeline is: ```text -/ctx-brainstorm → /ctx-plan → /ctx-spec → /ctx-task-out → /ctx-implement - (vague) (contested) (committed) (decomposed) (execution) +/ctx-brainstorm → /ctx-plan → /ctx-spec → /ctx-implement + (vague) (contested) (committed) (execution) ``` `/ctx-plan` is the second step. It takes an idea that is no @@ -17,8 +17,7 @@ longer vague but not yet committed, attacks it, and writes a *debated brief* to `.context/briefs/-.md`. The brief is consumed by `/ctx-spec --brief ` to produce the committed spec. This skill does **not** produce an implementation -plan or a task list; the deliverable is the brief. Decomposition -into tasks happens two steps later, at `/ctx-task-out`. +plan or a task list; the deliverable is the brief. Do not invert the order. A "plan" run after `/ctx-spec` is fixing the foundation while the building is up; run diff --git a/internal/assets/claude/skills/ctx-spec/SKILL.md b/internal/assets/claude/skills/ctx-spec/SKILL.md index 4d56ca7e5..1e39f84cf 100644 --- a/internal/assets/claude/skills/ctx-spec/SKILL.md +++ b/internal/assets/claude/skills/ctx-spec/SKILL.md @@ -11,18 +11,15 @@ each section with the user to produce a complete design document. The project's design-to-implementation pipeline is: ```text -/ctx-brainstorm → /ctx-plan → /ctx-spec → /ctx-task-out → /ctx-implement - (vague) (contested) (committed) (decomposed) (execution) +/ctx-brainstorm → /ctx-plan → /ctx-spec → /ctx-implement + (vague) (contested) (committed) (execution) ``` `/ctx-spec` is the third step. It consumes the *debated brief* produced by `/ctx-plan` (via `--brief `) or writes a fresh spec interactively when no brief is needed. Specs are committed artifacts under `specs/`; briefs are working state under -`.context/briefs/` that the spec absorbs. Downstream, -`/ctx-task-out` decomposes multi-milestone specs into the plan -document `/ctx-implement` executes; small specs go straight to -`/ctx-implement`. +`.context/briefs/` that the spec absorbs. Do not invert the order. A spec without a settled bet ahead of it is a wishlist; running `/ctx-plan` after `/ctx-spec` is fixing @@ -92,9 +89,6 @@ follow the brief. 4. Where the brief is silent, write `TBD` rather than inventing. 5. Write the spec to `specs/{feature-name}.md` and surface the `TBD` entries for the user to fill in next. -6. Apply the tasking handoff (step 7 of the interactive flow): - multi-milestone specs get `/ctx-task-out`, small specs go - straight to `/ctx-implement`. ## Process (interactive, when `--brief` is absent) @@ -158,14 +152,6 @@ Write the completed spec to `specs/{feature-name}.md`. - If no tasks exist yet, offer to create them: > "Want me to break this into tasks in TASKS.md?" -### 7. Hand Off to Tasking - -If the spec spans multiple milestones or more than ~one session -of implementation, do not stop at coarse task creation: recommend -`/ctx-task-out --spec specs/.md --milestone ` and -say why (specs stay concise; the plan carries decomposition). For -small specs, suggest `/ctx-implement` directly. - ## Skipping Sections Not every spec needs every section. If a section clearly does not diff --git a/internal/assets/claude/skills/ctx-task-out/SKILL.md b/internal/assets/claude/skills/ctx-task-out/SKILL.md deleted file mode 100644 index 83abced97..000000000 --- a/internal/assets/claude/skills/ctx-task-out/SKILL.md +++ /dev/null @@ -1,228 +0,0 @@ ---- -name: ctx-task-out -description: "Decompose a committed spec into a per-milestone implementation plan at specs/plans/.md — data model, contracts, invariant-test matrix, and tasks with falsifiable acceptance criteria — that /ctx-implement consumes. Use after /ctx-spec when a spec is too large to implement in one session." ---- - -## Canonical Chain - -The project's design-to-implementation pipeline is: - -```text -/ctx-brainstorm → /ctx-plan → /ctx-spec → /ctx-task-out → /ctx-implement - (vague) (contested) (committed) (decomposed) (execution) -``` - -`/ctx-task-out` is the fourth step. It consumes a committed spec -(`--spec `) and produces the *plan document* that -`/ctx-implement` executes. It closes a gap the chain otherwise -leaves unowned: `/ctx-plan` explicitly disclaims implementation -planning, `/ctx-spec` commits the what/why at spec altitude, and -`/ctx-implement` opens with "use when you have a plan document" — -this skill is what produces that document. - -Small specs skip this step. If the whole spec is implementable in -roughly one session, go straight to `/ctx-implement` with the spec -itself. - -## Role - -You decompose; you do not redesign the bet. The spec is -committed; do not relitigate scope, behavior, or the bet here — -disagreements with the spec go back through `/ctx-plan`. -Implementation structure is different: choosing schema shapes, -signatures, and index strategies is exactly the job, because -resolving those decisions *before* execution is the point of -this skill. Make every task falsifiable and every design detail -the implementer needs explicit before execution starts, so no -large decision is made mid-flight. - -Authority boundary: invariants, validation rules, and behavior -come *from the spec*. If decomposition surfaces an invariant the -spec never states, that is a spec gap — surface it and mark it -`TBD`; do not mint it here. - -## When to Use - -- After `/ctx-spec`, when the spec spans milestones/phases or - exceeds ~one session of implementation -- When a TASKS.md phase references a spec but its tasks are coarse - and carry no acceptance criteria -- When `/ctx-implement` is invoked without a plan document - (redirect here first) - -## When NOT to Use - -- Single-session features — the spec *is* the plan -- The spec is not committed yet (`/ctx-spec` first) -- The bet is still contested (`/ctx-plan` first) -- Decomposing milestone N+1 while milestone N's DoD is unmet - (see rolling-wave gate) - -## Usage - -```text -/ctx-task-out --spec specs/v1-substrate.md --milestone m0a -/ctx-task-out --spec specs/rss-feed.md # single-milestone: whole spec -``` - -Without `--milestone`, the plan file takes the spec's basename: -`specs/plans/rss-feed.md`. - -## Preconditions (hard gates — refuse, do not degrade) - -1. **Spec exists.** If `--spec` is missing or the file is absent, - stop and report; no interactive fallback. -2. **Blocking-TBD gate.** Enumerate the spec's Open Questions / - `TBD` entries and classify each as *blocking* or *deferrable* - for the target milestone. A TBD is blocking if any task in the - milestone would embed an assumption about its answer (language - choice, storage engine, schema format…). Refuse to decompose - past a blocking TBD: list the blockers, name who can resolve - them, and stop. Deferrable TBDs do not vanish: carry each into - the plan (Out of scope or Risks), annotated with the milestone - at which it becomes blocking. Resolving a blocking TBD is a - spec edit or a DECISIONS.md entry *first*; the plan only - points at that record. A resolution that exists nowhere but - the plan is minting. -3. **Rolling-wave gate.** If a prior milestone's plan exists and - its DoD is not checked off, refuse to decompose the next - milestone. The user may override explicitly; log the - override in the plan's Amendments section. Tasking distant milestones - produces fiction — the current milestone's measurements are - allowed to reshape everything downstream. - -Milestone boundaries belong to the spec. If decomposition shows -the cut is wrong — one "milestone" hiding several, or a boundary -in the wrong place — stop and route the resize through the spec; -do not mint sub-milestones here. - -## Process - -0. **Detect mode.** If the target plan file already exists, this - is an amendment run, not a fresh decomposition: read the - existing plan, classify the change as obsolete/append, re-run - only the blocking-TBD gate against the delta, and log the - change in the plan's Amendments section. The rolling-wave - gate does not fire when amending the current milestone. - Steps 1–8 below describe a fresh run. - -1. Read the spec in full. Read TASKS.md, DECISIONS.md, and - CONVENTIONS.md from the context directory. -2. Run the blocking-TBD gate; surface the classification to the - user before proceeding. -3. Draft the plan sections (structure below). Lift from the spec - verbatim where it speaks; where it is silent, prefer asking or - marking `TBD` over inventing — same authority discipline as - `/ctx-spec --brief`. -4. Break down tasks: typically 15–40 per milestone. Each task - carries: id, a state cell (`st`, initialized `[ ]` — see the - ledger rule below), title, dependencies (by id), the files/paths it - is expected to touch, a `[P]` marker when - parallelizable with its siblings, a **falsifiable acceptance - criterion** (a command to run, a test that must pass, an - observable behavior), and a reference to the spec section it - implements. Size each task to roughly one commit — small - enough that a failed acceptance check localizes the fault to - that task. `[P]` is mechanical, not aspirational: no - dependency edge, no file touched by a sibling `[P]` task, no - shared sequence (e.g. migration numbers). File disjointness - is checkable from the files column — which is also how an - amendment run detects a new task colliding with one in - flight. -5. Build the test matrix: every invariant, validation rule, and - edge case the milestone touches × the attempted violation × the - expected failure mode × the task id whose acceptance criterion - exercises it. A matrix row no task exercises is documentation, - not execution. -6. Write `specs/plans/.md` (create `specs/plans/` if - absent). -7. Sync anchors to TASKS.md: **epic-level anchors only** — one per - task cluster, each annotated `Plan: specs/plans/.md` - with its task-id range. The clusters must **partition** the - plan's task ids: every id in exactly one epic, and the range - sizes must sum to the task count — state the arithmetic in the - plan; double-counted ids make the two surfaces irreconcilable. - State the completion rule where the anchors live: an epic is - checked `[x]` only when every task in its range is `[x]` or - `[o]` in the plan — the plan is the single source of truth for - milestone progress, TASKS.md epics are projections of it. - One-way sync, plan → TASKS.md. Never duplicate the full task - list into TASKS.md; never move or delete existing entries - (CONSTITUTION). -8. Hand off: report blockers resolved/remaining and suggest - `/ctx-implement` against the plan. - -## Plan Document Structure - -```markdown -# Plan — - -**Spec:** · **Status:** Ready | Blocked -**Blocking TBDs resolved:** - -## Scope & DoD (lifted from the spec's milestone entry) -## Data model & storage (DDL, migrations, indexes) -## Contracts (API signatures, schemas, CLI surface) -## Test matrix (invariant × violation attempt × expected failure × task ref) -## Task breakdown (table: id · st · task · deps · files · [P] · acceptance criterion · spec ref) -## Risks & measurement gates (results that may reshape later tasks) -## Out of scope (deferred to later milestones, with pointers) -## Amendments (date · what · why — appended by amendment runs) -``` - -The plan is the **execution ledger**: the task table's `st` -column carries per-task state — `[ ]` pending, `[x]` done -(acceptance criterion demonstrably passed), `[o]` obsoleted by -amendment — Scope & DoD carries the DoD checkboxes, and -`/ctx-implement` updates both as it executes. A task table -without the `st` column is not a ledger: completion becomes -unrecordable and the milestone unauditable. DoD is -confirmed by measurement or by the user — never derived from -task completion — and the rolling-wave gate reads the DoD -checkboxes only. No other record of milestone progress exists. -`Status: Blocked` is reachable only by amendment: a fresh run -refuses instead of writing a Blocked plan; the status marks a -deferrable TBD that graduated to blocking mid-milestone. - -## Amendments (Mid-Milestone Changes) - -Plans meet reality; the plan document owns that contact. When a -measurement gate fires or the implementer hits a wall: - -- Tasks may be marked obsolete (`st` → `[o]`) with a one-line - reason; never deleted. -- New tasks are appended with fresh ids; ids are never reused. -- An acceptance criterion is **never edited in place** once its - task has started — weakening the test until it passes is the - failure mode this rule exists to prevent. A criterion change - is a re-invocation of `/ctx-task-out` against the same - milestone: with the plan already present, the skill operates - in amendment mode — read the existing plan, apply the change - as obsolete-and-append, and log date · what · why in the - plan's Amendments section. -- Disagreements with the *spec* discovered mid-flight still - route through `/ctx-plan`; amendments cover implementation - reality, not the bet. - -## Quality Checklist - -Before writing the file, verify: - -- [ ] Every task has a falsifiable acceptance criterion — no - "implement X" without a way to check it happened -- [ ] No task depends on an unresolved blocking TBD -- [ ] Every invariant the milestone touches appears in the test - matrix, and every matrix row is exercised by a task's - acceptance criterion (by id) -- [ ] Task ids admit a topological order — verify by listing - execution waves; `[P]` siblings share no files, edges, or - sequences -- [ ] Every task row has an `st` cell initialized `[ ]` — a - stateless table cannot be marked off or audited -- [ ] TASKS.md gained anchors only — nothing moved, nothing deleted -- [ ] Epic anchors partition the task ids (each id in exactly one - epic; range sizes sum to the task count) and the completion - rule is stated alongside them -- [ ] The plan is implementable-alone: a fresh agent holding only - the plan and the spec can state the acceptance check for - any task without asking a question diff --git a/internal/assets/commands/commands.yaml b/internal/assets/commands/commands.yaml index 06e484922..9aa6ab2a7 100644 --- a/internal/assets/commands/commands.yaml +++ b/internal/assets/commands/commands.yaml @@ -62,6 +62,18 @@ agent: ctx agent --format json # JSON output for programmatic use ctx agent --session $PPID # Cooldown scoped to calling process short: Print AI-ready context packet +ai: + long: |- + Run optional AI backend commands. + short: Run AI backend commands +ai.ping: + long: |- + Check the configured AI backend and print model reachability. + short: Check AI backend reachability +ai.propose: + long: |- + Generate a validation-only proposed-patch artifact from an input file. + short: Generate AI proposal artifact change: long: |- Show changes in context files and code since the last AI session. @@ -1538,21 +1550,6 @@ system.specsnudge: Output: agent directive (always, when .context/ is initialized) Silent when: .context/ not initialized short: Plan-to-specs directory nudge -system.statusline: - long: |- - Renders a one-line status line from the JSON payload Claude Code - pipes to the configured statusLine command on stdin. - - Segments: user@host dir | model | ctx: N% | $C.CC - Missing payload fields drop their segment; malformed input renders - a degraded line. Always exits zero (a non-zero exit would blank - the status line). Output is sanitized to bounded printable ASCII. - Informational only: no cost gating, no model suggestions - (specs/statusline.md). - - Wired by: ctx init (statusLine block in .claude/settings.local.json) - Config: .ctxrc statusline.enabled, statusline.show_cost - short: Render Claude Code status line from stdin JSON usage: long: |- Display per-session token usage statistics from stats JSONL files. diff --git a/internal/assets/commands/examples.yaml b/internal/assets/commands/examples.yaml index 12ec7f4d2..62a24c74a 100644 --- a/internal/assets/commands/examples.yaml +++ b/internal/assets/commands/examples.yaml @@ -42,6 +42,17 @@ agent: ctx agent ctx agent --budget 4000 ctx agent --format json +ai: + short: |2- + ctx ai ping + ctx ai propose transcript.md --emit decisions,learnings +ai.ping: + short: |2- + ctx ai ping + ctx ai ping --backend vllm +ai.propose: + short: |2- + ctx ai propose transcript.md --emit decisions,learnings,tasks change: short: |2- @@ -564,9 +575,6 @@ system.sessionevent: system.specsnudge: short: ' ctx system specs-nudge' -system.statusline: - short: ' ctx system statusline < payload.json' - usage: short: |2- ctx usage diff --git a/internal/assets/commands/flags.yaml b/internal/assets/commands/flags.yaml index ca903042f..222bee970 100644 --- a/internal/assets/commands/flags.yaml +++ b/internal/assets/commands/flags.yaml @@ -85,6 +85,20 @@ trigger.test.tool: short: Tool name for mock input setup.write: short: Write the configuration file instead of printing +ai.backend: + short: Backend name to use +ai.emit: + short: Comma-separated proposal kinds to emit +setup.backend: + short: Configure an AI backend in .ctxrc +setup.endpoint: + short: Backend HTTP endpoint URL +setup.api-key-env: + short: Environment variable containing the backend API key +setup.model: + short: Default model for the backend +setup.timeout: + short: Backend request timeout duration initialize.reset: short: Reset an existing context (interactive only; backs up existing files to .context/.backup-init-/ before overwriting) initialize.merge: diff --git a/internal/assets/commands/text/ui.yaml b/internal/assets/commands/text/ui.yaml index 90c1ded89..fc5c31b9a 100644 --- a/internal/assets/commands/text/ui.yaml +++ b/internal/assets/commands/text/ui.yaml @@ -252,8 +252,6 @@ init.label-project-dirs: short: Project dirs init.label-permissions: short: Permissions -init.label-statusline: - short: Status line init.label-plugin-enable: short: Plugin enablement init.label-steering: diff --git a/internal/assets/commands/text/write.yaml b/internal/assets/commands/text/write.yaml index c3655cb23..dd599c339 100644 --- a/internal/assets/commands/text/write.yaml +++ b/internal/assets/commands/text/write.yaml @@ -281,7 +281,6 @@ write.init-workflow-tips: Planning and design: /ctx-brainstorm Structured design dialogue before implementation /ctx-spec Scaffold a feature spec from the project template - /ctx-task-out Decompose a committed spec into a per-milestone plan /ctx-implement Execute a plan step-by-step with checkpointed verification Periodic maintenance: @@ -301,14 +300,6 @@ write.init-getting-started-saved: short: ' ✓ Quick-start reference saved to %s' write.init-no-changes: short: ' ○ %s (no changes needed)' -write.init-statusline-deployed: - short: ' ✓ %s (statusLine → ctx system statusline)' -write.init-statusline-backed-up: - short: ' ○ previous statusLine backed up to %s' -write.init-statusline-restored: - short: ' ○ statusLine restored from %s' -write.init-statusline-removed: - short: ' ○ %s (statusLine removed; statusline.enabled: false)' write.init-reset-prompt-header: short: 'ctx init --reset will OVERWRITE the following populated context files:' write.init-reset-prompt-dir: diff --git a/internal/assets/context/AGENT_PLAYBOOK.md b/internal/assets/context/AGENT_PLAYBOOK.md index c5e7a75b5..ab3aab9a7 100644 --- a/internal/assets/context/AGENT_PLAYBOOK.md +++ b/internal/assets/context/AGENT_PLAYBOOK.md @@ -329,9 +329,7 @@ alone. **2. Task it out**: Break the work into individual tasks in TASKS.md under a dedicated Phase section. Each task should be independently completable and -verifiable. For multi-milestone specs, run `/ctx-task-out` instead of -tasking by hand: it writes `specs/plans/.md` with falsifiable -acceptance criteria, and TASKS.md carries epic-level anchors only. +verifiable. **3. Cross-reference**: The Phase header in TASKS.md must reference the spec: `Spec: \`specs/feature-name.md\``. The first task in the phase should diff --git a/internal/assets/context/AGENT_PLAYBOOK_GATE.md b/internal/assets/context/AGENT_PLAYBOOK_GATE.md index a1fab82fa..865d50bb4 100644 --- a/internal/assets/context/AGENT_PLAYBOOK_GATE.md +++ b/internal/assets/context/AGENT_PLAYBOOK_GATE.md @@ -41,18 +41,16 @@ a spec; no exceptions. Scale the spec to the work. The design-to-implementation chain is: ```text -/ctx-brainstorm → /ctx-plan → /ctx-spec → /ctx-task-out → /ctx-implement - (vague) (contested) (committed) (decomposed) (execution) +/ctx-brainstorm → /ctx-plan → /ctx-spec → /ctx-implement + (vague) (contested) (committed) (execution) ``` `/ctx-brainstorm` shapes a vague idea into a bet. `/ctx-plan` attacks the bet and writes a debated brief to `.context/briefs/-.md`. `/ctx-spec` (optionally `--brief `) absorbs the brief into a committed spec under -`specs/`. `/ctx-task-out` decomposes a multi-milestone spec into -a per-milestone plan at `specs/plans/.md`; -single-session specs skip it. Skip the predecessors only when -the step's input is already settled. +`specs/`. Skip the predecessors only when the step's input is +already settled. ## Proactive Persistence diff --git a/internal/assets/integrations/copilot-cli/INSTRUCTIONS.md b/internal/assets/integrations/copilot-cli/INSTRUCTIONS.md index 576958218..b3f357bc5 100644 --- a/internal/assets/integrations/copilot-cli/INSTRUCTIONS.md +++ b/internal/assets/integrations/copilot-cli/INSTRUCTIONS.md @@ -6,27 +6,15 @@ ## IMPORTANT: You Have Persistent Memory This project uses Context (`ctx`) for context persistence across sessions. -When `ctx` is installed, **your memory is NOT ephemeral**: it lives in the -context directory. - -`ctx` is an optional companion tool: helpful, but never required to build, -test, or contribute to this project. If it is not installed, skip every -`ctx`-dependent instruction in this file and help with the task as usual. +**Your memory is NOT ephemeral**: it lives in the context directory. ## On Session Start -1. **Run `ctx system bootstrap`**: it tells you where the context - directory is. - - If the `ctx` command is not found: `ctx` is optional, so this is - not an error. Mention once that the user can enable persistent - context by cloning https://github.com/ActiveMemory/ctx and - following https://ctx.ist/home/getting-started/ (releases are - infrequent, so released versions may lag behind the repository). - Then continue with the user's task. - - If `ctx` is installed but returns an error: relay the error output - to the user verbatim, point them at - https://ctx.ist/home/getting-started/ for setup, and STOP. - Do not try to recover: the user decides. +1. **Run `ctx system bootstrap`**: CRITICAL, not optional. + This tells you where the context directory is. If it returns any + error, relay the error output to the user verbatim, point them at + https://ctx.ist/home/getting-started/ for setup, and STOP. + Do not try to recover: the user decides. 2. **Read AGENT_PLAYBOOK.md** from the context directory: it explains how to use this system 3. **Run `ctx agent`** for a content summary diff --git a/internal/assets/integrations/copilot-cli/skills/ctx-implement/SKILL.md b/internal/assets/integrations/copilot-cli/skills/ctx-implement/SKILL.md index 9a9e0b907..fc4aa19a0 100644 --- a/internal/assets/integrations/copilot-cli/skills/ctx-implement/SKILL.md +++ b/internal/assets/integrations/copilot-cli/skills/ctx-implement/SKILL.md @@ -1,17 +1,14 @@ --- name: ctx-implement -description: "Execute a plan step-by-step with verification. Use when you have a plan document — canonically specs/plans/.md from /ctx-task-out — and need disciplined, checkpointed implementation." +description: "Execute a plan step-by-step with verification. Use when you have a plan document and need disciplined, checkpointed implementation." --- -Take a plan — canonically `specs/plans/.md` as written -by `/ctx-task-out`, though inline text, another file path, or a -plan from the conversation also work — and execute it -step-by-step with build/test verification between steps. +Take a plan (inline text, file path, or from the conversation) +and execute it step-by-step with build/test verification between +steps. ## When to Use -- After `/ctx-task-out` has decomposed a spec into - `specs/plans/.md` (the canonical input) - When the user provides a plan document or file and says "implement this" - When a multi-step task has been planned and needs disciplined @@ -23,9 +20,6 @@ step-by-step with build/test verification between steps. ## When NOT to Use - For single-step tasks: just do them directly -- When handed a bare multi-milestone spec instead of a plan: - suggest `/ctx-task-out --spec --milestone ` - first; decomposing on the fly is what it exists to prevent - When the plan is vague or incomplete: use `/ctx-brainstorm` first to refine it - When the user wants to explore or discuss, not execute @@ -35,7 +29,6 @@ step-by-step with build/test verification between steps. ```text /ctx-implement -/ctx-implement specs/plans/m0a.md /ctx-implement path/to/plan.md /ctx-implement (the plan from our discussion above) ``` @@ -45,14 +38,6 @@ step-by-step with build/test verification between steps. ### 1. Load the plan - If a file path is provided, read it -- If the file is a multi-milestone spec rather than a plan (no - task breakdown, no acceptance criteria, spans milestones), - redirect: suggest `/ctx-task-out --spec --milestone - ` and stop rather than improvising a decomposition -- If the plan's header shows `Status: Blocked`, stop: a - deferrable TBD graduated to blocking mid-milestone. Route its - resolution (a spec edit or DECISIONS.md entry) and a - `/ctx-task-out` amendment run before executing further tasks - If inline text is provided, use it directly - If neither, look back in the conversation for the most recent plan or approved design @@ -85,15 +70,13 @@ For each step: 2. **Think through** the change before writing code: what does it touch, what could break, what's the simplest correct path? 3. **Implement** the change -4. **Verify** with the appropriate check: - - Task from a task-out plan → its acceptance criterion, - verbatim (in addition to the map below) +3. **Verify** with the appropriate check: - Go code changed → `CGO_ENABLED=0 go build -o /dev/null ./cmd/ctx` - Tests affected → `CGO_ENABLED=0 go test ./...` - Config/template changed → build to verify embeds - Docs only → no verification needed -5. **Report** step result: pass or fail -6. **If failed**: stop, diagnose, fix, re-verify before +4. **Report** step result: pass or fail +5. **If failed**: stop, diagnose, fix, re-verify before moving to the next step Verify after every individual step before proceeding to the next. @@ -102,8 +85,6 @@ Verify after every individual step before proceeding to the next. After every 3-5 steps (or after a significant milestone): - Summarize what has been completed -- If executing `specs/plans/.md`, update the execution - ledger (see Ledger Duties below) - Note any deviations from the plan - Ask the user if they want to continue, adjust, or stop @@ -116,32 +97,6 @@ After all steps complete: - Note any deviations from the original plan - Suggest context to persist (decisions, learnings, tasks) -## Ledger Duties (plans from /ctx-task-out) - -A task-out plan is the execution ledger — the only record of -milestone progress. Executing one carries four bookkeeping duties: - -- **`st` is the record.** Flip a task's `st` cell to `[x]` only - when its acceptance criterion has demonstrably passed — the - command ran, the test is green, the behavior was observed. - Tasks obsoleted by amendment become `[o]`. `st` never moves - backwards silently; a regression is a deviation to report. -- **DoD is not yours to derive.** Scope & DoD checkboxes are - confirmed by measurement or by the user — never checked because - the tasks that "cover" them are done. The rolling-wave gate - reads DoD only; deriving it from task completion defeats the - gate. -- **Project epics outward.** TASKS.md epics carry disjoint - task-id ranges (`Plan: specs/plans/.md (Txx–Tyy)`). - When every task in a range is `[x]` or `[o]`, mark that epic - `[x]`. Sync is one-way, plan → TASKS.md; never track task - state in TASKS.md directly. -- **Amendments, not edits.** Never edit a task's acceptance - criterion in place; a criterion change goes back through - `/ctx-task-out` (amendment mode). When a measurement gate - fires (Risks & measurement gates), stop and route the outcome - through an amendment before executing dependent tasks. - ## Step Verification Map | Change type | Verification command | @@ -213,9 +168,6 @@ During execution, verify: - [ ] Each step is verified before moving on - [ ] Failures are fixed in place, not deferred - [ ] Checkpoints happen every 3-5 steps -- [ ] Task-out plans: `st` flipped only on demonstrated - acceptance; epics projected to TASKS.md when their range - completes; DoD boxes left to measurement or the user After completion, verify: - [ ] Final full verification passes diff --git a/internal/assets/integrations/copilot-cli/skills/ctx-spec/SKILL.md b/internal/assets/integrations/copilot-cli/skills/ctx-spec/SKILL.md index 4d56ca7e5..1e39f84cf 100644 --- a/internal/assets/integrations/copilot-cli/skills/ctx-spec/SKILL.md +++ b/internal/assets/integrations/copilot-cli/skills/ctx-spec/SKILL.md @@ -11,18 +11,15 @@ each section with the user to produce a complete design document. The project's design-to-implementation pipeline is: ```text -/ctx-brainstorm → /ctx-plan → /ctx-spec → /ctx-task-out → /ctx-implement - (vague) (contested) (committed) (decomposed) (execution) +/ctx-brainstorm → /ctx-plan → /ctx-spec → /ctx-implement + (vague) (contested) (committed) (execution) ``` `/ctx-spec` is the third step. It consumes the *debated brief* produced by `/ctx-plan` (via `--brief `) or writes a fresh spec interactively when no brief is needed. Specs are committed artifacts under `specs/`; briefs are working state under -`.context/briefs/` that the spec absorbs. Downstream, -`/ctx-task-out` decomposes multi-milestone specs into the plan -document `/ctx-implement` executes; small specs go straight to -`/ctx-implement`. +`.context/briefs/` that the spec absorbs. Do not invert the order. A spec without a settled bet ahead of it is a wishlist; running `/ctx-plan` after `/ctx-spec` is fixing @@ -92,9 +89,6 @@ follow the brief. 4. Where the brief is silent, write `TBD` rather than inventing. 5. Write the spec to `specs/{feature-name}.md` and surface the `TBD` entries for the user to fill in next. -6. Apply the tasking handoff (step 7 of the interactive flow): - multi-milestone specs get `/ctx-task-out`, small specs go - straight to `/ctx-implement`. ## Process (interactive, when `--brief` is absent) @@ -158,14 +152,6 @@ Write the completed spec to `specs/{feature-name}.md`. - If no tasks exist yet, offer to create them: > "Want me to break this into tasks in TASKS.md?" -### 7. Hand Off to Tasking - -If the spec spans multiple milestones or more than ~one session -of implementation, do not stop at coarse task creation: recommend -`/ctx-task-out --spec specs/.md --milestone ` and -say why (specs stay concise; the plan carries decomposition). For -small specs, suggest `/ctx-implement` directly. - ## Skipping Sections Not every spec needs every section. If a section clearly does not diff --git a/internal/assets/integrations/copilot-cli/skills/ctx-task-out/SKILL.md b/internal/assets/integrations/copilot-cli/skills/ctx-task-out/SKILL.md deleted file mode 100644 index 83abced97..000000000 --- a/internal/assets/integrations/copilot-cli/skills/ctx-task-out/SKILL.md +++ /dev/null @@ -1,228 +0,0 @@ ---- -name: ctx-task-out -description: "Decompose a committed spec into a per-milestone implementation plan at specs/plans/.md — data model, contracts, invariant-test matrix, and tasks with falsifiable acceptance criteria — that /ctx-implement consumes. Use after /ctx-spec when a spec is too large to implement in one session." ---- - -## Canonical Chain - -The project's design-to-implementation pipeline is: - -```text -/ctx-brainstorm → /ctx-plan → /ctx-spec → /ctx-task-out → /ctx-implement - (vague) (contested) (committed) (decomposed) (execution) -``` - -`/ctx-task-out` is the fourth step. It consumes a committed spec -(`--spec `) and produces the *plan document* that -`/ctx-implement` executes. It closes a gap the chain otherwise -leaves unowned: `/ctx-plan` explicitly disclaims implementation -planning, `/ctx-spec` commits the what/why at spec altitude, and -`/ctx-implement` opens with "use when you have a plan document" — -this skill is what produces that document. - -Small specs skip this step. If the whole spec is implementable in -roughly one session, go straight to `/ctx-implement` with the spec -itself. - -## Role - -You decompose; you do not redesign the bet. The spec is -committed; do not relitigate scope, behavior, or the bet here — -disagreements with the spec go back through `/ctx-plan`. -Implementation structure is different: choosing schema shapes, -signatures, and index strategies is exactly the job, because -resolving those decisions *before* execution is the point of -this skill. Make every task falsifiable and every design detail -the implementer needs explicit before execution starts, so no -large decision is made mid-flight. - -Authority boundary: invariants, validation rules, and behavior -come *from the spec*. If decomposition surfaces an invariant the -spec never states, that is a spec gap — surface it and mark it -`TBD`; do not mint it here. - -## When to Use - -- After `/ctx-spec`, when the spec spans milestones/phases or - exceeds ~one session of implementation -- When a TASKS.md phase references a spec but its tasks are coarse - and carry no acceptance criteria -- When `/ctx-implement` is invoked without a plan document - (redirect here first) - -## When NOT to Use - -- Single-session features — the spec *is* the plan -- The spec is not committed yet (`/ctx-spec` first) -- The bet is still contested (`/ctx-plan` first) -- Decomposing milestone N+1 while milestone N's DoD is unmet - (see rolling-wave gate) - -## Usage - -```text -/ctx-task-out --spec specs/v1-substrate.md --milestone m0a -/ctx-task-out --spec specs/rss-feed.md # single-milestone: whole spec -``` - -Without `--milestone`, the plan file takes the spec's basename: -`specs/plans/rss-feed.md`. - -## Preconditions (hard gates — refuse, do not degrade) - -1. **Spec exists.** If `--spec` is missing or the file is absent, - stop and report; no interactive fallback. -2. **Blocking-TBD gate.** Enumerate the spec's Open Questions / - `TBD` entries and classify each as *blocking* or *deferrable* - for the target milestone. A TBD is blocking if any task in the - milestone would embed an assumption about its answer (language - choice, storage engine, schema format…). Refuse to decompose - past a blocking TBD: list the blockers, name who can resolve - them, and stop. Deferrable TBDs do not vanish: carry each into - the plan (Out of scope or Risks), annotated with the milestone - at which it becomes blocking. Resolving a blocking TBD is a - spec edit or a DECISIONS.md entry *first*; the plan only - points at that record. A resolution that exists nowhere but - the plan is minting. -3. **Rolling-wave gate.** If a prior milestone's plan exists and - its DoD is not checked off, refuse to decompose the next - milestone. The user may override explicitly; log the - override in the plan's Amendments section. Tasking distant milestones - produces fiction — the current milestone's measurements are - allowed to reshape everything downstream. - -Milestone boundaries belong to the spec. If decomposition shows -the cut is wrong — one "milestone" hiding several, or a boundary -in the wrong place — stop and route the resize through the spec; -do not mint sub-milestones here. - -## Process - -0. **Detect mode.** If the target plan file already exists, this - is an amendment run, not a fresh decomposition: read the - existing plan, classify the change as obsolete/append, re-run - only the blocking-TBD gate against the delta, and log the - change in the plan's Amendments section. The rolling-wave - gate does not fire when amending the current milestone. - Steps 1–8 below describe a fresh run. - -1. Read the spec in full. Read TASKS.md, DECISIONS.md, and - CONVENTIONS.md from the context directory. -2. Run the blocking-TBD gate; surface the classification to the - user before proceeding. -3. Draft the plan sections (structure below). Lift from the spec - verbatim where it speaks; where it is silent, prefer asking or - marking `TBD` over inventing — same authority discipline as - `/ctx-spec --brief`. -4. Break down tasks: typically 15–40 per milestone. Each task - carries: id, a state cell (`st`, initialized `[ ]` — see the - ledger rule below), title, dependencies (by id), the files/paths it - is expected to touch, a `[P]` marker when - parallelizable with its siblings, a **falsifiable acceptance - criterion** (a command to run, a test that must pass, an - observable behavior), and a reference to the spec section it - implements. Size each task to roughly one commit — small - enough that a failed acceptance check localizes the fault to - that task. `[P]` is mechanical, not aspirational: no - dependency edge, no file touched by a sibling `[P]` task, no - shared sequence (e.g. migration numbers). File disjointness - is checkable from the files column — which is also how an - amendment run detects a new task colliding with one in - flight. -5. Build the test matrix: every invariant, validation rule, and - edge case the milestone touches × the attempted violation × the - expected failure mode × the task id whose acceptance criterion - exercises it. A matrix row no task exercises is documentation, - not execution. -6. Write `specs/plans/.md` (create `specs/plans/` if - absent). -7. Sync anchors to TASKS.md: **epic-level anchors only** — one per - task cluster, each annotated `Plan: specs/plans/.md` - with its task-id range. The clusters must **partition** the - plan's task ids: every id in exactly one epic, and the range - sizes must sum to the task count — state the arithmetic in the - plan; double-counted ids make the two surfaces irreconcilable. - State the completion rule where the anchors live: an epic is - checked `[x]` only when every task in its range is `[x]` or - `[o]` in the plan — the plan is the single source of truth for - milestone progress, TASKS.md epics are projections of it. - One-way sync, plan → TASKS.md. Never duplicate the full task - list into TASKS.md; never move or delete existing entries - (CONSTITUTION). -8. Hand off: report blockers resolved/remaining and suggest - `/ctx-implement` against the plan. - -## Plan Document Structure - -```markdown -# Plan — - -**Spec:** · **Status:** Ready | Blocked -**Blocking TBDs resolved:** - -## Scope & DoD (lifted from the spec's milestone entry) -## Data model & storage (DDL, migrations, indexes) -## Contracts (API signatures, schemas, CLI surface) -## Test matrix (invariant × violation attempt × expected failure × task ref) -## Task breakdown (table: id · st · task · deps · files · [P] · acceptance criterion · spec ref) -## Risks & measurement gates (results that may reshape later tasks) -## Out of scope (deferred to later milestones, with pointers) -## Amendments (date · what · why — appended by amendment runs) -``` - -The plan is the **execution ledger**: the task table's `st` -column carries per-task state — `[ ]` pending, `[x]` done -(acceptance criterion demonstrably passed), `[o]` obsoleted by -amendment — Scope & DoD carries the DoD checkboxes, and -`/ctx-implement` updates both as it executes. A task table -without the `st` column is not a ledger: completion becomes -unrecordable and the milestone unauditable. DoD is -confirmed by measurement or by the user — never derived from -task completion — and the rolling-wave gate reads the DoD -checkboxes only. No other record of milestone progress exists. -`Status: Blocked` is reachable only by amendment: a fresh run -refuses instead of writing a Blocked plan; the status marks a -deferrable TBD that graduated to blocking mid-milestone. - -## Amendments (Mid-Milestone Changes) - -Plans meet reality; the plan document owns that contact. When a -measurement gate fires or the implementer hits a wall: - -- Tasks may be marked obsolete (`st` → `[o]`) with a one-line - reason; never deleted. -- New tasks are appended with fresh ids; ids are never reused. -- An acceptance criterion is **never edited in place** once its - task has started — weakening the test until it passes is the - failure mode this rule exists to prevent. A criterion change - is a re-invocation of `/ctx-task-out` against the same - milestone: with the plan already present, the skill operates - in amendment mode — read the existing plan, apply the change - as obsolete-and-append, and log date · what · why in the - plan's Amendments section. -- Disagreements with the *spec* discovered mid-flight still - route through `/ctx-plan`; amendments cover implementation - reality, not the bet. - -## Quality Checklist - -Before writing the file, verify: - -- [ ] Every task has a falsifiable acceptance criterion — no - "implement X" without a way to check it happened -- [ ] No task depends on an unresolved blocking TBD -- [ ] Every invariant the milestone touches appears in the test - matrix, and every matrix row is exercised by a task's - acceptance criterion (by id) -- [ ] Task ids admit a topological order — verify by listing - execution waves; `[P]` siblings share no files, edges, or - sequences -- [ ] Every task row has an `st` cell initialized `[ ]` — a - stateless table cannot be marked off or audited -- [ ] TASKS.md gained anchors only — nothing moved, nothing deleted -- [ ] Epic anchors partition the task ids (each id in exactly one - epic; range sizes sum to the task count) and the completion - rule is stated alongside them -- [ ] The plan is implementable-alone: a fresh agent holding only - the plan and the spec can state the acceptance check for - any task without asking a question diff --git a/internal/assets/permissions/allow.txt b/internal/assets/permissions/allow.txt index c3156de0c..4bdb7ee79 100644 --- a/internal/assets/permissions/allow.txt +++ b/internal/assets/permissions/allow.txt @@ -38,6 +38,5 @@ Skill(ctx-skill-audit) Skill(ctx-skill-create) Skill(ctx-spec) Skill(ctx-status) -Skill(ctx-task-out) Skill(ctx-worktree) Skill(ctx-wrap-up) diff --git a/internal/assets/project/specs-README.md b/internal/assets/project/specs-README.md index 1474f1d9d..815619d61 100644 --- a/internal/assets/project/specs-README.md +++ b/internal/assets/project/specs-README.md @@ -10,11 +10,8 @@ It's complete enough that another session could implement from it alone. 1. **Draft**: write the spec in this directory 2. **Reference**: add a Phase to TASKS.md with `Spec: specs/.md` -3. **Task out**: for multi-milestone specs, `/ctx-task-out` writes - `specs/plans/.md`; TASKS.md carries epic anchors only -4. **Implement**: follow the plan (or the spec directly for - single-session features), checking off tasks as you go -5. **Archive**: move to `specs/done/` when all tasks are complete +3. **Implement**: follow the spec, checking off tasks as you go +4. **Archive**: move to `specs/done/` when all tasks are complete ## Tips diff --git a/internal/assets/schema/ctxrc.schema.json b/internal/assets/schema/ctxrc.schema.json index ea7ad13ad..2a2a5a7f7 100644 --- a/internal/assets/schema/ctxrc.schema.json +++ b/internal/assets/schema/ctxrc.schema.json @@ -247,21 +247,6 @@ } } }, - "statusline": { - "type": "object", - "description": "Claude Code status line configuration. Informational only: renders model, context usage, and session cost; no cost gating or model-switch nudging.", - "additionalProperties": false, - "properties": { - "enabled": { - "type": "boolean", - "description": "Whether ctx init deploys (and keeps) the statusLine entry in .claude/settings.local.json. Default: true." - }, - "show_cost": { - "type": "boolean", - "description": "Whether the $ segment is rendered. Disable for screen-sharing or recorded demos. Default: true." - } - } - }, "dream": { "type": "object", "description": "ctx-dream memory-consolidation settings. Opt-in: nothing runs until enabled is true and a cron entry is installed.", diff --git a/internal/assets/schema_test.go b/internal/assets/schema_test.go index 864b72694..27a515255 100644 --- a/internal/assets/schema_test.go +++ b/internal/assets/schema_test.go @@ -74,7 +74,6 @@ func TestSchemaCoversCtxRC(t *testing.T) { Tool string `yaml:"tool"` Steering *int `yaml:"steering"` Hooks *int `yaml:"hooks"` - Statusline *int `yaml:"statusline"` ProvenanceRequired *int `yaml:"provenance_required"` Dream *int `yaml:"dream"` } diff --git a/internal/backend/backend.go b/internal/backend/backend.go new file mode 100644 index 000000000..471b25751 --- /dev/null +++ b/internal/backend/backend.go @@ -0,0 +1,104 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import errBackend "github.com/ActiveMemory/ctx/internal/err/backend" + +// SetDefault records the configured default backend name. +// +// Parameters: +// - name: configured backend name used by Default +func (registry *Registry) SetDefault(name string) { + registry.defaultName = name +} + +// RegisterBuiltin adds a built-in backend factory by type. +// +// Parameters: +// - name: configured backend name +// - config: backend configuration passed to the factory +// +// Returns: +// - error: duplicate registration or missing built-in backend +func (registry *Registry) RegisterBuiltin(name string, config Config) error { + factory, ok := builtinFactory(config.Type) + if !ok { + factory, ok = builtinFactory(name) + } + if !ok { + return errBackend.MissingBackend{Name: name} + } + return registry.Register(name, config, factory) +} + +// Register adds a backend factory and its config to the registry. +// +// Parameters: +// - name: configured backend name +// - config: backend configuration passed to the factory +// - factory: backend constructor +// +// Returns: +// - error: duplicate registration error, when name already exists +func (registry *Registry) Register( + name string, + config Config, + factory Factory, +) error { + registry.ensure() + if _, ok := registry.factories[name]; ok { + return errBackend.DuplicateRegistration{Name: name} + } + registry.factories[name] = factory + registry.configs[name] = config + return nil +} + +// Resolve returns the backend selected by name. +// +// Parameters: +// - name: configured backend name +// +// Returns: +// - Backend: resolved backend instance +// - error: missing backend or factory failure +func (registry *Registry) Resolve(name string) (Backend, error) { + registry.ensure() + factory, ok := registry.factories[name] + if !ok { + return nil, errBackend.MissingBackend{Name: name} + } + resolved, resolveErr := factory(registry.configs[name]) + if resolveErr != nil { + return nil, errBackend.Factory{Name: name, Cause: resolveErr} + } + return resolved, nil +} + +// Default resolves the registry default backend. +// +// Returns: +// - Backend: resolved default backend instance +// - error: empty registry, ambiguous registry, missing default, +// or factory failure +func (registry *Registry) Default() (Backend, error) { + registry.ensure() + if registry.defaultName != "" { + return registry.Resolve(registry.defaultName) + } + count := len(registry.factories) + if count == 0 { + return nil, errBackend.NoBackendConfigured{} + } + if count > 1 { + return nil, errBackend.MultipleBackends{} + } + for name := range registry.factories { + return registry.Resolve(name) + } + return nil, errBackend.NoBackendConfigured{} +} diff --git a/internal/backend/backend_test.go b/internal/backend/backend_test.go new file mode 100644 index 000000000..0357cf390 --- /dev/null +++ b/internal/backend/backend_test.go @@ -0,0 +1,151 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import ( + "context" + "errors" + "testing" + + errBackend "github.com/ActiveMemory/ctx/internal/err/backend" +) + +type fakeBackend struct { + name string +} + +func (backend fakeBackend) Name() string { + return backend.name +} + +func (backend fakeBackend) Ping(context.Context) error { + return nil +} + +func (backend fakeBackend) Complete( + context.Context, + Request, +) (Response, error) { + return Response{Model: backend.name}, nil +} + +func TestRegistryResolvesSingleBackendAsDefault(t *testing.T) { + registry := &Registry{} + registerTestBackend(t, registry, "vllm") + + resolved, resolveErr := registry.Default() + if resolveErr != nil { + t.Fatalf("Default() error = %v", resolveErr) + } + if resolved.Name() != "vllm" { + t.Fatalf("Default().Name() = %q", resolved.Name()) + } +} + +func TestRegistryMultipleBackendsWithoutDefaultFails(t *testing.T) { + registry := &Registry{} + registerTestBackend(t, registry, "vllm") + registerTestBackend(t, registry, "openai") + + _, resolveErr := registry.Default() + var multiple errBackend.MultipleBackends + if !errors.As(resolveErr, &multiple) { + t.Fatalf("Default() error = %T, want MultipleBackends", resolveErr) + } +} + +func TestRegistryExplicitDefault(t *testing.T) { + registry := &Registry{} + registerTestBackend(t, registry, "vllm") + registerTestBackend(t, registry, "openai") + registry.SetDefault("openai") + + resolved, resolveErr := registry.Default() + if resolveErr != nil { + t.Fatalf("Default() error = %v", resolveErr) + } + if resolved.Name() != "openai" { + t.Fatalf("Default().Name() = %q", resolved.Name()) + } +} + +func TestRegistryMissingDefault(t *testing.T) { + registry := &Registry{} + registerTestBackend(t, registry, "vllm") + registry.SetDefault("openai") + + _, resolveErr := registry.Default() + var missing errBackend.MissingBackend + if !errors.As(resolveErr, &missing) { + t.Fatalf("Default() error = %T, want MissingBackend", resolveErr) + } +} + +func TestRegistryEmptyDefault(t *testing.T) { + registry := &Registry{} + + _, resolveErr := registry.Default() + var empty errBackend.NoBackendConfigured + if !errors.As(resolveErr, &empty) { + t.Fatalf("Default() error = %T, want NoBackendConfigured", resolveErr) + } +} + +func TestRegistryMissingBackend(t *testing.T) { + registry := &Registry{} + + _, resolveErr := registry.Resolve("missing") + var missing errBackend.MissingBackend + if !errors.As(resolveErr, &missing) { + t.Fatalf("Resolve() error = %T, want MissingBackend", resolveErr) + } +} + +func TestRegistryDuplicateRegistration(t *testing.T) { + registry := &Registry{} + registerTestBackend(t, registry, "vllm") + + registerErr := registry.Register("vllm", Config{}, testFactory("vllm")) + var duplicate errBackend.DuplicateRegistration + if !errors.As(registerErr, &duplicate) { + t.Fatalf("Register() error = %T, want DuplicateRegistration", registerErr) + } +} + +func TestRegistryFactoryErrors(t *testing.T) { + factoryErr := errors.New("boom") + registry := &Registry{} + registerErr := registry.Register("vllm", Config{}, func(Config) (Backend, error) { + return nil, factoryErr + }) + if registerErr != nil { + t.Fatalf("Register() error = %v", registerErr) + } + + _, resolveErr := registry.Resolve("vllm") + var wrapped errBackend.Factory + if !errors.As(resolveErr, &wrapped) { + t.Fatalf("Resolve() error = %T, want Factory", resolveErr) + } + if !errors.Is(resolveErr, factoryErr) { + t.Fatalf("Resolve() does not wrap factory error") + } +} + +func registerTestBackend(t *testing.T, registry *Registry, name string) { + t.Helper() + registerErr := registry.Register(name, Config{Name: name}, testFactory(name)) + if registerErr != nil { + t.Fatalf("Register() error = %v", registerErr) + } +} + +func testFactory(name string) Factory { + return func(Config) (Backend, error) { + return fakeBackend{name: name}, nil + } +} diff --git a/internal/backend/builtin_internal.go b/internal/backend/builtin_internal.go new file mode 100644 index 000000000..242bf4ada --- /dev/null +++ b/internal/backend/builtin_internal.go @@ -0,0 +1,36 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import cfgBackend "github.com/ActiveMemory/ctx/internal/config/backend" + +// builtinFactory returns a built-in backend factory by name. +// +// Parameters: +// - name: backend implementation name +// +// Returns: +// - Factory: backend factory +// - bool: whether the factory exists +func builtinFactory(name string) (Factory, bool) { + switch name { + case cfgBackend.NameOpenAICompatible: + return openAICompatibleFactory, true + case cfgBackend.NameVLLM: + return vllmFactory, true + case cfgBackend.NameOpenAI: + return openAIFactory, true + case cfgBackend.NameAnthropic: + return anthropicFactory, true + case cfgBackend.NameOllama: + return ollamaFactory, true + case cfgBackend.NameLMStudio: + return lmStudioFactory, true + default: + return nil, false + } +} diff --git a/internal/backend/doc.go b/internal/backend/doc.go new file mode 100644 index 000000000..8ed75593b --- /dev/null +++ b/internal/backend/doc.go @@ -0,0 +1,13 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +// Package backend defines the optional AI backend contract and an +// internal registry for resolving configured backends. +// +// The package contains no concrete HTTP backend implementations. It is +// the dispatch seam later rc-backed configuration and ctx ai commands +// use to select a backend, ping it, and request completions. +package backend diff --git a/internal/backend/info.go b/internal/backend/info.go new file mode 100644 index 000000000..474c360ac --- /dev/null +++ b/internal/backend/info.go @@ -0,0 +1,41 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import "context" + +// PingInfo checks backend reachability and returns optional model info. +// +// Parameters: +// - ctx: request context +// - target: backend to ping +// +// Returns: +// - Response: optional ping metadata, including FirstModel when available +// - error: backend ping failure +func PingInfo(ctx context.Context, target Backend) (Response, error) { + if modelBackend, ok := target.(interface { + models(context.Context) (Response, error) + }); ok { + return modelBackend.models(ctx) + } + return Response{}, target.Ping(ctx) +} + +// EndpointInfo returns the resolved endpoint for HTTP-backed backends. +// +// Parameters: +// - target: backend to inspect +// +// Returns: +// - string: resolved endpoint when the backend exposes one +func EndpointInfo(target Backend) string { + if endpointBackend, ok := target.(interface{ endpoint() string }); ok { + return endpointBackend.endpoint() + } + return "" +} diff --git a/internal/backend/named_internal.go b/internal/backend/named_internal.go new file mode 100644 index 000000000..a7456ac6d --- /dev/null +++ b/internal/backend/named_internal.go @@ -0,0 +1,107 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import cfgBackend "github.com/ActiveMemory/ctx/internal/config/backend" + +// openAIFactory creates the named OpenAI backend wrapper. +// +// Parameters: +// - config: backend configuration +// +// Returns: +// - Backend: configured OpenAI-compatible backend +// - error: always nil; request validation happens during calls +func openAIFactory(config Config) (Backend, error) { + return openAICompatible{ + name: cfgBackend.NameOpenAI, + config: defaultConfig( + config, + cfgBackend.DefaultEndpointOpenAI, + cfgBackend.DefaultAPIKeyEnvOpenAI, + ), + }, nil +} + +// anthropicFactory creates the named Anthropic backend wrapper. +// +// Anthropic currently uses the OpenAI-compatible floor. Messages API +// specialization is deferred until backend capability detection exists. +// +// Parameters: +// - config: backend configuration +// +// Returns: +// - Backend: configured OpenAI-compatible backend +// - error: always nil; request validation happens during calls +func anthropicFactory(config Config) (Backend, error) { + return openAICompatible{ + name: cfgBackend.NameAnthropic, + config: defaultConfig( + config, + cfgBackend.DefaultEndpointAnthropic, + cfgBackend.DefaultAPIKeyEnvAnthropic, + ), + }, nil +} + +// ollamaFactory creates the named Ollama backend wrapper. +// +// Parameters: +// - config: backend configuration +// +// Returns: +// - Backend: configured OpenAI-compatible backend +// - error: always nil; request validation happens during calls +func ollamaFactory(config Config) (Backend, error) { + return openAICompatible{ + name: cfgBackend.NameOllama, + config: defaultConfig( + config, + cfgBackend.DefaultEndpointOllama, + "", + ), + }, nil +} + +// lmStudioFactory creates the named LM Studio backend wrapper. +// +// Parameters: +// - config: backend configuration +// +// Returns: +// - Backend: configured OpenAI-compatible backend +// - error: always nil; request validation happens during calls +func lmStudioFactory(config Config) (Backend, error) { + return openAICompatible{ + name: cfgBackend.NameLMStudio, + config: defaultConfig( + config, + cfgBackend.DefaultEndpointLMStudio, + "", + ), + }, nil +} + +// defaultConfig applies endpoint and auth defaults. +// +// Parameters: +// - config: caller-supplied config +// - endpoint: default endpoint when config omits one +// - apiKeyEnv: default API key env var when config omits one +// +// Returns: +// - Config: config with defaults applied +func defaultConfig(config Config, endpoint string, apiKeyEnv string) Config { + if config.Endpoint == "" { + config.Endpoint = endpoint + } + if config.APIKeyEnv == "" { + config.APIKeyEnv = apiKeyEnv + } + return config +} diff --git a/internal/backend/named_test.go b/internal/backend/named_test.go new file mode 100644 index 000000000..eb670fd3d --- /dev/null +++ b/internal/backend/named_test.go @@ -0,0 +1,123 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import ( + "testing" + + cfgBackend "github.com/ActiveMemory/ctx/internal/config/backend" +) + +func TestOpenAIFactoryDefaults(t *testing.T) { + assertNamedFactory( + t, + openAIFactory, + cfgBackend.NameOpenAI, + cfgBackend.DefaultEndpointOpenAI, + cfgBackend.DefaultAPIKeyEnvOpenAI, + ) +} + +func TestAnthropicFactoryDefaults(t *testing.T) { + assertNamedFactory( + t, + anthropicFactory, + cfgBackend.NameAnthropic, + cfgBackend.DefaultEndpointAnthropic, + cfgBackend.DefaultAPIKeyEnvAnthropic, + ) +} + +func TestOllamaFactoryDefaults(t *testing.T) { + assertNamedFactory( + t, + ollamaFactory, + cfgBackend.NameOllama, + cfgBackend.DefaultEndpointOllama, + "", + ) +} + +func TestLMStudioFactoryDefaults(t *testing.T) { + assertNamedFactory( + t, + lmStudioFactory, + cfgBackend.NameLMStudio, + cfgBackend.DefaultEndpointLMStudio, + "", + ) +} + +func TestVLLMFactoryDefaults(t *testing.T) { + assertNamedFactory( + t, + vllmFactory, + cfgBackend.NameVLLM, + cfgBackend.DefaultEndpointVLLM, + "", + ) +} + +func TestEndpointInfoReportsFactoryDefault(t *testing.T) { + backend, factoryErr := vllmFactory(Config{}) + if factoryErr != nil { + t.Fatalf("vllmFactory() error = %v", factoryErr) + } + if got := EndpointInfo(backend); got != cfgBackend.DefaultEndpointVLLM { + t.Fatalf("EndpointInfo() = %q, want %q", got, cfgBackend.DefaultEndpointVLLM) + } +} + +func TestNamedFactoryKeepsConfiguredValues(t *testing.T) { + backend, factoryErr := openAIFactory(Config{ //nolint:gosec // G101: test fixture, value is an env var name, not a credential + Endpoint: "https://example.invalid", + APIKeyEnv: "CTX_CUSTOM_KEY", + }) + if factoryErr != nil { + t.Fatalf("openAIFactory() error = %v", factoryErr) + } + wrapped := assertOpenAICompatible(t, backend) + if wrapped.config.Endpoint != "https://example.invalid" { + t.Fatalf("Endpoint = %q", wrapped.config.Endpoint) + } + if wrapped.config.APIKeyEnv != "CTX_CUSTOM_KEY" { + t.Fatalf("APIKeyEnv = %q", wrapped.config.APIKeyEnv) + } +} + +func assertNamedFactory( + t *testing.T, + factory Factory, + name string, + endpoint string, + apiKeyEnv string, +) { + t.Helper() + backend, factoryErr := factory(Config{}) + if factoryErr != nil { + t.Fatalf("factory() error = %v", factoryErr) + } + if backend.Name() != name { + t.Fatalf("Name() = %q, want %q", backend.Name(), name) + } + wrapped := assertOpenAICompatible(t, backend) + if wrapped.config.Endpoint != endpoint { + t.Fatalf("Endpoint = %q, want %q", wrapped.config.Endpoint, endpoint) + } + if wrapped.config.APIKeyEnv != apiKeyEnv { + t.Fatalf("APIKeyEnv = %q, want %q", wrapped.config.APIKeyEnv, apiKeyEnv) + } +} + +func assertOpenAICompatible(t *testing.T, backend Backend) openAICompatible { + t.Helper() + wrapped, ok := backend.(openAICompatible) + if !ok { + t.Fatalf("backend = %T, want openAICompatible", backend) + } + return wrapped +} diff --git a/internal/backend/openaicompat.go b/internal/backend/openaicompat.go new file mode 100644 index 000000000..8ad664afb --- /dev/null +++ b/internal/backend/openaicompat.go @@ -0,0 +1,107 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import ( + "context" + "encoding/json" + + cfgBackend "github.com/ActiveMemory/ctx/internal/config/backend" + errBackend "github.com/ActiveMemory/ctx/internal/err/backend" +) + +// Name returns the backend implementation name. +// +// Returns: +// - string: backend name +func (backend openAICompatible) Name() string { + return backend.name +} + +// Ping checks model-list reachability. +// +// Parameters: +// - ctx: request context +// +// Returns: +// - error: unreachable, upstream, or response decode failure +func (backend openAICompatible) Ping(ctx context.Context) error { + _, pingErr := backend.models(ctx) + return pingErr +} + +// Complete requests a chat completion. +// +// Parameters: +// - ctx: request context +// - req: completion request +// +// Returns: +// - Response: completion response +// - error: unreachable, upstream, encode, or decode failure +func (backend openAICompatible) Complete( + ctx context.Context, + req Request, +) (Response, error) { + model := req.Model + if model == "" { + model = backend.config.DefaultModel + } + payload := chatRequest{ + Model: model, + Messages: []chatMessage{{ + Role: cfgBackend.RoleUser, + Content: req.Prompt, + }}, + } + if req.Schema.Name != "" || req.Schema.Schema != nil { + payload.ResponseFormat = &responseFormat{ + Type: cfgBackend.ResponseFormatJSONSchema, + JSONSchema: &responseFormatSchema{ + Name: req.Schema.Name, + Strict: true, + Schema: req.Schema.Schema, + }, + } + } + body, marshalErr := json.Marshal(payload) + if marshalErr != nil { + return Response{}, errBackend.BadRequest{ + Name: backend.name, + Cause: marshalErr, + } + } + raw, doErr := backend.do( + ctx, + cfgBackend.HTTPMethodPost, + cfgBackend.ChatCompletionsPath, + body, + ) + if doErr != nil { + return Response{}, doErr + } + var decoded chatResponse + if decodeErr := json.Unmarshal(raw, &decoded); decodeErr != nil { + return Response{}, errBackend.BadRequest{ + Name: backend.name, + Cause: decodeErr, + } + } + if decoded.Model == "" || + len(decoded.Choices) == 0 || + decoded.Choices[0].Message.Content == "" { + return Response{}, errBackend.BadRequest{ + Name: backend.name, + Cause: errBackend.InvalidResponseShape(), + } + } + text := "" + if len(decoded.Choices) > 0 { + text = decoded.Choices[0].Message.Content + } + return Response{Model: decoded.Model, Text: text, Raw: raw}, nil +} diff --git a/internal/backend/openaicompat_internal.go b/internal/backend/openaicompat_internal.go new file mode 100644 index 000000000..cfef5ab2a --- /dev/null +++ b/internal/backend/openaicompat_internal.go @@ -0,0 +1,217 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import ( + "bytes" + "context" + "encoding/json" + "io" + "net/http" + "net/url" + "os" + pathpkg "path" + "strings" + "time" + + cfgBackend "github.com/ActiveMemory/ctx/internal/config/backend" + cfgHTTP "github.com/ActiveMemory/ctx/internal/config/http" + cfgWarn "github.com/ActiveMemory/ctx/internal/config/warn" + errBackend "github.com/ActiveMemory/ctx/internal/err/backend" + logWarn "github.com/ActiveMemory/ctx/internal/log/warn" +) + +// openAICompatibleFactory creates a generic OpenAI-compatible backend. +// +// Parameters: +// - config: backend configuration +// +// Returns: +// - Backend: configured backend +// - error: always nil; request validation happens during calls +func openAICompatibleFactory(config Config) (Backend, error) { + return openAICompatible{ + name: cfgBackend.NameOpenAICompatible, + config: config, + }, nil +} + +// models requests the model list and extracts the first model. +// +// Parameters: +// - ctx: request context +// +// Returns: +// - Response: model-list response with FirstModel set when present +// - error: unreachable, upstream, or decode failure +func (backend openAICompatible) models(ctx context.Context) (Response, error) { + raw, doErr := backend.do( + ctx, + cfgBackend.HTTPMethodGet, + cfgBackend.ModelsPath, + nil, + ) + if doErr != nil { + return Response{}, doErr + } + var decoded modelsResponse + if decodeErr := json.Unmarshal(raw, &decoded); decodeErr != nil { + return Response{}, errBackend.BadRequest{ + Name: backend.name, + Cause: decodeErr, + } + } + firstModel := "" + if len(decoded.Data) > 0 { + firstModel = decoded.Data[0].ID + } + return Response{FirstModel: firstModel, Raw: raw}, nil +} + +// do sends a backend HTTP request and returns the raw response body. +// +// Parameters: +// - ctx: request context +// - method: HTTP method constant +// - path: endpoint path constant +// - body: optional JSON request body +// +// Returns: +// - []byte: raw response body +// - error: endpoint, transport, read, or upstream status error +func (backend openAICompatible) do( + ctx context.Context, + method string, + path string, + body []byte, +) ([]byte, error) { + endpoint, endpointErr := backend.url(path) + if endpointErr != nil { + return nil, endpointErr + } + requestBody := io.Reader(nil) + if body != nil { + requestBody = bytes.NewReader(body) + } + request, requestErr := http.NewRequestWithContext( + ctx, + method, + endpoint, + requestBody, + ) + if requestErr != nil { + return nil, errBackend.InvalidEndpoint{ + Endpoint: backend.config.Endpoint, + Cause: requestErr, + } + } + backend.headers(request, body != nil) + client := http.Client{Timeout: backend.timeout()} + response, doErr := client.Do(request) + if doErr != nil { + return nil, errBackend.Unreachable{ + Name: backend.name, + Endpoint: backend.config.Endpoint, + Cause: doErr, + } + } + defer func() { + if closeErr := response.Body.Close(); closeErr != nil { + logWarn.Warn(cfgWarn.CloseResponse, closeErr) + } + }() + raw, readErr := io.ReadAll( + io.LimitReader(response.Body, cfgBackend.MaxResponseBytes), + ) + if readErr != nil { + return nil, errBackend.BadRequest{Name: backend.name, Cause: readErr} + } + if response.StatusCode < http.StatusOK || + response.StatusCode >= http.StatusMultipleChoices { + return nil, errBackend.Upstream{ + Name: backend.name, + StatusCode: response.StatusCode, + Body: string(raw), + } + } + return raw, nil +} + +// headers applies optional JSON and authorization headers. +// +// Parameters: +// - request: outbound HTTP request +// - hasBody: whether the request has a JSON body +func (backend openAICompatible) headers( + request *http.Request, + hasBody bool, +) { + if hasBody { + request.Header.Set( + cfgBackend.HeaderContentType, + cfgBackend.ContentTypeJSON, + ) + } + if backend.config.APIKeyEnv == "" { + return + } + apiKey := os.Getenv(backend.config.APIKeyEnv) + if apiKey == "" { + return + } + request.Header.Set( + cfgBackend.HeaderAuthorization, + cfgBackend.AuthorizationBearerPrefix+apiKey, + ) +} + +// timeout parses the configured timeout with a safe fallback. +// +// Returns: +// - time.Duration: configured or default timeout +func (backend openAICompatible) timeout() time.Duration { + parsed, parseErr := time.ParseDuration(backend.config.Timeout) + if parseErr != nil || parsed <= 0 { + return cfgBackend.DefaultTimeout + } + return parsed +} + +// endpoint returns the fully defaulted backend endpoint. +// +// Returns: +// - string: configured endpoint after factory defaults +func (backend openAICompatible) endpoint() string { + return backend.config.Endpoint +} + +// url combines the configured endpoint with an API path. +// +// Parameters: +// - apiPath: endpoint path constant +// +// Returns: +// - string: absolute request URL +// - error: invalid endpoint error +func (backend openAICompatible) url(apiPath string) (string, error) { + parsed, parseErr := url.Parse(backend.config.Endpoint) + if parseErr != nil { + return "", errBackend.InvalidEndpoint{ + Endpoint: backend.config.Endpoint, + Cause: parseErr, + } + } + if parsed.Scheme != cfgHTTP.SchemeHTTP && + parsed.Scheme != cfgHTTP.SchemeHTTPS { + return "", errBackend.InvalidEndpoint{ + Endpoint: backend.config.Endpoint, + } + } + basePath := strings.TrimSuffix(parsed.Path, cfgHTTP.PathSepStr) + parsed.Path = pathpkg.Join(basePath, apiPath) + return parsed.String(), nil +} diff --git a/internal/backend/openaicompat_test.go b/internal/backend/openaicompat_test.go new file mode 100644 index 000000000..7ec1ec311 --- /dev/null +++ b/internal/backend/openaicompat_test.go @@ -0,0 +1,323 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import ( + "context" + "encoding/json" + "errors" + "net/http" + "net/http/httptest" + "strings" + "testing" + "time" + + cfgAI "github.com/ActiveMemory/ctx/internal/config/ai" + cfgBackend "github.com/ActiveMemory/ctx/internal/config/backend" + errBackend "github.com/ActiveMemory/ctx/internal/err/backend" +) + +func TestOpenAICompatiblePingSuccess(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func( + w http.ResponseWriter, + r *http.Request, + ) { + if r.Method != http.MethodGet { + t.Fatalf("method = %s, want GET", r.Method) + } + if r.URL.Path != cfgBackend.ModelsPath { + t.Fatalf("path = %s, want %s", r.URL.Path, cfgBackend.ModelsPath) + } + _, writeErr := w.Write([]byte(`{"data":[{"id":"first"}]}`)) + if writeErr != nil { + t.Fatalf("Write() error = %v", writeErr) + } + })) + defer server.Close() + backend := testOpenAIBackend(t, Config{Endpoint: server.URL}) + + pingErr := backend.Ping(context.Background()) + if pingErr != nil { + t.Fatalf("Ping() error = %v", pingErr) + } +} + +func TestOpenAICompatibleCompleteSuccess(t *testing.T) { + t.Setenv("CTX_TEST_API_KEY", "token") + server := httptest.NewServer(http.HandlerFunc(func( + w http.ResponseWriter, + r *http.Request, + ) { + if r.Method != http.MethodPost { + t.Fatalf("method = %s, want POST", r.Method) + } + if r.URL.Path != cfgBackend.ChatCompletionsPath { + t.Fatalf( + "path = %s, want %s", + r.URL.Path, + cfgBackend.ChatCompletionsPath, + ) + } + if got := r.Header.Get(cfgBackend.HeaderAuthorization); got == "" { + t.Fatalf("authorization header missing") + } + var request chatRequest + decodeErr := json.NewDecoder(r.Body).Decode(&request) + if decodeErr != nil { + t.Fatalf("Decode() error = %v", decodeErr) + } + if request.Model != "configured-model" { + t.Fatalf("model = %q", request.Model) + } + if request.ResponseFormat == nil || request.ResponseFormat.JSONSchema == nil { + t.Fatalf("response_format missing") + } + if request.ResponseFormat.Type != cfgBackend.ResponseFormatJSONSchema { + t.Fatalf("response_format type = %q", request.ResponseFormat.Type) + } + if !strings.Contains(string(request.ResponseFormat.JSONSchema.Schema), `"rows"`) || + !strings.Contains(string(request.ResponseFormat.JSONSchema.Schema), `"metadata"`) { + t.Fatalf("schema = %s", string(request.ResponseFormat.JSONSchema.Schema)) + } + _, writeErr := w.Write([]byte(`{"model":"configured-model","choices":[{"message":{"content":"ok"}}]}`)) + if writeErr != nil { + t.Fatalf("Write() error = %v", writeErr) + } + })) + defer server.Close() + backend := testOpenAIBackend(t, Config{ //nolint:gosec // G101: test fixture, value is an env var name, not a credential + Endpoint: server.URL, + APIKeyEnv: "CTX_TEST_API_KEY", + DefaultModel: "configured-model", + }) + + response, completeErr := backend.Complete( + context.Background(), + Request{Prompt: "hello", Schema: Schema{Name: "proposal", Schema: json.RawMessage(cfgAI.ProposalSchema)}}, + ) + if completeErr != nil { + t.Fatalf("Complete() error = %v", completeErr) + } + if response.Model != "configured-model" { + t.Fatalf("Model = %q", response.Model) + } + if response.Text != "ok" { + t.Fatalf("Text = %q", response.Text) + } +} + +func TestOpenAICompatibleUpstream4xxBody(t *testing.T) { + backend := testStatusBackend(t, http.StatusUnauthorized, "nope") + + _, completeErr := backend.Complete(context.Background(), Request{}) + assertUpstreamBody(t, completeErr, "nope") +} + +func TestOpenAICompatibleUpstream5xxBody(t *testing.T) { + backend := testStatusBackend(t, http.StatusBadGateway, "bad gateway") + + _, completeErr := backend.Complete(context.Background(), Request{}) + assertUpstreamBody(t, completeErr, "bad gateway") +} + +func TestOpenAICompatibleUnreachableServer(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func( + http.ResponseWriter, + *http.Request, + ) { + })) + endpoint := server.URL + server.Close() + backend := testOpenAIBackend(t, Config{Endpoint: endpoint}) + + pingErr := backend.Ping(context.Background()) + var unreachable errBackend.Unreachable + if !errors.As(pingErr, &unreachable) { + t.Fatalf("Ping() error = %T, want Unreachable", pingErr) + } +} + +func TestOpenAICompatibleInvalidEndpointScheme(t *testing.T) { + backend := testOpenAIBackend(t, Config{Endpoint: "file:///tmp/socket"}) + + pingErr := backend.Ping(context.Background()) + var invalid errBackend.InvalidEndpoint + if !errors.As(pingErr, &invalid) { + t.Fatalf("Ping() error = %T, want InvalidEndpoint", pingErr) + } +} + +func TestOpenAICompatibleTimeout(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func( + w http.ResponseWriter, + r *http.Request, + ) { + time.Sleep(20 * time.Millisecond) + _, writeErr := w.Write([]byte(`{"data":[]}`)) + if writeErr != nil { + t.Fatalf("Write() error = %v", writeErr) + } + })) + defer server.Close() + backend := testOpenAIBackend(t, Config{ + Endpoint: server.URL, + Timeout: "1ms", + }) + + pingErr := backend.Ping(context.Background()) + var unreachable errBackend.Unreachable + if !errors.As(pingErr, &unreachable) { + t.Fatalf("Ping() error = %T, want Unreachable", pingErr) + } +} + +func TestOpenAICompatiblePingJoinsEndpointBasePath(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func( + w http.ResponseWriter, + r *http.Request, + ) { + if r.URL.Path != "/proxy/openai"+cfgBackend.ModelsPath { + t.Fatalf( + "path = %s, want %s", + r.URL.Path, + "/proxy/openai"+cfgBackend.ModelsPath, + ) + } + _, writeErr := w.Write([]byte(`{"data":[{"id":"first"}]}`)) + if writeErr != nil { + t.Fatalf("Write() error = %v", writeErr) + } + })) + defer server.Close() + backend := testOpenAIBackend(t, Config{Endpoint: server.URL + "/proxy/openai"}) + + pingErr := backend.Ping(context.Background()) + if pingErr != nil { + t.Fatalf("Ping() error = %v", pingErr) + } +} + +func TestOpenAICompatibleCompleteJoinsEndpointBasePath(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func( + w http.ResponseWriter, + r *http.Request, + ) { + if r.URL.Path != "/proxy/openai"+cfgBackend.ChatCompletionsPath { + t.Fatalf( + "path = %s, want %s", + r.URL.Path, + "/proxy/openai"+cfgBackend.ChatCompletionsPath, + ) + } + _, writeErr := w.Write([]byte( + `{"model":"configured-model","choices":[{"message":{"content":"ok"}}]}`, + )) + if writeErr != nil { + t.Fatalf("Write() error = %v", writeErr) + } + })) + defer server.Close() + backend := testOpenAIBackend(t, Config{ + Endpoint: server.URL + "/proxy/openai/", + DefaultModel: "configured-model", + }) + + response, completeErr := backend.Complete( + context.Background(), + Request{Prompt: "hello"}, + ) + if completeErr != nil { + t.Fatalf("Complete() error = %v", completeErr) + } + if response.Text != "ok" { + t.Fatalf("Text = %q", response.Text) + } +} + +func TestOpenAICompatibleRequestModelOverride(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func( + w http.ResponseWriter, + r *http.Request, + ) { + var request chatRequest + decodeErr := json.NewDecoder(r.Body).Decode(&request) + if decodeErr != nil { + t.Fatalf("Decode() error = %v", decodeErr) + } + if request.Model != "override-model" { + t.Fatalf("model = %q", request.Model) + } + _, writeErr := w.Write([]byte( + `{"model":"override-model","choices":[{"message":{"content":"ok"}}]}`, + )) + if writeErr != nil { + t.Fatalf("Write() error = %v", writeErr) + } + })) + defer server.Close() + backend := testOpenAIBackend(t, Config{ + Endpoint: server.URL, + DefaultModel: "configured-model", + }) + + response, completeErr := backend.Complete( + context.Background(), + Request{Model: "override-model"}, + ) + if completeErr != nil { + t.Fatalf("Complete() error = %v", completeErr) + } + if response.Model != "override-model" { + t.Fatalf("Model = %q", response.Model) + } +} + +func TestVLLMFactoryNameBehavior(t *testing.T) { + backend, factoryErr := vllmFactory(Config{}) + if factoryErr != nil { + t.Fatalf("vllmFactory() error = %v", factoryErr) + } + if backend.Name() != cfgBackend.NameVLLM { + t.Fatalf("Name() = %q", backend.Name()) + } +} + +func testOpenAIBackend(t *testing.T, config Config) Backend { + t.Helper() + backend, factoryErr := openAICompatibleFactory(config) + if factoryErr != nil { + t.Fatalf("openAICompatibleFactory() error = %v", factoryErr) + } + return backend +} + +func testStatusBackend(t *testing.T, status int, body string) Backend { + t.Helper() + server := httptest.NewServer(http.HandlerFunc(func( + w http.ResponseWriter, + r *http.Request, + ) { + w.WriteHeader(status) + _, writeErr := w.Write([]byte(body)) + if writeErr != nil { + t.Fatalf("Write() error = %v", writeErr) + } + })) + t.Cleanup(server.Close) + return testOpenAIBackend(t, Config{Endpoint: server.URL}) +} + +func assertUpstreamBody(t *testing.T, targetErr error, body string) { + t.Helper() + var upstream errBackend.Upstream + if !errors.As(targetErr, &upstream) { + t.Fatalf("error = %T, want Upstream", targetErr) + } + if upstream.Body != body { + t.Fatalf("Body = %q", upstream.Body) + } +} diff --git a/internal/backend/registry_internal.go b/internal/backend/registry_internal.go new file mode 100644 index 000000000..a1c37b99b --- /dev/null +++ b/internal/backend/registry_internal.go @@ -0,0 +1,20 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +// ensure initializes the registry's maps for zero-value use. +// +// Parameters: +// - registry: registry receiver to initialize +func (registry *Registry) ensure() { + if registry.factories == nil { + registry.factories = make(map[string]Factory) + } + if registry.configs == nil { + registry.configs = make(map[string]Config) + } +} diff --git a/internal/backend/types.go b/internal/backend/types.go new file mode 100644 index 000000000..d16cf7904 --- /dev/null +++ b/internal/backend/types.go @@ -0,0 +1,131 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import ( + "context" + "encoding/json" +) + +// Backend is the AI completion backend contract. +type Backend interface { + Name() string + Ping(ctx context.Context) error + Complete(ctx context.Context, req Request) (Response, error) +} + +// Factory builds a backend from registry configuration. +type Factory func(Config) (Backend, error) + +// Config carries rc-backed backend settings into backend factories. +// +// Fields: +// - Name: configured backend name +// - Type: registered backend implementation type +// - Endpoint: backend HTTP endpoint, when applicable +// - APIKeyEnv: environment variable name for credentials +// - Timeout: request timeout duration string from configuration +// - DefaultModel: model selected when a request omits one +type Config struct { + Name string + Type string + Endpoint string + APIKeyEnv string + Timeout string + DefaultModel string +} + +// Request describes a backend completion request. +// +// Fields: +// - Model: model override for this request +// - Prompt: input prompt text +// - Schema: optional JSON schema for structured output +type Request struct { + Model string + Prompt string + Schema Schema +} + +// Schema carries a structured-output schema definition. +type Schema struct { + Name string + Schema json.RawMessage +} + +// Response describes a backend completion response. +// +// Fields: +// - Model: model that produced the response +// - Text: completion text +// - Raw: optional raw provider payload +type Response struct { + Model string + Text string + Raw []byte + FirstModel string +} + +// Registry stores backend factories and resolves configured backends. +type Registry struct { + factories map[string]Factory + configs map[string]Config + defaultName string +} + +// openAICompatible is an OpenAI-compatible HTTP backend. +type openAICompatible struct { + name string + config Config +} + +// modelsResponse is the OpenAI-compatible /v1/models response. +type modelsResponse struct { + Data []modelInfo `json:"data"` +} + +// modelInfo is a single model entry. +type modelInfo struct { + ID string `json:"id"` +} + +// chatRequest is the OpenAI-compatible chat completion request. +type chatRequest struct { + Model string `json:"model"` + Messages []chatMessage `json:"messages"` + ResponseFormat *responseFormat `json:"response_format,omitempty"` +} + +// responseFormat encodes an OpenAI-compatible structured output schema. +type responseFormat struct { + Type string `json:"type"` + JSONSchema *responseFormatSchema `json:"json_schema,omitempty"` +} + +// responseFormatSchema is the structured output schema wrapper. +type responseFormatSchema struct { + Name string `json:"name"` + Strict bool `json:"strict"` + Schema json.RawMessage `json:"schema"` +} + +// chatMessage is a chat message in an OpenAI-compatible payload. +type chatMessage struct { + Role string `json:"role"` + Content string `json:"content"` +} + +// chatResponse is the OpenAI-compatible chat completion response. +type chatResponse struct { + Model string `json:"model"` + Choices []chatChoice `json:"choices"` +} + +// chatChoice is one chat completion candidate. +type chatChoice struct { + Message chatMessage `json:"message"` +} diff --git a/internal/backend/vllm.go b/internal/backend/vllm.go new file mode 100644 index 000000000..add3b7e17 --- /dev/null +++ b/internal/backend/vllm.go @@ -0,0 +1,24 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import cfgBackend "github.com/ActiveMemory/ctx/internal/config/backend" + +// vllmFactory creates the canonical local vLLM backend. +// +// Parameters: +// - config: backend configuration +// +// Returns: +// - Backend: configured vLLM backend +// - error: always nil; request validation happens during calls +func vllmFactory(config Config) (Backend, error) { + return openAICompatible{ + name: cfgBackend.NameVLLM, + config: defaultConfig(config, cfgBackend.DefaultEndpointVLLM, ""), + }, nil +} diff --git a/internal/bootstrap/group.go b/internal/bootstrap/group.go index 802894b91..766959fe9 100644 --- a/internal/bootstrap/group.go +++ b/internal/bootstrap/group.go @@ -8,6 +8,7 @@ package bootstrap import ( "github.com/ActiveMemory/ctx/internal/cli/agent" + "github.com/ActiveMemory/ctx/internal/cli/ai" "github.com/ActiveMemory/ctx/internal/cli/change" "github.com/ActiveMemory/ctx/internal/cli/compact" "github.com/ActiveMemory/ctx/internal/cli/config" @@ -151,6 +152,7 @@ func runtimeCmds() []registration { // connect, mcp, watch, and loop commands func integrations() []registration { return []registration{ + {ai.Cmd, embedCmd.GroupIntegration}, {setup.Cmd, embedCmd.GroupIntegration}, {steering.Cmd, embedCmd.GroupIntegration}, {trigger.Cmd, embedCmd.GroupIntegration}, diff --git a/internal/claude/types.go b/internal/claude/types.go index 11fccf447..66b3546ea 100644 --- a/internal/claude/types.go +++ b/internal/claude/types.go @@ -66,23 +66,6 @@ type PermissionsConfig struct { Deny []string `json:"deny,omitempty"` } -// StatusLineConfig represents the statusLine section of Claude Code's -// settings.local.json. -// -// Claude Code pipes a JSON payload to the configured command on stdin -// and displays the first line of its stdout as the status line. See -// https://code.claude.com/docs/en/statusline for the payload schema. -// -// Fields: -// - Type: Entry type, "command" for executable status lines -// - Command: Shell command Claude Code runs on each status refresh -// - Padding: Optional horizontal padding override -type StatusLineConfig struct { - Type string `json:"type,omitempty"` - Command string `json:"command,omitempty"` - Padding *int `json:"padding,omitempty"` -} - // Settings represents the full Claude Code settings.local.json structure. // // This is used when reading or writing project-level Claude Code configuration. @@ -90,9 +73,7 @@ type StatusLineConfig struct { // Fields: // - Hooks: Hook configuration for lifecycle events // - Permissions: Tool permission configuration -// - StatusLine: Status line command configuration type Settings struct { Hooks HookConfig `json:"hooks,omitempty"` Permissions PermissionsConfig `json:"permissions,omitempty"` - StatusLine *StatusLineConfig `json:"statusLine,omitempty"` } diff --git a/internal/cli/ai/ai.go b/internal/cli/ai/ai.go new file mode 100644 index 000000000..04c77c98d --- /dev/null +++ b/internal/cli/ai/ai.go @@ -0,0 +1,21 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package ai + +import ( + "github.com/spf13/cobra" + + aiRoot "github.com/ActiveMemory/ctx/internal/cli/ai/cmd/root" +) + +// Cmd returns the ctx ai command. +// +// Returns: +// - *cobra.Command: configured ai command +func Cmd() *cobra.Command { + return aiRoot.Cmd() +} diff --git a/internal/cli/ai/cmd/root/cmd.go b/internal/cli/ai/cmd/root/cmd.go new file mode 100644 index 000000000..9e34e4dc2 --- /dev/null +++ b/internal/cli/ai/cmd/root/cmd.go @@ -0,0 +1,64 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package root + +import ( + "github.com/spf13/cobra" + + "github.com/ActiveMemory/ctx/internal/assets/read/desc" + "github.com/ActiveMemory/ctx/internal/config/embed/cmd" + "github.com/ActiveMemory/ctx/internal/config/embed/flag" + cFlag "github.com/ActiveMemory/ctx/internal/config/flag" + "github.com/ActiveMemory/ctx/internal/flagbind" +) + +// Cmd returns the ctx ai command tree. +// +// Returns: +// - *cobra.Command: configured ai command with subcommands +func Cmd() *cobra.Command { + short, long := desc.Command(cmd.DescKeyAI) + c := &cobra.Command{ + Use: cmd.UseAI, + Short: short, + Long: long, + } + var backendName string + pingShort, pingLong := desc.Command(cmd.DescKeyAIPing) + ping := &cobra.Command{ + Use: cmd.UseAIPing, + Short: pingShort, + Long: pingLong, + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + return RunPing(cmd, backendName) + }, + } + flagbind.StringFlag(ping, &backendName, cFlag.Backend, flag.DescKeyAIBackend) + var proposeBackend string + var emit string + proposeShort, proposeLong := desc.Command(cmd.DescKeyAIPropose) + propose := &cobra.Command{ + Use: cmd.UseAIPropose, + Short: proposeShort, + Long: proposeLong, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + return RunPropose(cmd, args[0], proposeBackend, emit) + }, + } + flagbind.StringFlag( + propose, + &proposeBackend, + cFlag.Backend, + flag.DescKeyAIBackend, + ) + flagbind.StringFlag(propose, &emit, cFlag.Emit, flag.DescKeyAIEmit) + c.AddCommand(ping) + c.AddCommand(propose) + return c +} diff --git a/internal/cli/ai/cmd/root/doc.go b/internal/cli/ai/cmd/root/doc.go new file mode 100644 index 000000000..798398887 --- /dev/null +++ b/internal/cli/ai/cmd/root/doc.go @@ -0,0 +1,12 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +// Package root defines the ctx ai command tree. +// +// It contains only cobra command construction and Run wrappers. Backend +// resolution and proposal writing live in core subpackages. +// Subcommands are constructed inline to keep cmd/ free of helper APIs. +package root diff --git a/internal/cli/ai/cmd/root/root_test.go b/internal/cli/ai/cmd/root/root_test.go new file mode 100644 index 000000000..7124b091d --- /dev/null +++ b/internal/cli/ai/cmd/root/root_test.go @@ -0,0 +1,230 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package root + +import ( + "bytes" + "encoding/json" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/ActiveMemory/ctx/internal/rc" +) + +func TestNoBackendConfiguredFails(t *testing.T) { + chdirProject(t) + + _, runErr := executeAI(t, "ping") + if runErr == nil { + t.Fatalf("ping without backend should fail") + } +} + +func TestMultipleBackendsWithoutDefaultFails(t *testing.T) { + project := chdirProject(t) + writeCtxRC(t, project, multipleBackendsYAML()) + + _, runErr := executeAI(t, "ping") + if runErr == nil { + t.Fatalf("ping with ambiguous backends should fail") + } +} + +func TestPingSucceeds(t *testing.T) { + project := chdirProject(t) + server := modelsServer(t) + t.Cleanup(server.Close) + writeCtxRC(t, project, singleBackendYAML(server.URL)) + + out, runErr := executeAI(t, "ping") + if runErr != nil { + t.Fatalf("ping failed: %v", runErr) + } + for _, want := range []string{"vllm", server.URL, "model-a"} { + if !strings.Contains(out, want) { + t.Fatalf("output missing %q: %q", want, out) + } + } +} + +func TestProposeWritesArtifactOnly(t *testing.T) { + project := chdirProject(t) + server := completionServer(t) + t.Cleanup(server.Close) + writeCtxRC(t, project, singleBackendYAML(server.URL)) + contextFile := filepath.Join(project, ".context", "DECISIONS.md") + before, readErr := os.ReadFile(contextFile) + if readErr != nil { + t.Fatalf("ReadFile() error = %v", readErr) + } + input := filepath.Join(project, "input.txt") + if writeErr := os.WriteFile(input, []byte("source"), 0o644); writeErr != nil { + t.Fatalf("WriteFile() error = %v", writeErr) + } + + _, runErr := executeAI( + t, + "propose", + input, + "--emit", + "decisions,learnings,tasks,open-questions", + ) + if runErr != nil { + t.Fatalf("propose failed: %v", runErr) + } + after, readErr := os.ReadFile(contextFile) + if readErr != nil { + t.Fatalf("ReadFile() error = %v", readErr) + } + if string(before) != string(after) { + t.Fatalf("context file changed") + } + entries, readDirErr := os.ReadDir( + filepath.Join(project, ".context", "proposals", "ai"), + ) + if readDirErr != nil { + t.Fatalf("ReadDir() error = %v", readDirErr) + } + if len(entries) != 1 { + t.Fatalf("artifact count = %d", len(entries)) + } + data, readErr := os.ReadFile(filepath.Join(project, ".context", "proposals", "ai", entries[0].Name())) + if readErr != nil { + t.Fatalf("ReadFile() error = %v", readErr) + } + var artifact map[string]any + if err := json.Unmarshal(data, &artifact); err != nil { + t.Fatalf("artifact json invalid: %v", err) + } + if artifact["response"] == nil { + t.Fatalf("artifact missing response") + } +} + +func TestProposeRejectsEmptyEmit(t *testing.T) { + project := chdirProject(t) + server := completionServer(t) + t.Cleanup(server.Close) + writeCtxRC(t, project, singleBackendYAML(server.URL)) + input := filepath.Join(project, "input.txt") + if writeErr := os.WriteFile(input, []byte("source"), 0o644); writeErr != nil { + t.Fatalf("WriteFile() error = %v", writeErr) + } + _, runErr := executeAI(t, "propose", input, "--emit", "") + if runErr == nil { + t.Fatalf("empty emit should fail") + } +} + +func TestCommandRegistrationPathResolves(t *testing.T) { + cmd := Cmd() + cmd.SetArgs([]string{"ping", "--backend", "vllm"}) + leaf, _, findErr := cmd.Find([]string{"ping"}) + if findErr != nil { + t.Fatalf("Find() error = %v", findErr) + } + if leaf == nil { + t.Fatalf("ping command not registered") + } +} + +func executeAI(t *testing.T, args ...string) (string, error) { + t.Helper() + rc.Reset() + t.Cleanup(rc.Reset) + buf := new(bytes.Buffer) + cmd := Cmd() + cmd.SetOut(buf) + cmd.SetErr(buf) + cmd.SetArgs(args) + runErr := cmd.Execute() + return buf.String(), runErr +} + +func chdirProject(t *testing.T) string { + t.Helper() + project := t.TempDir() + contextDir := filepath.Join(project, ".context") + if mkdirErr := os.MkdirAll(contextDir, 0o755); mkdirErr != nil { + t.Fatalf("MkdirAll() error = %v", mkdirErr) + } + if writeErr := os.WriteFile( + filepath.Join(contextDir, "DECISIONS.md"), + []byte("decisions"), + 0o644, + ); writeErr != nil { + t.Fatalf("WriteFile() error = %v", writeErr) + } + origDir, wdErr := os.Getwd() + if wdErr != nil { + t.Fatalf("Getwd() error = %v", wdErr) + } + if chdirErr := os.Chdir(project); chdirErr != nil { + t.Fatalf("Chdir() error = %v", chdirErr) + } + t.Cleanup(func() { + if chdirErr := os.Chdir(origDir); chdirErr != nil { + t.Fatalf("Chdir() cleanup error = %v", chdirErr) + } + }) + return project +} + +func writeCtxRC(t *testing.T, project string, content string) { + t.Helper() + if writeErr := os.WriteFile( + filepath.Join(project, ".ctxrc"), + []byte(content), + 0o644, + ); writeErr != nil { + t.Fatalf("WriteFile() error = %v", writeErr) + } +} + +func modelsServer(t *testing.T) *httptest.Server { + t.Helper() + return httptest.NewServer(http.HandlerFunc(func( + w http.ResponseWriter, + r *http.Request, + ) { + _, writeErr := w.Write([]byte(`{"data":[{"id":"model-a"}]}`)) + if writeErr != nil { + t.Fatalf("Write() error = %v", writeErr) + } + })) +} + +func completionServer(t *testing.T) *httptest.Server { + t.Helper() + return httptest.NewServer(http.HandlerFunc(func( + w http.ResponseWriter, + r *http.Request, + ) { + _, writeErr := w.Write([]byte(completionResponseJSON())) + if writeErr != nil { + t.Fatalf("Write() error = %v", writeErr) + } + })) +} + +func singleBackendYAML(endpoint string) string { + return "backends:\n default: vllm\n vllm:\n endpoint: " + + endpoint + "\n" +} + +func multipleBackendsYAML() string { + return "backends:\n vllm:\n endpoint: http://127.0.0.1\n" + + " openai:\n endpoint: http://127.0.0.2\n" +} + +func completionResponseJSON() string { + return `{"model":"m","choices":[{"message":{"content":"{\"rows\":[{\"emit\":\"decisions\",\"text\":\"ok\"}],\"metadata\":{\"backend\":\"vllm\",\"model\":\"m\",\"input\":\"` + "input.txt" + `\",\"status\":\"proposed\"}}"}}]}` +} diff --git a/internal/cli/ai/cmd/root/run.go b/internal/cli/ai/cmd/root/run.go new file mode 100644 index 000000000..782bb9292 --- /dev/null +++ b/internal/cli/ai/cmd/root/run.go @@ -0,0 +1,55 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package root + +import ( + "github.com/spf13/cobra" + + aiRun "github.com/ActiveMemory/ctx/internal/cli/ai/core/run" + writeAI "github.com/ActiveMemory/ctx/internal/write/ai" +) + +// RunPing executes ctx ai ping. +// +// Parameters: +// - cmd: cobra command for output stream +// - backendName: optional backend selector +// +// Returns: +// - error: backend resolution or ping failure +func RunPing(cmd *cobra.Command, backendName string) error { + result, pingErr := aiRun.Ping(cmd.Context(), backendName) + if pingErr != nil { + return pingErr + } + return writeAI.Ping( + cmd.OutOrStdout(), + result.Backend, + result.Endpoint, + result.FirstModel, + ) +} + +// RunPropose executes ctx ai propose. +// +// Parameters: +// - cmd: cobra command for output stream +// - input: input file path +// - backendName: optional backend selector +// - emit: comma-separated emit kinds +// +// Returns: +// - error: backend, completion, validation, or artifact write failure +func RunPropose( + cmd *cobra.Command, + input string, + backendName string, + emit string, +) error { + _, proposeErr := aiRun.Propose(cmd.Context(), input, backendName, emit) + return proposeErr +} diff --git a/internal/cli/ai/cmd/root/testmain_test.go b/internal/cli/ai/cmd/root/testmain_test.go new file mode 100644 index 000000000..adc4e3eef --- /dev/null +++ b/internal/cli/ai/cmd/root/testmain_test.go @@ -0,0 +1,19 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package root + +import ( + "os" + "testing" + + "github.com/ActiveMemory/ctx/internal/assets/read/lookup" +) + +func TestMain(m *testing.M) { + lookup.Init() + os.Exit(m.Run()) +} diff --git a/internal/cli/ai/core/doc.go b/internal/cli/ai/core/doc.go new file mode 100644 index 000000000..a974b8296 --- /dev/null +++ b/internal/cli/ai/core/doc.go @@ -0,0 +1,12 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +// Package core groups ctx ai implementation subpackages. +// +// Direct logic lives below this directory to keep core from becoming a +// god package. The root package is documentation-only by convention. +// Command packages import the concrete subpackages directly. +package core diff --git a/internal/cli/ai/core/run/doc.go b/internal/cli/ai/core/run/doc.go new file mode 100644 index 000000000..724472d60 --- /dev/null +++ b/internal/cli/ai/core/run/doc.go @@ -0,0 +1,12 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +// Package run implements ctx ai backend resolution and actions. +// +// It builds backend registries from .ctxrc configuration, performs ping +// checks, and writes validation-only proposal artifacts. It does not own +// cobra command construction or terminal formatting. +package run diff --git a/internal/cli/ai/core/run/run.go b/internal/cli/ai/core/run/run.go new file mode 100644 index 000000000..15c5117c9 --- /dev/null +++ b/internal/cli/ai/core/run/run.go @@ -0,0 +1,117 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package run + +import ( + "context" + "encoding/json" + + backendPkg "github.com/ActiveMemory/ctx/internal/backend" + cfgAI "github.com/ActiveMemory/ctx/internal/config/ai" + "github.com/ActiveMemory/ctx/internal/config/token" + errAI "github.com/ActiveMemory/ctx/internal/err/ai" + errBackend "github.com/ActiveMemory/ctx/internal/err/backend" + ctxio "github.com/ActiveMemory/ctx/internal/io" +) + +// Ping resolves and pings a configured backend. +// +// Parameters: +// - ctx: request context +// - backendName: optional backend selector +// +// Returns: +// - PingResult: backend, endpoint, and first model +// - error: backend resolution or ping failure +func Ping(ctx context.Context, backendName string) (PingResult, error) { + resolved, resolveErr := resolve(backendName) + if resolveErr != nil { + return PingResult{}, resolveErr + } + info, pingErr := backendPkg.PingInfo(ctx, resolved.backend) + if pingErr != nil { + return PingResult{}, pingErr + } + return PingResult{ + Backend: resolved.name, + Endpoint: backendPkg.EndpointInfo(resolved.backend), + FirstModel: info.FirstModel, + }, nil +} + +// Propose generates and writes a validation-only proposal artifact. +// +// Parameters: +// - ctx: request context +// - input: input file path +// - backendName: optional backend selector +// - emit: comma-separated proposal kinds +// +// Returns: +// - string: artifact path +// - error: backend, completion, validation, or write failure +func Propose( + ctx context.Context, + input string, + backendName string, + emit string, +) (string, error) { + resolved, resolveErr := resolve(backendName) + if resolveErr != nil { + return "", resolveErr + } + data, readErr := ctxio.SafeReadUserFile(input) + if readErr != nil { + return "", readErr + } + kinds := splitEmit(emit) + if len(kinds) == 0 { + return "", errAI.EmitRequired() + } + response, completeErr := resolved.backend.Complete( + ctx, + backendPkg.Request{ + Prompt: cfgAI.PromptPrefix + emit + token.NewlineLF + string(data), + Schema: backendPkg.Schema{ + Name: cfgAI.SchemaProposalName, + Schema: json.RawMessage(cfgAI.ProposalSchema), + }, + }, + ) + if completeErr != nil { + return "", completeErr + } + decoded := ProposalResponse{} + decodeErr := json.Unmarshal([]byte(response.Text), &decoded) + if decodeErr != nil || len(decoded.Rows) == 0 { + return "", errBackend.BadRequest{ + Name: resolved.name, + Cause: errAI.InvalidArtifactResponse(), + } + } + artifact := ProposalArtifact{ + Kind: cfgAI.KindProposedPatch, + Backend: resolved.name, + Model: response.Model, + Input: input, + Emit: kinds, + Status: cfgAI.StatusProposed, + Response: ProposalResponse{ + Rows: decoded.Rows, + Metadata: ProposalMeta{ + Backend: resolved.name, + Model: response.Model, + Input: input, + Status: cfgAI.StatusProposed, + }, + }, + } + if validateErr := validateProposalArtifact(artifact); validateErr != nil { + return "", validateErr + } + return writeArtifact(artifact) +} diff --git a/internal/cli/ai/core/run/support_internal.go b/internal/cli/ai/core/run/support_internal.go new file mode 100644 index 000000000..309144d5a --- /dev/null +++ b/internal/cli/ai/core/run/support_internal.go @@ -0,0 +1,196 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package run + +import ( + "encoding/json" + "fmt" + "path/filepath" + "strings" + "sync/atomic" + "time" + + backendPkg "github.com/ActiveMemory/ctx/internal/backend" + cfgAI "github.com/ActiveMemory/ctx/internal/config/ai" + "github.com/ActiveMemory/ctx/internal/config/dir" + cfgFS "github.com/ActiveMemory/ctx/internal/config/fs" + "github.com/ActiveMemory/ctx/internal/config/token" + errAI "github.com/ActiveMemory/ctx/internal/err/ai" + errBackend "github.com/ActiveMemory/ctx/internal/err/backend" + ctxio "github.com/ActiveMemory/ctx/internal/io" + "github.com/ActiveMemory/ctx/internal/rc" +) + +// proposalNonce breaks same-timestamp artifact filename ties. +var proposalNonce uint64 + +// resolve returns the selected configured backend. +// +// Parameters: +// - backendName: optional backend selector +// +// Returns: +// - resolvedBackend: selected backend and metadata +// - error: rc or registry resolution error +func resolve(backendName string) (resolvedBackend, error) { + if validateErr := rc.ValidateCurrent(); validateErr != nil { + return resolvedBackend{}, validateErr + } + + registry := &backendPkg.Registry{} + configs := rc.RC().Backends.Configs + if len(configs) == 0 { + _, resolveErr := registry.Default() + return resolvedBackend{}, resolveErr + } + for name, config := range configs { + backendConfig := backendPkg.Config{ + Name: name, + Type: config.Type, + Endpoint: config.Endpoint, + APIKeyEnv: config.APIKeyEnv, + Timeout: config.Timeout, + DefaultModel: config.DefaultModel, + } + registerErr := registry.RegisterBuiltin(name, backendConfig) + if registerErr != nil { + return resolvedBackend{}, registerErr + } + } + registry.SetDefault(rc.RC().Backends.Default) + selectedName := selectedBackendName(backendName, configs) + selected, resolveErr := resolveSelected(registry, selectedName) + if resolveErr != nil { + return resolvedBackend{}, resolveErr + } + return resolvedBackend{ + name: selectedName, + backend: selected, + }, nil +} + +// resolveSelected resolves either an explicit or registry default backend. +// +// Parameters: +// - registry: backend registry +// - selectedName: explicit selected backend name +// +// Returns: +// - backend.Backend: resolved backend +// - error: registry resolution failure +func resolveSelected( + registry *backendPkg.Registry, + selectedName string, +) (backendPkg.Backend, error) { + if selectedName != "" { + return registry.Resolve(selectedName) + } + return registry.Default() +} + +// selectedBackendName returns the configured backend key to resolve. +// +// Parameters: +// - backendName: explicit backend selector +// - configs: configured backend map +// +// Returns: +// - string: backend key, or empty when registry default should decide +func selectedBackendName( + backendName string, + configs map[string]rc.BackendRC, +) string { + if backendName != "" { + return backendName + } + defaultName := rc.RC().Backends.Default + if defaultName != "" { + return defaultName + } + if len(configs) != 1 { + return "" + } + for name := range configs { + return name + } + return "" +} + +// writeArtifact writes a proposed-patch artifact under .context. +// +// Parameters: +// - artifact: proposal artifact to persist +// +// Returns: +// - string: artifact path +// - error: marshal, mkdir, or write failure +func writeArtifact(artifact ProposalArtifact) (string, error) { + indent := token.Space + token.Space + data, marshalErr := json.MarshalIndent(artifact, "", indent) + if marshalErr != nil { + return "", errBackend.BadRequest{ + Name: artifact.Backend, + Cause: marshalErr, + } + } + proposalDir := filepath.Join(dir.Context, cfgAI.DirProposals, cfgAI.DirAI) + mkdirErr := ctxio.SafeMkdirAll(proposalDir, cfgFS.PermExec) + if mkdirErr != nil { + return "", mkdirErr + } + name := cfgAI.ArtifactPrefix + + time.Now().UTC().Format(cfgAI.TimestampLayout) + + fmt.Sprintf( + cfgAI.ArtifactNonceFormat, + atomic.AddUint64(&proposalNonce, 1), + ) + + cfgAI.ArtifactExtJSON + path := filepath.Join(proposalDir, name) + writeErr := ctxio.SafeWriteFile(path, data, cfgFS.PermFile) + if writeErr != nil { + return "", writeErr + } + return path, nil +} + +// validateProposalArtifact checks required proposal artifact fields. +// +// Parameters: +// - artifact: proposal artifact to validate before persisting +// +// Returns: +// - error: invalid artifact error, invalid response error, or nil when valid +func validateProposalArtifact(artifact ProposalArtifact) error { + if artifact.Kind != cfgAI.KindProposedPatch || artifact.Backend == "" || + artifact.Model == "" || artifact.Input == "" || len(artifact.Emit) == 0 { + return errAI.InvalidArtifact() + } + if artifact.Status != cfgAI.StatusProposed || + len(artifact.Response.Rows) == 0 { + return errAI.InvalidArtifactResponse() + } + return nil +} + +// splitEmit splits comma-separated emit kinds. +// +// Parameters: +// - emit: comma-separated emit kinds +// +// Returns: +// - []string: trimmed emit kinds +func splitEmit(emit string) []string { + parts := strings.Split(emit, cfgAI.EmitSeparator) + out := make([]string, 0, len(parts)) + for _, part := range parts { + trimmed := strings.TrimSpace(part) + if trimmed != "" { + out = append(out, trimmed) + } + } + return out +} diff --git a/internal/cli/ai/core/run/support_internal_test.go b/internal/cli/ai/core/run/support_internal_test.go new file mode 100644 index 000000000..db0cb5a15 --- /dev/null +++ b/internal/cli/ai/core/run/support_internal_test.go @@ -0,0 +1,51 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package run + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "github.com/ActiveMemory/ctx/internal/config/dir" + "github.com/ActiveMemory/ctx/internal/rc" +) + +func declareContext(t *testing.T, content string) { + t.Helper() + tempDir := t.TempDir() + ctxDir := filepath.Join(tempDir, dir.Context) + if mkErr := os.MkdirAll(ctxDir, 0700); mkErr != nil { + t.Fatalf("mkdir .context: %v", mkErr) + } + if content != "" { + rcPath := filepath.Join(tempDir, ".ctxrc") + if wrErr := os.WriteFile(rcPath, []byte(content), 0600); wrErr != nil { + t.Fatalf("write .ctxrc: %v", wrErr) + } + } + t.Chdir(tempDir) + rc.Reset() + t.Cleanup(rc.Reset) +} + +func TestResolveRejectsInvalidBackendConfig(t *testing.T) { + declareContext(t, `backends: + vllm: + endpoint: http://localhost:8000 + api_token: nope +`) + + _, err := resolve("") + if err == nil { + t.Fatal("expected validation error") + } + if !strings.Contains(err.Error(), "backends.vllm.api_token") { + t.Fatalf("error = %v, want full backend field path", err) + } +} diff --git a/internal/cli/ai/core/run/types.go b/internal/cli/ai/core/run/types.go new file mode 100644 index 000000000..14d350ddb --- /dev/null +++ b/internal/cli/ai/core/run/types.go @@ -0,0 +1,69 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package run + +import backendPkg "github.com/ActiveMemory/ctx/internal/backend" + +// PingResult is printable backend reachability information. +// +// Fields: +// - Backend: resolved backend name +// - Endpoint: configured backend endpoint +// - FirstModel: first model returned by backend model listing +type PingResult struct { + Backend string + Endpoint string + FirstModel string +} + +// ProposalArtifact is the validation-only proposed-patch artifact. +// +// Fields: +// - Kind: artifact kind +// - Backend: backend that generated the response +// - Model: model reported by the backend +// - Input: input file path +// - Emit: requested proposal kinds +// - Status: artifact status +// - Response: decoded backend JSON response +type ProposalArtifact struct { + Kind string `json:"kind"` + Backend string `json:"backend"` + Model string `json:"model"` + Input string `json:"input"` + Emit []string `json:"emit"` + Status string `json:"status"` + Response ProposalResponse `json:"response"` +} + +// ProposalResponse is the structured proposal payload. +type ProposalResponse struct { + Rows []ProposalRow `json:"rows"` + Metadata ProposalMeta `json:"metadata"` +} + +// ProposalRow is one proposed artifact row. +type ProposalRow struct { + Emit string `json:"emit"` + Text string `json:"text"` + Start int `json:"start,omitempty"` + End int `json:"end,omitempty"` +} + +// ProposalMeta contains reviewable response metadata. +type ProposalMeta struct { + Backend string `json:"backend"` + Model string `json:"model"` + Input string `json:"input"` + Status string `json:"status"` +} + +// resolvedBackend carries the selected backend and metadata. +type resolvedBackend struct { + name string + backend backendPkg.Backend +} diff --git a/internal/cli/ai/doc.go b/internal/cli/ai/doc.go new file mode 100644 index 000000000..f6867d5e2 --- /dev/null +++ b/internal/cli/ai/doc.go @@ -0,0 +1,12 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +// Package ai exposes optional AI backend commands. +// +// The command surface is additive and fail-closed: it only runs when a +// backend is explicitly configured in .ctxrc. Deterministic context +// assembly commands do not depend on this package. +package ai diff --git a/internal/cli/initialize/cmd/root/run.go b/internal/cli/initialize/cmd/root/run.go index 72e1da70b..5fe3c8453 100644 --- a/internal/cli/initialize/cmd/root/run.go +++ b/internal/cli/initialize/cmd/root/run.go @@ -259,14 +259,6 @@ func Run( initialize.InfoWarnNonFatal(cmd, label, permsErr) } - // Merge the ctx status line into settings.local.json, backing up - // any pre-existing statusLine entry (specs/statusline.md). - if statuslineErr := coreMerge.SettingsStatusLine(cmd); statuslineErr != nil { - // Non-fatal: warn but continue - label := desc.Text(text.DescKeyInitLabelStatusline) - initialize.InfoWarnNonFatal(cmd, label, statuslineErr) - } - // Auto-enable plugin globally and locally unless suppressed. if !noPluginEnable { if pluginErr := plugin.EnableGlobally(cmd); pluginErr != nil { diff --git a/internal/cli/initialize/core/merge/perm.go b/internal/cli/initialize/core/merge/perm.go index bf0c75c4d..3d3ef0a85 100644 --- a/internal/cli/initialize/core/merge/perm.go +++ b/internal/cli/initialize/core/merge/perm.go @@ -7,6 +7,7 @@ package merge import ( + "bytes" "encoding/json" "strings" @@ -15,54 +16,59 @@ import ( "github.com/ActiveMemory/ctx/internal/assets/read/lookup" "github.com/ActiveMemory/ctx/internal/claude" cfgClaude "github.com/ActiveMemory/ctx/internal/config/claude" + "github.com/ActiveMemory/ctx/internal/config/dir" + "github.com/ActiveMemory/ctx/internal/config/fs" "github.com/ActiveMemory/ctx/internal/config/token" "github.com/ActiveMemory/ctx/internal/err/config" + errFs "github.com/ActiveMemory/ctx/internal/err/fs" errParser "github.com/ActiveMemory/ctx/internal/err/parser" + ctxIo "github.com/ActiveMemory/ctx/internal/io" "github.com/ActiveMemory/ctx/internal/write/initialize" ) // SettingsPermissions merges ctx permissions into settings.local.json. // -// Only the permissions section is rewritten: all other top-level keys -// in the settings file (hooks, statusLine, env, anything ctx does not -// model) survive byte-for-byte via the raw-map read-modify-write in -// settings.go. -// // Parameters: // - cmd: Cobra command for output // // Returns: // - error: Non-nil if file operations fail func SettingsPermissions(cmd *cobra.Command) error { - raw, fileExists, readErr := readSettingsRaw() - if readErr != nil { - return readErr - } - var perms claude.PermissionsConfig - if rawPerms, exists := raw[cfgClaude.FieldPermissions]; exists { - if unmarshalErr := json.Unmarshal(rawPerms, &perms); unmarshalErr != nil { + var settings claude.Settings + existingContent, readErr := ctxIo.SafeReadUserFile(cfgClaude.Settings) + fileExists := readErr == nil + if fileExists { + unmarshalErr := json.Unmarshal(existingContent, &settings) + if unmarshalErr != nil { return errParser.ParseFile(cfgClaude.Settings, unmarshalErr) } } allowModified := Permissions( - &perms.Allow, lookup.PermAllowListDefault(), + &settings.Permissions.Allow, lookup.PermAllowListDefault(), ) denyModified := Permissions( - &perms.Deny, lookup.PermDenyListDefault(), + &settings.Permissions.Deny, lookup.PermDenyListDefault(), ) - allowDeduped := DeduplicatePermissions(&perms.Allow) - denyDeduped := DeduplicatePermissions(&perms.Deny) + allowDeduped := DeduplicatePermissions(&settings.Permissions.Allow) + denyDeduped := DeduplicatePermissions(&settings.Permissions.Deny) if !allowModified && !denyModified && !allowDeduped && !denyDeduped { initialize.NoChanges(cmd, cfgClaude.Settings) return nil } - section, marshalErr := marshalSettingsSection(perms) - if marshalErr != nil { - return config.MarshalSettings(marshalErr) + if mkdirErr := ctxIo.SafeMkdirAll(dir.Claude, fs.PermExec); mkdirErr != nil { + return errFs.Mkdir(dir.Claude, mkdirErr) + } + var buf bytes.Buffer + encoder := json.NewEncoder(&buf) + encoder.SetEscapeHTML(false) + encoder.SetIndent("", token.Indent2) + if encodeErr := encoder.Encode(settings); encodeErr != nil { + return config.MarshalSettings(encodeErr) } - raw[cfgClaude.FieldPermissions] = section - if writeErr := writeSettingsRaw(raw); writeErr != nil { - return writeErr + if writeErr := ctxIo.SafeWriteFile( + cfgClaude.Settings, buf.Bytes(), fs.PermFile, + ); writeErr != nil { + return errFs.FileWrite(cfgClaude.Settings, writeErr) } if fileExists { deduped := allowDeduped || denyDeduped diff --git a/internal/cli/initialize/core/merge/settings.go b/internal/cli/initialize/core/merge/settings.go deleted file mode 100644 index ac0224085..000000000 --- a/internal/cli/initialize/core/merge/settings.go +++ /dev/null @@ -1,93 +0,0 @@ -// / ctx: https://ctx.ist -// ,'`./ do you remember? -// `.,'\ -// \ Copyright 2026-present Context contributors. -// SPDX-License-Identifier: Apache-2.0 - -package merge - -import ( - "bytes" - "encoding/json" - - cfgClaude "github.com/ActiveMemory/ctx/internal/config/claude" - "github.com/ActiveMemory/ctx/internal/config/dir" - "github.com/ActiveMemory/ctx/internal/config/fs" - "github.com/ActiveMemory/ctx/internal/config/token" - "github.com/ActiveMemory/ctx/internal/err/config" - errFs "github.com/ActiveMemory/ctx/internal/err/fs" - errParser "github.com/ActiveMemory/ctx/internal/err/parser" - ctxIo "github.com/ActiveMemory/ctx/internal/io" -) - -// readSettingsRaw reads settings.local.json into a key-level raw map. -// -// The raw-map representation exists so read-modify-write cycles only -// touch the sections they own: keys ctx does not model (a user's env, -// model, or other settings) survive the rewrite byte-for-byte instead -// of being silently dropped by a typed round-trip. -// -// A missing or unreadable file is reported as non-existent with an -// empty map, matching the merge semantics of a fresh project. -// -// Returns: -// - map[string]json.RawMessage: top-level settings keys -// - bool: true when the settings file exists and was read -// - error: non-nil when the file exists but does not parse -func readSettingsRaw() (map[string]json.RawMessage, bool, error) { - raw := map[string]json.RawMessage{} - content, readErr := ctxIo.SafeReadUserFile(cfgClaude.Settings) - if readErr != nil { - return raw, false, nil - } - if unmarshalErr := json.Unmarshal(content, &raw); unmarshalErr != nil { - return nil, true, errParser.ParseFile(cfgClaude.Settings, unmarshalErr) - } - return raw, true, nil -} - -// writeSettingsRaw writes the raw settings map back to -// settings.local.json, creating .claude/ when needed. -// -// Parameters: -// - raw: top-level settings keys to persist -// -// Returns: -// - error: non-nil if encoding or file operations fail -func writeSettingsRaw(raw map[string]json.RawMessage) error { - if mkdirErr := ctxIo.SafeMkdirAll(dir.Claude, fs.PermExec); mkdirErr != nil { - return errFs.Mkdir(dir.Claude, mkdirErr) - } - var buf bytes.Buffer - encoder := json.NewEncoder(&buf) - encoder.SetEscapeHTML(false) - encoder.SetIndent("", token.Indent2) - if encodeErr := encoder.Encode(raw); encodeErr != nil { - return config.MarshalSettings(encodeErr) - } - if writeErr := ctxIo.SafeWriteFile( - cfgClaude.Settings, buf.Bytes(), fs.PermFile, - ); writeErr != nil { - return errFs.FileWrite(cfgClaude.Settings, writeErr) - } - return nil -} - -// marshalSettingsSection marshals one settings section without HTML -// escaping, for insertion into the raw settings map. -// -// Parameters: -// - v: section value to marshal -// -// Returns: -// - json.RawMessage: marshaled section -// - error: non-nil on marshal failure -func marshalSettingsSection(v any) (json.RawMessage, error) { - var buf bytes.Buffer - encoder := json.NewEncoder(&buf) - encoder.SetEscapeHTML(false) - if encodeErr := encoder.Encode(v); encodeErr != nil { - return nil, encodeErr - } - return json.RawMessage(bytes.TrimSpace(buf.Bytes())), nil -} diff --git a/internal/cli/initialize/core/merge/statusline.go b/internal/cli/initialize/core/merge/statusline.go deleted file mode 100644 index 4b8b2769a..000000000 --- a/internal/cli/initialize/core/merge/statusline.go +++ /dev/null @@ -1,71 +0,0 @@ -// / ctx: https://ctx.ist -// ,'`./ do you remember? -// `.,'\ -// \ Copyright 2026-present Context contributors. -// SPDX-License-Identifier: Apache-2.0 - -package merge - -import ( - "encoding/json" - - "github.com/spf13/cobra" - - "github.com/ActiveMemory/ctx/internal/claude" - cfgClaude "github.com/ActiveMemory/ctx/internal/config/claude" - "github.com/ActiveMemory/ctx/internal/err/config" - "github.com/ActiveMemory/ctx/internal/rc" - "github.com/ActiveMemory/ctx/internal/write/initialize" -) - -// SettingsStatusLine merges the ctx status line into -// settings.local.json. -// -// Deploys a statusLine entry running "ctx system statusline" -// (spec: specs/statusline.md). A pre-existing statusLine that is not -// ours is backed up to .context/state/ before being replaced, and is -// restored from that backup when statusline.enabled is set to false -// in .ctxrc. A foreign statusLine is never removed on disable: it is -// not ours to delete. -// -// Parameters: -// - cmd: Cobra command for output -// -// Returns: -// - error: Non-nil if file operations fail -func SettingsStatusLine(cmd *cobra.Command) error { - if !rc.StatuslineEnabled() { - return removeStatusLine(cmd) - } - raw, _, readErr := readSettingsRaw() - if readErr != nil { - return readErr - } - desired := claude.StatusLineConfig{ - Type: cfgClaude.StatusLineType, - Command: cfgClaude.StatusLineCommand, - } - if rawEntry, exists := raw[cfgClaude.FieldStatusLine]; exists { - var existing claude.StatusLineConfig - unmarshalErr := json.Unmarshal(rawEntry, &existing) - if unmarshalErr == nil && existing.Command == desired.Command { - initialize.NoChanges(cmd, cfgClaude.Settings) - return nil - } - backupPath, backupErr := backupStatusLine(rawEntry) - if backupErr != nil { - return backupErr - } - initialize.StatuslineBackedUp(cmd, backupPath) - } - section, marshalErr := marshalSettingsSection(desired) - if marshalErr != nil { - return config.MarshalSettings(marshalErr) - } - raw[cfgClaude.FieldStatusLine] = section - if writeErr := writeSettingsRaw(raw); writeErr != nil { - return writeErr - } - initialize.StatuslineDeployed(cmd, cfgClaude.Settings) - return nil -} diff --git a/internal/cli/initialize/core/merge/statusline_test.go b/internal/cli/initialize/core/merge/statusline_test.go deleted file mode 100644 index ac9139f87..000000000 --- a/internal/cli/initialize/core/merge/statusline_test.go +++ /dev/null @@ -1,241 +0,0 @@ -// / ctx: https://ctx.ist -// ,'`./ do you remember? -// `.,'\ -// \ Copyright 2026-present Context contributors. -// SPDX-License-Identifier: Apache-2.0 - -package merge - -import ( - "encoding/json" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/spf13/cobra" - - cfgClaude "github.com/ActiveMemory/ctx/internal/config/claude" - "github.com/ActiveMemory/ctx/internal/config/dir" - "github.com/ActiveMemory/ctx/internal/rc" -) - -// setupProject creates a temp project root with .context/, chdirs -// into it, and resets the rc cache. Cleanup restores everything. -func setupProject(t *testing.T) string { - t.Helper() - tmpDir, mkErr := os.MkdirTemp("", "ctx-merge-statusline-*") - if mkErr != nil { - t.Fatalf("failed to create temp dir: %v", mkErr) - } - // Resolve symlinks (macOS /var vs /private/var) so path - // comparisons hold. - resolved, resolveErr := filepath.EvalSymlinks(tmpDir) - if resolveErr == nil { - tmpDir = resolved - } - if mkdirErr := os.Mkdir(filepath.Join(tmpDir, ".context"), 0o750); mkdirErr != nil { - t.Fatalf("failed to create .context: %v", mkdirErr) - } - origDir, _ := os.Getwd() - if chdirErr := os.Chdir(tmpDir); chdirErr != nil { - t.Fatalf("failed to chdir: %v", chdirErr) - } - rc.Reset() - t.Cleanup(func() { - _ = os.Chdir(origDir) - rc.Reset() - _ = os.RemoveAll(tmpDir) - }) - return tmpDir -} - -// runStatusLine invokes SettingsStatusLine with a throwaway command. -func runStatusLine(t *testing.T) { - t.Helper() - cmd := &cobra.Command{} - cmd.SetOut(os.NewFile(0, os.DevNull)) - if mergeErr := SettingsStatusLine(cmd); mergeErr != nil { - t.Fatalf("SettingsStatusLine failed: %v", mergeErr) - } -} - -// readSettings parses settings.local.json into a raw key map. -func readSettings(t *testing.T) map[string]json.RawMessage { - t.Helper() - content, readErr := os.ReadFile(cfgClaude.Settings) - if readErr != nil { - t.Fatalf("failed to read settings: %v", readErr) - } - raw := map[string]json.RawMessage{} - if unmarshalErr := json.Unmarshal(content, &raw); unmarshalErr != nil { - t.Fatalf("settings not valid JSON: %v", unmarshalErr) - } - return raw -} - -func TestStatusLineDeployedIntoFreshProject(t *testing.T) { - setupProject(t) - runStatusLine(t) - - raw := readSettings(t) - entry, exists := raw[cfgClaude.FieldStatusLine] - if !exists { - t.Fatal("statusLine key missing after deploy") - } - if !strings.Contains(string(entry), cfgClaude.StatusLineCommand) { - t.Errorf("statusLine %s does not run %q", - entry, cfgClaude.StatusLineCommand) - } -} - -func TestStatusLineBacksUpForeignEntry(t *testing.T) { - tmpDir := setupProject(t) - foreign := `{"type":"command","command":"my-custom-line.sh"}` - if mkdirErr := os.MkdirAll(".claude", 0o750); mkdirErr != nil { - t.Fatalf("failed to create .claude: %v", mkdirErr) - } - settings := `{"statusLine": ` + foreign + `, "env": {"FOO": "bar"}}` - if writeErr := os.WriteFile(cfgClaude.Settings, []byte(settings), 0o600); writeErr != nil { - t.Fatalf("failed to seed settings: %v", writeErr) - } - - runStatusLine(t) - - raw := readSettings(t) - if !strings.Contains(string(raw[cfgClaude.FieldStatusLine]), - cfgClaude.StatusLineCommand) { - t.Errorf("statusLine not replaced: %s", raw[cfgClaude.FieldStatusLine]) - } - if _, exists := raw["env"]; !exists { - t.Error("unmodeled env key dropped by statusline merge") - } - - backupPath := filepath.Join( - tmpDir, ".context", dir.State, cfgClaude.PreviousStatusLine, - ) - backup, readErr := os.ReadFile(filepath.Clean(backupPath)) - if readErr != nil { - t.Fatalf("backup not written: %v", readErr) - } - if !strings.Contains(string(backup), "my-custom-line.sh") { - t.Errorf("backup %s lost the foreign command", backup) - } -} - -func TestStatusLineIdempotent(t *testing.T) { - setupProject(t) - runStatusLine(t) - before := readSettings(t) - runStatusLine(t) - after := readSettings(t) - if string(before[cfgClaude.FieldStatusLine]) != - string(after[cfgClaude.FieldStatusLine]) { - t.Error("second deploy changed the statusLine entry") - } -} - -func TestStatusLineDisableRestoresBackup(t *testing.T) { - setupProject(t) - foreign := `{"type":"command","command":"my-custom-line.sh"}` - if mkdirErr := os.MkdirAll(".claude", 0o750); mkdirErr != nil { - t.Fatalf("failed to create .claude: %v", mkdirErr) - } - settings := `{"statusLine": ` + foreign + `}` - if writeErr := os.WriteFile(cfgClaude.Settings, []byte(settings), 0o600); writeErr != nil { - t.Fatalf("failed to seed settings: %v", writeErr) - } - runStatusLine(t) // deploys ours, backs up foreign - - rcBody := "statusline:\n enabled: false\n" - if writeErr := os.WriteFile(".ctxrc", []byte(rcBody), 0o600); writeErr != nil { - t.Fatalf("failed to write .ctxrc: %v", writeErr) - } - rc.Reset() - runStatusLine(t) // disable path - - raw := readSettings(t) - if !strings.Contains(string(raw[cfgClaude.FieldStatusLine]), - "my-custom-line.sh") { - t.Errorf("foreign statusLine not restored: %s", - raw[cfgClaude.FieldStatusLine]) - } -} - -func TestStatusLineDisableRemovesWithoutBackup(t *testing.T) { - setupProject(t) - runStatusLine(t) // deploys ours; nothing to back up - - rcBody := "statusline:\n enabled: false\n" - if writeErr := os.WriteFile(".ctxrc", []byte(rcBody), 0o600); writeErr != nil { - t.Fatalf("failed to write .ctxrc: %v", writeErr) - } - rc.Reset() - runStatusLine(t) - - raw := readSettings(t) - if _, exists := raw[cfgClaude.FieldStatusLine]; exists { - t.Errorf("statusLine survived disable with no backup: %s", - raw[cfgClaude.FieldStatusLine]) - } -} - -func TestStatusLineDisableLeavesForeignAlone(t *testing.T) { - setupProject(t) - foreign := `{"type":"command","command":"my-custom-line.sh"}` - if mkdirErr := os.MkdirAll(".claude", 0o750); mkdirErr != nil { - t.Fatalf("failed to create .claude: %v", mkdirErr) - } - settings := `{"statusLine": ` + foreign + `}` - if writeErr := os.WriteFile(cfgClaude.Settings, []byte(settings), 0o600); writeErr != nil { - t.Fatalf("failed to seed settings: %v", writeErr) - } - - rcBody := "statusline:\n enabled: false\n" - if writeErr := os.WriteFile(".ctxrc", []byte(rcBody), 0o600); writeErr != nil { - t.Fatalf("failed to write .ctxrc: %v", writeErr) - } - rc.Reset() - runStatusLine(t) - - raw := readSettings(t) - if !strings.Contains(string(raw[cfgClaude.FieldStatusLine]), - "my-custom-line.sh") { - t.Errorf("foreign statusLine modified on disable: %s", - raw[cfgClaude.FieldStatusLine]) - } -} - -func TestPermissionsMergePreservesUnknownKeys(t *testing.T) { - setupProject(t) - if mkdirErr := os.MkdirAll(".claude", 0o750); mkdirErr != nil { - t.Fatalf("failed to create .claude: %v", mkdirErr) - } - settings := `{ - "env": {"FOO": "bar"}, - "statusLine": {"type": "command", "command": "my-custom-line.sh"}, - "permissions": {"allow": ["Bash(ls:*)"]} - }` - if writeErr := os.WriteFile(cfgClaude.Settings, []byte(settings), 0o600); writeErr != nil { - t.Fatalf("failed to seed settings: %v", writeErr) - } - - cmd := &cobra.Command{} - cmd.SetOut(os.NewFile(0, os.DevNull)) - if mergeErr := SettingsPermissions(cmd); mergeErr != nil { - t.Fatalf("SettingsPermissions failed: %v", mergeErr) - } - - raw := readSettings(t) - if _, exists := raw["env"]; !exists { - t.Error("permissions merge dropped the env key") - } - if !strings.Contains(string(raw[cfgClaude.FieldStatusLine]), - "my-custom-line.sh") { - t.Error("permissions merge dropped or rewrote statusLine") - } - if !strings.Contains(string(raw[cfgClaude.FieldPermissions]), - "Bash(ls:*)") { - t.Error("permissions merge lost the user's existing allow entry") - } -} diff --git a/internal/cli/initialize/core/merge/statuslinebackup.go b/internal/cli/initialize/core/merge/statuslinebackup.go deleted file mode 100644 index 3c0a0b35c..000000000 --- a/internal/cli/initialize/core/merge/statuslinebackup.go +++ /dev/null @@ -1,133 +0,0 @@ -// / ctx: https://ctx.ist -// ,'`./ do you remember? -// `.,'\ -// \ Copyright 2026-present Context contributors. -// SPDX-License-Identifier: Apache-2.0 - -package merge - -import ( - "bytes" - "encoding/json" - "path/filepath" - - "github.com/spf13/cobra" - - "github.com/ActiveMemory/ctx/internal/claude" - cfgClaude "github.com/ActiveMemory/ctx/internal/config/claude" - "github.com/ActiveMemory/ctx/internal/config/dir" - "github.com/ActiveMemory/ctx/internal/config/fs" - "github.com/ActiveMemory/ctx/internal/config/token" - errFs "github.com/ActiveMemory/ctx/internal/err/fs" - ctxIo "github.com/ActiveMemory/ctx/internal/io" - "github.com/ActiveMemory/ctx/internal/rc" - "github.com/ActiveMemory/ctx/internal/write/initialize" -) - -// removeStatusLine handles statusline.enabled: false. When the -// deployed statusLine is ours, it is replaced by the backed-up -// previous entry when one exists, or dropped. Foreign entries are -// left untouched. -// -// Parameters: -// - cmd: Cobra command for output -// -// Returns: -// - error: Non-nil if file operations fail -func removeStatusLine(cmd *cobra.Command) error { - raw, fileExists, readErr := readSettingsRaw() - if readErr != nil { - return readErr - } - rawEntry, exists := raw[cfgClaude.FieldStatusLine] - if !fileExists || !exists { - initialize.NoChanges(cmd, cfgClaude.Settings) - return nil - } - var existing claude.StatusLineConfig - unmarshalErr := json.Unmarshal(rawEntry, &existing) - if unmarshalErr != nil || - existing.Command != cfgClaude.StatusLineCommand { - initialize.NoChanges(cmd, cfgClaude.Settings) - return nil - } - backupPath, previous := readStatusLineBackup() - if len(previous) > 0 { - raw[cfgClaude.FieldStatusLine] = previous - if writeErr := writeSettingsRaw(raw); writeErr != nil { - return writeErr - } - initialize.StatuslineRestored(cmd, backupPath) - return nil - } - delete(raw, cfgClaude.FieldStatusLine) - if writeErr := writeSettingsRaw(raw); writeErr != nil { - return writeErr - } - initialize.StatuslineRemoved(cmd, cfgClaude.Settings) - return nil -} - -// statusLineBackupPath resolves the backup file location under the -// project's .context/state/ directory. -// -// Returns: -// - string: absolute backup file path -// - error: Non-nil when the context directory cannot be resolved -func statusLineBackupPath() (string, error) { - ctxDir, dirErr := rc.ContextDir() - if dirErr != nil { - return "", dirErr - } - return filepath.Join(ctxDir, dir.State, cfgClaude.PreviousStatusLine), nil -} - -// backupStatusLine persists a displaced statusLine entry so a later -// statusline.enabled: false can restore it. -// -// Parameters: -// - rawEntry: statusLine entry being displaced, verbatim -// -// Returns: -// - string: backup file path the entry was written to -// - error: Non-nil if path resolution or file operations fail -func backupStatusLine(rawEntry json.RawMessage) (string, error) { - path, pathErr := statusLineBackupPath() - if pathErr != nil { - return "", pathErr - } - stateDir := filepath.Dir(path) - if mkdirErr := ctxIo.SafeMkdirAll(stateDir, fs.PermExec); mkdirErr != nil { - return "", errFs.Mkdir(stateDir, mkdirErr) - } - content := append(bytes.TrimSpace(rawEntry), token.NewlineLF...) - if writeErr := ctxIo.SafeWriteFile( - path, content, fs.PermFile, - ); writeErr != nil { - return "", errFs.FileWrite(path, writeErr) - } - return path, nil -} - -// readStatusLineBackup loads a previously backed-up statusLine entry. -// Restore is best-effort, never fatal. -// -// Returns: -// - string: backup file path (may be "" when unresolvable) -// - json.RawMessage: backed-up entry, or nil when no valid backup -// exists -func readStatusLineBackup() (string, json.RawMessage) { - path, pathErr := statusLineBackupPath() - if pathErr != nil { - return "", nil - } - content, readErr := ctxIo.SafeReadUserFile(path) - if readErr != nil { - return path, nil - } - trimmed := bytes.TrimSpace(content) - if !json.Valid(trimmed) { - return path, nil - } - return path, json.RawMessage(trimmed) -} diff --git a/internal/cli/setup/cmd/root/backend_test.go b/internal/cli/setup/cmd/root/backend_test.go new file mode 100644 index 000000000..c6b2536ca --- /dev/null +++ b/internal/cli/setup/cmd/root/backend_test.go @@ -0,0 +1,258 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package root + +import ( + "bytes" + "os" + "path/filepath" + "strings" + "testing" +) + +func TestSetupBackendNoArgsAccepted(t *testing.T) { + out, runErr := executeSetup(t, + "--backend", "vllm", + "--endpoint", "http://localhost:8000", + ) + if runErr != nil { + t.Fatalf("setup --backend failed: %v", runErr) + } + if !strings.Contains(out, "backends:") { + t.Fatalf("output = %q", out) + } +} + +func TestSetupBackendOnlyDoesNotWriteOpenCodeConfig(t *testing.T) { + home := t.TempDir() + t.Setenv("OPENCODE_HOME", home) + _, runErr := executeSetup(t, + "--backend", "openai", + "--endpoint", "https://example.com/v1", + "--write", + ) + if runErr != nil { + t.Fatalf("setup --backend failed: %v", runErr) + } + if _, err := os.Stat(filepath.Join(home, "opencode.json")); !os.IsNotExist(err) { + t.Fatalf("unexpected opencode.json write") + } +} + +func TestSetupNoArgsNoBackendRejected(t *testing.T) { + _, runErr := executeSetup(t) + if runErr == nil { + t.Fatalf("setup without args should fail") + } +} + +func TestSetupExistingToolStillWorks(t *testing.T) { + _, runErr := executeSetup(t, "aider") + if runErr != nil { + t.Fatalf("setup aider failed: %v", runErr) + } +} + +func TestSetupBackendModeWinsOverToolArg(t *testing.T) { + _, runErr := executeSetup(t, + "aider", + "--backend", "vllm", + "--endpoint", "http://localhost:8000", + ) + if runErr != nil { + t.Fatalf("setup --backend with tool arg failed: %v", runErr) + } +} + +func TestSetupBackendUnsupportedRejected(t *testing.T) { + _, runErr := executeSetup(t, "--backend", "unknown") + if runErr == nil { + t.Fatalf("unsupported backend should fail") + } +} + +func TestSetupBackendMissingEndpointRejected(t *testing.T) { + _, runErr := executeSetup(t, "--backend", "openai-compatible") + if runErr == nil { + t.Fatalf("missing endpoint should fail") + } +} + +func TestSetupBackendDryRunPrintsYaml(t *testing.T) { + out, runErr := executeSetup(t, + "--backend", "vllm", + "--endpoint", "http://localhost:8000", + ) + if runErr != nil { + t.Fatalf("setup --backend failed: %v", runErr) + } + for _, want := range []string{"backends:", "vllm:", "endpoint:"} { + if !strings.Contains(out, want) { + t.Fatalf("output missing %q: %q", want, out) + } + } +} + +func TestSetupBackendWriteCreatesCtxRC(t *testing.T) { + tmpDir := chdirTemp(t) + _, runErr := executeSetup(t, + "--backend", "vllm", + "--endpoint", "http://localhost:8000", + "--write", + ) + if runErr != nil { + t.Fatalf("setup --backend --write failed: %v", runErr) + } + data, readErr := os.ReadFile(filepath.Join(tmpDir, ".ctxrc")) + if readErr != nil { + t.Fatalf("ReadFile() error = %v", readErr) + } + if !strings.Contains(string(data), "vllm:") { + t.Fatalf(".ctxrc = %q", string(data)) + } +} + +func TestSetupBackendWritePreservesUnrelatedFields(t *testing.T) { + tmpDir := chdirTemp(t) + writeErr := os.WriteFile( + filepath.Join(tmpDir, ".ctxrc"), + []byte("token_budget: 123\n"), + 0o644, + ) + if writeErr != nil { + t.Fatalf("WriteFile() error = %v", writeErr) + } + _, runErr := executeSetup(t, + "--backend", "vllm", + "--endpoint", "http://localhost:8000", + "--write", + ) + if runErr != nil { + t.Fatalf("setup --backend --write failed: %v", runErr) + } + data, readErr := os.ReadFile(filepath.Join(tmpDir, ".ctxrc")) + if readErr != nil { + t.Fatalf("ReadFile() error = %v", readErr) + } + if !strings.Contains(string(data), "token_budget: 123") { + t.Fatalf(".ctxrc = %q", string(data)) + } +} + +func TestSetupBackendEnvConflictWarning(t *testing.T) { + t.Setenv("CTX_TEST_BACKEND_KEY", "set") + out, runErr := executeSetup(t, + "--backend", "openai", + "--api-key-env", "CTX_TEST_BACKEND_KEY", + ) + if runErr != nil { + t.Fatalf("setup --backend failed: %v", runErr) + } + if !strings.Contains(out, "warning:") { + t.Fatalf("output = %q", out) + } +} + +func TestSetupBackendOpenCodeWritesProviderConfig(t *testing.T) { + project := chdirTemp(t) + home := t.TempDir() + t.Setenv("OPENCODE_HOME", home) + _, runErr := executeSetup(t, + "opencode", + "--backend", "openai", + "--endpoint", "https://example.com/v1", + "--write", + ) + if runErr != nil { + t.Fatalf("setup opencode --backend failed: %v", runErr) + } + data, err := os.ReadFile(filepath.Join(home, "opencode.json")) + if err != nil { + t.Fatalf("ReadFile() error = %v", err) + } + if !strings.Contains(string(data), `"provider"`) || + !strings.Contains(string(data), `"baseURL": "https://example.com/v1"`) || + !strings.Contains(string(data), `"mcp"`) { + t.Fatalf("opencode.json = %s", string(data)) + } + if _, err := os.Stat(filepath.Join(project, ".ctxrc")); err != nil { + t.Fatalf(".ctxrc not written: %v", err) + } +} + +func TestSetupBackendOpenCodeUsesDefaultEndpoint(t *testing.T) { + project := chdirTemp(t) + home := t.TempDir() + t.Setenv("OPENCODE_HOME", home) + _, runErr := executeSetup(t, + "opencode", + "--backend", "openai", + "--write", + ) + if runErr != nil { + t.Fatalf("setup opencode --backend failed: %v", runErr) + } + data, err := os.ReadFile(filepath.Join(home, "opencode.json")) + if err != nil { + t.Fatalf("ReadFile() error = %v", err) + } + if !strings.Contains(string(data), `"baseURL": "https://api.openai.com"`) { + t.Fatalf("opencode.json = %s", string(data)) + } + if _, err := os.Stat(filepath.Join(project, ".ctxrc")); err != nil { + t.Fatalf(".ctxrc not written: %v", err) + } +} + +func TestSetupBackendMalformedCtxRCRejectedAndUntouched(t *testing.T) { + tmpDir := chdirTemp(t) + path := filepath.Join(tmpDir, ".ctxrc") + original := []byte("backends: [broken\n") + if err := os.WriteFile(path, original, 0o644); err != nil { + t.Fatalf("WriteFile() error = %v", err) + } + _, runErr := executeSetup(t, "--backend", "vllm", "--endpoint", "http://localhost:8000", "--write") + if runErr == nil { + t.Fatalf("malformed .ctxrc should fail") + } + after, err := os.ReadFile(path) + if err != nil { + t.Fatalf("ReadFile() error = %v", err) + } + if string(after) != string(original) { + t.Fatalf(".ctxrc changed: %q", string(after)) + } +} + +func executeSetup(t *testing.T, args ...string) (string, error) { + t.Helper() + buf := new(bytes.Buffer) + cmd := Cmd() + cmd.SetOut(buf) + cmd.SetErr(buf) + cmd.SetArgs(args) + runErr := cmd.Execute() + return buf.String(), runErr +} + +func chdirTemp(t *testing.T) string { + t.Helper() + tmpDir := t.TempDir() + origDir, wdErr := os.Getwd() + if wdErr != nil { + t.Fatalf("Getwd() error = %v", wdErr) + } + if chdirErr := os.Chdir(tmpDir); chdirErr != nil { + t.Fatalf("Chdir() error = %v", chdirErr) + } + t.Cleanup(func() { + if chdirErr := os.Chdir(origDir); chdirErr != nil { + t.Fatalf("Chdir() cleanup error = %v", chdirErr) + } + }) + return tmpDir +} diff --git a/internal/cli/setup/cmd/root/cmd.go b/internal/cli/setup/cmd/root/cmd.go index 56fd2de1f..65421d2b8 100644 --- a/internal/cli/setup/cmd/root/cmd.go +++ b/internal/cli/setup/cmd/root/cmd.go @@ -20,7 +20,7 @@ import ( // Cmd returns the "ctx setup" command for generating AI tool integrations. // // The command outputs configuration snippets and instructions for integrating -// Context with various AI coding tools like Claude Code, Cursor, Aider, etc. +// Context with various AI coding tools or backend setup flows. // // Flags: // - --write, -w: Write the configuration file instead of printing @@ -30,6 +30,11 @@ import ( // accepts a tool name argument func Cmd() *cobra.Command { var write bool + var backend string + var endpoint string + var apiKeyEnv string + var model string + var timeout string short, long := desc.Command(cmd.DescKeySetup) c := &cobra.Command{ @@ -38,9 +43,23 @@ func Cmd() *cobra.Command { Annotations: map[string]string{cli.AnnotationSkipInit: cli.AnnotationTrue}, Long: long, Example: desc.Example(cmd.DescKeySetup), - Args: cobra.ExactArgs(1), + Args: func(cmd *cobra.Command, args []string) error { + if backend != "" && len(args) <= 1 { + return nil + } + return cobra.ExactArgs(1)(cmd, args) + }, RunE: func(cmd *cobra.Command, args []string) error { - return Run(cmd, args, write) + return Run( + cmd, + args, + write, + backend, + endpoint, + apiKeyEnv, + model, + timeout, + ) }, } @@ -48,6 +67,26 @@ func Cmd() *cobra.Command { cFlag.Write, cFlag.ShortWrite, flag.DescKeySetupWrite, ) + flagbind.StringFlag(c, &backend, + cFlag.Backend, + flag.DescKeySetupBackend, + ) + flagbind.StringFlag(c, &endpoint, + cFlag.Endpoint, + flag.DescKeySetupEndpoint, + ) + flagbind.StringFlag(c, &apiKeyEnv, + cFlag.APIKeyEnv, + flag.DescKeySetupAPIKeyEnv, + ) + flagbind.StringFlag(c, &model, + cFlag.Model, + flag.DescKeySetupModel, + ) + flagbind.StringFlag(c, &timeout, + cFlag.Timeout, + flag.DescKeySetupTimeout, + ) return c } diff --git a/internal/cli/setup/cmd/root/run.go b/internal/cli/setup/cmd/root/run.go index 66b82d45b..056fc7f1a 100644 --- a/internal/cli/setup/cmd/root/run.go +++ b/internal/cli/setup/cmd/root/run.go @@ -13,6 +13,7 @@ import ( "github.com/ActiveMemory/ctx/internal/assets/read/desc" coreCC "github.com/ActiveMemory/ctx/internal/cli/initialize/core/claudecheck" coreAgents "github.com/ActiveMemory/ctx/internal/cli/setup/core/agents" + coreBackend "github.com/ActiveMemory/ctx/internal/cli/setup/core/backend" coreCline "github.com/ActiveMemory/ctx/internal/cli/setup/core/cline" coreCopilot "github.com/ActiveMemory/ctx/internal/cli/setup/core/copilot" coreCopCLI "github.com/ActiveMemory/ctx/internal/cli/setup/core/copilotcli" @@ -39,7 +40,44 @@ import ( // // Returns: // - error: Non-nil if the tool is not supported or file write fails -func Run(cmd *cobra.Command, args []string, writeFile bool) error { +func Run( + cmd *cobra.Command, + args []string, + writeFile bool, + backend string, + endpoint string, + apiKeyEnv string, + model string, + timeout string, +) error { + if backend != "" { + backendName := i18n.Fold(backend) + if runErr := coreBackend.Run(cmd.OutOrStdout(), coreBackend.Options{ + Name: backendName, + Endpoint: endpoint, + APIKeyEnv: apiKeyEnv, + Model: model, + Timeout: timeout, + Write: writeFile, + }); runErr != nil { + return runErr + } + if len(args) == 1 && i18n.Fold(args[0]) == cfgHook.ToolOpenCode { + if writeFile { + providerErr := coreOpenCode.EnsureProviderConfig( + cmd, + backendName, + coreBackend.ResolveEndpoint(backendName, endpoint), + ) + if providerErr != nil { + return providerErr + } + } + } + if len(args) == 0 { + return nil + } + } tool := i18n.Fold(args[0]) switch tool { diff --git a/internal/cli/setup/core/backend/backend.go b/internal/cli/setup/core/backend/backend.go new file mode 100644 index 000000000..c2a2f129f --- /dev/null +++ b/internal/cli/setup/core/backend/backend.go @@ -0,0 +1,71 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import ( + "io" + "os" + + cfgFS "github.com/ActiveMemory/ctx/internal/config/fs" + cfgSetup "github.com/ActiveMemory/ctx/internal/config/setup" + setupErr "github.com/ActiveMemory/ctx/internal/err/setup" + ctxio "github.com/ActiveMemory/ctx/internal/io" +) + +// Run writes or prints backend setup configuration. +// +// Parameters: +// - out: destination for dry-run output and warnings +// - options: backend setup options +// +// Returns: +// - error: read, marshal, or write failure +func Run(out io.Writer, options Options) error { + if validateErr := validate(options); validateErr != nil { + return validateErr + } + resolved := defaults(options) + if resolved.APIKeyEnv != "" && os.Getenv(resolved.APIKeyEnv) != "" { + if _, warnErr := io.WriteString( + out, + cfgSetup.BackendEnvWarn+resolved.APIKeyEnv+ + cfgSetup.BackendEnvWarnEnd, + ); warnErr != nil { + return setupErr.WriteFile(cfgSetup.FileCtxRC, warnErr) + } + } + content, contentErr := content(resolved) + if contentErr != nil { + return contentErr + } + if !resolved.Write { + if _, writeErr := io.WriteString( + out, + cfgSetup.BackendDryRunPrefix, + ); writeErr != nil { + return setupErr.WriteFile(cfgSetup.FileCtxRC, writeErr) + } + if _, writeErr := out.Write(content); writeErr != nil { + return setupErr.WriteFile(cfgSetup.FileCtxRC, writeErr) + } + return nil + } + if writeErr := ctxio.SafeWriteFile( + cfgSetup.FileCtxRC, + content, + cfgFS.PermFile, + ); writeErr != nil { + return setupErr.WriteFile(cfgSetup.FileCtxRC, writeErr) + } + if _, doneErr := io.WriteString( + out, + cfgSetup.BackendWriteDone, + ); doneErr != nil { + return setupErr.WriteFile(cfgSetup.FileCtxRC, doneErr) + } + return nil +} diff --git a/internal/cli/setup/core/backend/config_internal.go b/internal/cli/setup/core/backend/config_internal.go new file mode 100644 index 000000000..bcfa58346 --- /dev/null +++ b/internal/cli/setup/core/backend/config_internal.go @@ -0,0 +1,172 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import ( + "net/url" + "os" + + "gopkg.in/yaml.v3" + + cfgBackend "github.com/ActiveMemory/ctx/internal/config/backend" + cfgHTTP "github.com/ActiveMemory/ctx/internal/config/http" + cfgRC "github.com/ActiveMemory/ctx/internal/config/rc" + cfgSetup "github.com/ActiveMemory/ctx/internal/config/setup" + setupErr "github.com/ActiveMemory/ctx/internal/err/setup" + ctxio "github.com/ActiveMemory/ctx/internal/io" + rcPkg "github.com/ActiveMemory/ctx/internal/rc" +) + +// content returns merged .ctxrc YAML for backend setup. +// +// Parameters: +// - options: resolved backend setup options +// +// Returns: +// - []byte: YAML content +// - error: read or marshal failure +func content(options Options) ([]byte, error) { + root, readErr := readRoot() + if readErr != nil { + return nil, readErr + } + backends := mapping(root, cfgRC.BackendsKey) + if scalar(backends, cfgRC.BackendDefaultKey) == nil { + setScalar(backends, cfgRC.BackendDefaultKey, options.Name) + } + entry := mapping(backends, options.Name) + setScalar(entry, cfgRC.BackendTypeKey, options.Name) + setScalar(entry, cfgRC.BackendEndpointKey, options.Endpoint) + setScalar(entry, cfgRC.BackendAPIKeyEnvKey, options.APIKeyEnv) + setScalar(entry, cfgRC.BackendTimeoutKey, options.Timeout) + setScalar(entry, cfgRC.BackendDefaultModelKey, options.Model) + return yaml.Marshal(root) +} + +// readRoot reads .ctxrc into a YAML mapping node. +// +// Returns: +// - *yaml.Node: root document mapping +// - error: read or decode failure +func readRoot() (*yaml.Node, error) { + data, readErr := ctxio.SafeReadUserFile(cfgSetup.FileCtxRC) + if readErr != nil && !os.IsNotExist(readErr) { + return nil, readErr + } + root := &yaml.Node{Kind: yaml.MappingNode} + if len(data) == 0 { + return root, nil + } + if _, validateErr := rcPkg.Validate(data); validateErr != nil { + return nil, validateErr + } + var doc yaml.Node + if decodeErr := yaml.Unmarshal(data, &doc); decodeErr != nil { + return nil, decodeErr + } + if len(doc.Content) == 0 { + return root, nil + } + if doc.Content[0].Kind != yaml.MappingNode { + return nil, setupErr.BackendRCMapping() + } + return doc.Content[0], nil +} + +// defaults applies backend-specific option defaults. +// +// Parameters: +// - options: backend setup options +// +// Returns: +// - Options: setup options with defaults applied +func defaults(options Options) Options { + if options.Endpoint == "" { + options.Endpoint = defaultEndpoint(options.Name) + } + if options.APIKeyEnv == "" { + options.APIKeyEnv = defaultAPIKeyEnv(options.Name) + } + return options +} + +// validate reports whether backend setup options name a supported backend. +// +// Parameters: +// - options: backend setup options +// +// Returns: +// - error: unsupported backend error, or nil when supported +func validate(options Options) error { + if defaultEndpoint(options.Name) == "" && + options.Name != cfgBackend.NameOpenAICompatible { + return setupErr.UnsupportedBackend(options.Name) + } + if options.Name == cfgBackend.NameOpenAICompatible && options.Endpoint == "" { + return setupErr.BackendEndpointRequired(options.Name) + } + if options.Endpoint != "" { + parsed, parseErr := url.Parse(options.Endpoint) + if parseErr != nil || + (parsed.Scheme != cfgHTTP.SchemeHTTP && + parsed.Scheme != cfgHTTP.SchemeHTTPS) { + return setupErr.BackendEndpointScheme(options.Name) + } + } + return nil +} + +// defaultEndpoint returns the default endpoint for a backend. +// +// Parameters: +// - name: backend name +// +// Returns: +// - string: default endpoint, or empty when unknown +func defaultEndpoint(name string) string { + switch name { + case cfgBackend.NameVLLM: + return cfgBackend.DefaultEndpointVLLM + case cfgBackend.NameOpenAI: + return cfgBackend.DefaultEndpointOpenAI + case cfgBackend.NameAnthropic: + return cfgBackend.DefaultEndpointAnthropic + case cfgBackend.NameOllama: + return cfgBackend.DefaultEndpointOllama + case cfgBackend.NameLMStudio: + return cfgBackend.DefaultEndpointLMStudio + default: + return "" + } +} + +// defaultAPIKeyEnv returns the default credential env var for a backend. +// +// Parameters: +// - name: backend name +// +// Returns: +// - string: default env var, or empty when none +func defaultAPIKeyEnv(name string) string { + switch name { + case cfgBackend.NameOpenAI: + return cfgBackend.DefaultAPIKeyEnvOpenAI + case cfgBackend.NameAnthropic: + return cfgBackend.DefaultAPIKeyEnvAnthropic + default: + return "" + } +} + +// downstreamEnv returns optional shell export hints for downstream tools. +// +// Parameters: +// - name: backend name +// - endpoint: configured backend endpoint +// +// Returns: +// - string: shell export line, or empty when no hint applies diff --git a/internal/cli/setup/core/backend/doc.go b/internal/cli/setup/core/backend/doc.go new file mode 100644 index 000000000..828431aa4 --- /dev/null +++ b/internal/cli/setup/core/backend/doc.go @@ -0,0 +1,12 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +// Package backend writes .ctxrc backend setup entries. +// +// It owns both dry-run snippet generation and safe file updates for the +// setup command's backend mode. The package deliberately does not create +// runtime backend instances or wire command dispatch. +package backend diff --git a/internal/cli/setup/core/backend/resolve.go b/internal/cli/setup/core/backend/resolve.go new file mode 100644 index 000000000..7c8f24e22 --- /dev/null +++ b/internal/cli/setup/core/backend/resolve.go @@ -0,0 +1,37 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import cfgBackend "github.com/ActiveMemory/ctx/internal/config/backend" + +// ResolveEndpoint returns the explicit endpoint or the backend default. +// +// Parameters: +// - name: configured backend name +// - endpoint: explicit endpoint flag value, if any +// +// Returns: +// - string: explicit endpoint when set, otherwise the backend default +func ResolveEndpoint(name string, endpoint string) string { + if endpoint != "" { + return endpoint + } + switch name { + case cfgBackend.NameVLLM: + return cfgBackend.DefaultEndpointVLLM + case cfgBackend.NameOpenAI: + return cfgBackend.DefaultEndpointOpenAI + case cfgBackend.NameAnthropic: + return cfgBackend.DefaultEndpointAnthropic + case cfgBackend.NameOllama: + return cfgBackend.DefaultEndpointOllama + case cfgBackend.NameLMStudio: + return cfgBackend.DefaultEndpointLMStudio + default: + return "" + } +} diff --git a/internal/cli/setup/core/backend/types.go b/internal/cli/setup/core/backend/types.go new file mode 100644 index 000000000..709b62654 --- /dev/null +++ b/internal/cli/setup/core/backend/types.go @@ -0,0 +1,25 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +// Options controls backend setup output. +// +// Fields: +// - Name: backend name to configure +// - Endpoint: backend HTTP endpoint +// - APIKeyEnv: environment variable containing credentials +// - Model: default model name +// - Timeout: backend request timeout duration +// - Write: whether to write .ctxrc instead of printing a snippet +type Options struct { + Name string + Endpoint string + APIKeyEnv string + Model string + Timeout string + Write bool +} diff --git a/internal/cli/setup/core/backend/yaml_internal.go b/internal/cli/setup/core/backend/yaml_internal.go new file mode 100644 index 000000000..099134802 --- /dev/null +++ b/internal/cli/setup/core/backend/yaml_internal.go @@ -0,0 +1,72 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import "gopkg.in/yaml.v3" + +// mapping returns a child mapping node, creating it when absent. +// +// Parameters: +// - parent: mapping node to search +// - key: child key +// +// Returns: +// - *yaml.Node: child mapping node +func mapping(parent *yaml.Node, key string) *yaml.Node { + for idx := 0; idx < len(parent.Content); idx += 2 { + if parent.Content[idx].Value == key { + parent.Content[idx+1].Kind = yaml.MappingNode + return parent.Content[idx+1] + } + } + child := &yaml.Node{Kind: yaml.MappingNode} + parent.Content = append(parent.Content, scalarNode(key), child) + return child +} + +// scalar returns a child scalar node by key. +// +// Parameters: +// - parent: mapping node to search +// - key: child key +// +// Returns: +// - *yaml.Node: child scalar node, or nil +func scalar(parent *yaml.Node, key string) *yaml.Node { + for idx := 0; idx < len(parent.Content); idx += 2 { + if parent.Content[idx].Value == key { + return parent.Content[idx+1] + } + } + return nil +} + +// setScalar sets a child scalar node by key. +// +// Parameters: +// - parent: mapping node to mutate +// - key: child key +// - value: scalar value +func setScalar(parent *yaml.Node, key string, value string) { + if existing := scalar(parent, key); existing != nil { + existing.Kind = yaml.ScalarNode + existing.Value = value + return + } + parent.Content = append(parent.Content, scalarNode(key), scalarNode(value)) +} + +// scalarNode creates a YAML scalar node. +// +// Parameters: +// - value: scalar value +// +// Returns: +// - *yaml.Node: scalar node +func scalarNode(value string) *yaml.Node { + return &yaml.Node{Kind: yaml.ScalarNode, Value: value} +} diff --git a/internal/cli/setup/core/opencode/provider.go b/internal/cli/setup/core/opencode/provider.go new file mode 100644 index 000000000..1d71b60a4 --- /dev/null +++ b/internal/cli/setup/core/opencode/provider.go @@ -0,0 +1,75 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package opencode + +import ( + "encoding/json" + "os" + + "github.com/spf13/cobra" + + cfgFS "github.com/ActiveMemory/ctx/internal/config/fs" + cfgToken "github.com/ActiveMemory/ctx/internal/config/token" + errFS "github.com/ActiveMemory/ctx/internal/err/fs" + setupErr "github.com/ActiveMemory/ctx/internal/err/setup" + ctxio "github.com/ActiveMemory/ctx/internal/io" + writeSetup "github.com/ActiveMemory/ctx/internal/write/setup" +) + +// EnsureProviderConfig merges backend baseURL wiring into the user's +// OpenCode global config. +// +// Parameters: +// - cmd: Cobra command for output messages +// - backendName: configured ctx backend name +// - endpoint: resolved backend endpoint URL +// +// Returns: +// - error: read, merge, marshal, or write failure +func EnsureProviderConfig( + cmd *cobra.Command, + backendName string, + endpoint string, +) error { + target, pathErr := globalConfigPath() + if pathErr != nil { + return pathErr + } + if _, validateErr := validateManagedTarget(target); validateErr != nil { + return validateErr + } + providerID, npmPackage, ok := providerDetails(backendName) + if !ok { + return nil + } + config := map[string]any{} + data, readErr := ctxio.SafeReadUserFile(target) + if readErr == nil { + if len(data) > 0 { + if unmarshalErr := json.Unmarshal(data, &config); unmarshalErr != nil { + return setupErr.MarshalConfig(unmarshalErr) + } + } + } else if !os.IsNotExist(readErr) { + return errFS.FileRead(target, readErr) + } + mergeProviderConfig(config, providerID, npmPackage, endpoint) + out, marshalErr := json.MarshalIndent(config, "", cfgToken.Indent2) + if marshalErr != nil { + return setupErr.MarshalConfig(marshalErr) + } + out = append(out, cfgToken.NewlineLF...) + if writeFileErr := ctxio.SafeWriteFileAtomic( + target, + out, + cfgFS.PermFile, + ); writeFileErr != nil { + return errFS.FileWrite(target, writeFileErr) + } + writeSetup.InfoOpenCodeCreated(cmd, target) + return nil +} diff --git a/internal/cli/setup/core/opencode/provider_internal.go b/internal/cli/setup/core/opencode/provider_internal.go new file mode 100644 index 000000000..03cb8f3e4 --- /dev/null +++ b/internal/cli/setup/core/opencode/provider_internal.go @@ -0,0 +1,74 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package opencode + +import ( + cfgBackend "github.com/ActiveMemory/ctx/internal/config/backend" + cfgOpenCode "github.com/ActiveMemory/ctx/internal/config/opencode" +) + +// providerDetails returns the OpenCode provider ID and optional npm package. +// +// Parameters: +// - name: configured ctx backend name +// +// Returns: +// - string: provider ID +// - string: npm package for custom providers, or empty +// - bool: true when the backend maps to an OpenCode provider +func providerDetails(name string) (string, string, bool) { + switch name { + case cfgBackend.NameOpenAI: + return cfgOpenCode.ProviderIDOpenAI, "", true + case cfgBackend.NameAnthropic: + return cfgOpenCode.ProviderIDAnthropic, "", true + case cfgBackend.NameOpenAICompatible, + cfgBackend.NameVLLM, + cfgBackend.NameOllama, + cfgBackend.NameLMStudio: + return name, cfgOpenCode.ProviderNPMOpenAICompatible, true + default: + return "", "", false + } +} + +// mergeProviderConfig overlays one provider entry into an OpenCode config map. +// +// Parameters: +// - config: parsed OpenCode config map to mutate in place +// - providerID: target provider identifier +// - npmPackage: optional custom npm package for the provider +// - endpoint: backend base URL to write into provider options +// +// Returns: +// - none +func mergeProviderConfig( + config map[string]any, + providerID string, + npmPackage string, + endpoint string, +) { + providers, _ := config[cfgOpenCode.KeyProvider].(map[string]any) + if providers == nil { + providers = map[string]any{} + } + entry, _ := providers[providerID].(map[string]any) + if entry == nil { + entry = map[string]any{} + } + if npmPackage != "" { + entry[cfgOpenCode.KeyNPM] = npmPackage + } + options, _ := entry[cfgOpenCode.KeyOptions].(map[string]any) + if options == nil { + options = map[string]any{} + } + options[cfgOpenCode.KeyBaseURL] = endpoint + entry[cfgOpenCode.KeyOptions] = options + providers[providerID] = entry + config[cfgOpenCode.KeyProvider] = providers +} diff --git a/internal/cli/setup/core/opencode/provider_test.go b/internal/cli/setup/core/opencode/provider_test.go new file mode 100644 index 000000000..ca7b61b0b --- /dev/null +++ b/internal/cli/setup/core/opencode/provider_test.go @@ -0,0 +1,57 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package opencode + +import ( + "bytes" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/spf13/cobra" +) + +func TestEnsureProviderConfig_WritesProviderBaseURL(t *testing.T) { + home := t.TempDir() + t.Setenv("OPENCODE_HOME", home) + if err := EnsureProviderConfig(testProviderCmd(), "openai", "https://example.com/v1"); err != nil { + t.Fatalf("EnsureProviderConfig() error = %v", err) + } + data, err := os.ReadFile(filepath.Join(home, "opencode.json")) + if err != nil { + t.Fatalf("ReadFile() error = %v", err) + } + if !strings.Contains(string(data), `"baseURL": "https://example.com/v1"`) { + t.Fatalf("opencode.json = %s", string(data)) + } +} + +func TestEnsureProviderConfig_PreservesExistingKeys(t *testing.T) { + home := t.TempDir() + t.Setenv("OPENCODE_HOME", home) + path := filepath.Join(home, "opencode.json") + if err := os.WriteFile(path, []byte(`{"theme":"dark"}`), 0o644); err != nil { + t.Fatalf("WriteFile() error = %v", err) + } + if err := EnsureProviderConfig(testProviderCmd(), "openai-compatible", "https://proxy.example"); err != nil { + t.Fatalf("EnsureProviderConfig() error = %v", err) + } + data, err := os.ReadFile(path) + if err != nil { + t.Fatalf("ReadFile() error = %v", err) + } + if !strings.Contains(string(data), `"theme": "dark"`) || !strings.Contains(string(data), `"provider"`) { + t.Fatalf("opencode.json = %s", string(data)) + } +} + +func testProviderCmd() *cobra.Command { + cmd := &cobra.Command{} + cmd.SetOut(&bytes.Buffer{}) + return cmd +} diff --git a/internal/cli/system/cmd/statusline/cmd.go b/internal/cli/system/cmd/statusline/cmd.go deleted file mode 100644 index 6082d51b6..000000000 --- a/internal/cli/system/cmd/statusline/cmd.go +++ /dev/null @@ -1,35 +0,0 @@ -// / ctx: https://ctx.ist -// ,'`./ do you remember? -// `.,'\ -// \ Copyright 2026-present Context contributors. -// SPDX-License-Identifier: Apache-2.0 - -package statusline - -import ( - "os" - - "github.com/spf13/cobra" - - "github.com/ActiveMemory/ctx/internal/assets/read/desc" - "github.com/ActiveMemory/ctx/internal/config/embed/cmd" -) - -// Cmd returns the "ctx system statusline" subcommand. -// -// Returns: -// - *cobra.Command: Configured statusline subcommand -func Cmd() *cobra.Command { - short, long := desc.Command(cmd.DescKeySystemStatusline) - - return &cobra.Command{ - Use: cmd.UseSystemStatusline, - Short: short, - Long: long, - Example: desc.Example(cmd.DescKeySystemStatusline), - Hidden: true, - RunE: func(cmd *cobra.Command, _ []string) error { - return Run(cmd, os.Stdin) - }, - } -} diff --git a/internal/cli/system/cmd/statusline/doc.go b/internal/cli/system/cmd/statusline/doc.go deleted file mode 100644 index ff8f9eb3a..000000000 --- a/internal/cli/system/cmd/statusline/doc.go +++ /dev/null @@ -1,56 +0,0 @@ -// / ctx: https://ctx.ist -// ,'`./ do you remember? -// `.,'\ -// \ Copyright 2026-present Context contributors. -// SPDX-License-Identifier: Apache-2.0 - -// Package statusline implements the hidden -// "ctx system statusline" cobra subcommand. -// -// Claude Code invokes the configured statusLine command after each -// assistant message and pipes a JSON payload to its stdin; the first -// line of stdout becomes the status line. ctx init wires this command -// into .claude/settings.local.json (see the initialize merge core). -// -// # Behavior -// -// The command renders one line assembled from up to four segments: -// -// user@host dir | model | ctx: N% | $C.CC -// -// Location comes from the process environment plus -// workspace.current_dir (falling back to cwd), home-abbreviated. -// Model comes from model.display_name. Context percentage comes -// from context_window.used_percentage, which may be null early in -// a session. Cost comes from cost.total_cost_usd, rendered as a -// plain figure; the segment is suppressed when .ctxrc sets -// statusline.show_cost to false. -// -// Missing payload fields drop their segment rather than rendering a -// placeholder: a wrong-looking number is worse than an absent one. -// Malformed input degrades to whatever segments remain renderable. -// When statusline.enabled is false, the command prints an empty -// line so the display blanks immediately. -// -// The command always exits zero: Claude Code blanks the status line -// on a non-zero exit, so failures here must never be fatal. Output -// is sanitized to bounded printable ASCII; hostile payload content -// cannot corrupt the terminal. -// -// This surface is deliberately informational. There is no cost -// gating and no model-switch nudging (specs/statusline.md records -// the rationale). -// -// # Flags -// -// None. The command reads the status line JSON payload from stdin. -// -// # Output -// -// A single sanitized line on stdout. -// -// # Delegation -// -// Rendering primitives live in system/core/statusline; the line is -// written via write/statusline. -package statusline diff --git a/internal/cli/system/cmd/statusline/run.go b/internal/cli/system/cmd/statusline/run.go deleted file mode 100644 index 9a8191767..000000000 --- a/internal/cli/system/cmd/statusline/run.go +++ /dev/null @@ -1,80 +0,0 @@ -// / ctx: https://ctx.ist -// ,'`./ do you remember? -// `.,'\ -// \ Copyright 2026-present Context contributors. -// SPDX-License-Identifier: Apache-2.0 - -package statusline - -import ( - "encoding/json" - "fmt" - "io" - "os" - "strings" - - "github.com/spf13/cobra" - - core "github.com/ActiveMemory/ctx/internal/cli/system/core/statusline" - cfgStatusline "github.com/ActiveMemory/ctx/internal/config/statusline" - "github.com/ActiveMemory/ctx/internal/rc" - writeStatusline "github.com/ActiveMemory/ctx/internal/write/statusline" -) - -// Run executes the statusline rendering logic. -// -// Reads the status line JSON payload from stdin and prints one -// sanitized line assembled from location, model, context-usage, and -// cost segments. Missing fields drop their segment; malformed input -// degrades to whatever remains renderable. When statusline.enabled -// is false in .ctxrc, prints an empty line so the displayed status -// line goes blank immediately. -// -// Parameters: -// - cmd: Cobra command for output -// - stdin: standard input carrying the status line JSON payload -// -// Returns: -// - error: Always nil (a non-zero exit blanks the status line) -func Run(cmd *cobra.Command, stdin *os.File) error { - if !rc.StatuslineEnabled() { - // statusline.enabled: false takes effect immediately by - // rendering nothing; the settings.local.json entry itself is - // restored/removed the next time the init merge runs. - writeStatusline.Blank(cmd) - return nil - } - var p core.Payload - if raw, readErr := io.ReadAll( - io.LimitReader(stdin, cfgStatusline.MaxPayloadBytes), - ); readErr == nil { - // Unmarshal errors are deliberately ignored: a partial or - // malformed payload still renders a degraded line below. - _ = json.Unmarshal(raw, &p) - } - - segments := make([]string, 0, cfgStatusline.SegmentCapacity) - if loc := core.LocationSegment(&p); loc != "" { - segments = append(segments, loc) - } - if model := core.Sanitize(p.Model.DisplayName); model != "" { - segments = append(segments, model) - } - if pct := p.ContextWindow.UsedPercentage; pct != nil && - *pct >= 0 && *pct <= cfgStatusline.PercentMax { - segments = append(segments, - fmt.Sprintf(cfgStatusline.ContextFormat, *pct)) - } - if cost := p.Cost.TotalCostUSD; cost != nil && *cost >= 0 && - rc.StatuslineShowCost() { - segments = append(segments, - fmt.Sprintf(cfgStatusline.CostFormat, *cost)) - } - - line := strings.Join(segments, cfgStatusline.SegmentSeparator) - if len(line) > cfgStatusline.MaxLineLen { - line = line[:cfgStatusline.MaxLineLen] - } - writeStatusline.Line(cmd, line) - return nil -} diff --git a/internal/cli/system/cmd/statusline/run_test.go b/internal/cli/system/cmd/statusline/run_test.go deleted file mode 100644 index af4eabdff..000000000 --- a/internal/cli/system/cmd/statusline/run_test.go +++ /dev/null @@ -1,215 +0,0 @@ -// / ctx: https://ctx.ist -// ,'`./ do you remember? -// `.,'\ -// \ Copyright 2026-present Context contributors. -// SPDX-License-Identifier: Apache-2.0 - -package statusline - -import ( - "bytes" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/spf13/cobra" - - cfgStatusline "github.com/ActiveMemory/ctx/internal/config/statusline" - "github.com/ActiveMemory/ctx/internal/rc" -) - -// render feeds the given payload through Run via a pipe and returns -// the rendered line. -func render(t *testing.T, payloadJSON string) string { - t.Helper() - r, w, pipeErr := os.Pipe() - if pipeErr != nil { - t.Fatalf("failed to create pipe: %v", pipeErr) - } - if _, writeErr := w.WriteString(payloadJSON); writeErr != nil { - t.Fatalf("failed to write payload: %v", writeErr) - } - if closeErr := w.Close(); closeErr != nil { - t.Fatalf("failed to close pipe writer: %v", closeErr) - } - defer func() { _ = r.Close() }() - - var buf bytes.Buffer - cmd := &cobra.Command{} - cmd.SetOut(&buf) - if runErr := Run(cmd, r); runErr != nil { - t.Fatalf("Run returned error: %v", runErr) - } - return strings.TrimRight(buf.String(), "\n") -} - -func TestRunRendersAllSegments(t *testing.T) { - line := render(t, `{ - "model": {"display_name": "Opus"}, - "workspace": {"current_dir": "/tmp/project"}, - "cost": {"total_cost_usd": 1.2345}, - "context_window": {"used_percentage": 42.4} - }`) - - for _, want := range []string{"Opus", "ctx: 42%", "$1.23"} { - if !strings.Contains(line, want) { - t.Errorf("line %q missing %q", line, want) - } - } - if !strings.Contains(line, cfgStatusline.SegmentSeparator) { - t.Errorf("line %q missing segment separator", line) - } -} - -func TestRunMalformedPayloadDegrades(t *testing.T) { - line := render(t, `{not json at all`) - if strings.Contains(line, "$") || strings.Contains(line, "ctx:") { - t.Errorf("degraded line %q should carry no payload segments", line) - } -} - -func TestRunEmptyPayloadDegrades(t *testing.T) { - line := render(t, `{}`) - if strings.Contains(line, "$") || strings.Contains(line, "ctx:") { - t.Errorf("line %q should drop segments for absent fields", line) - } -} - -func TestRunMissingCostOmitsSegment(t *testing.T) { - line := render(t, `{ - "model": {"display_name": "Opus"}, - "context_window": {"used_percentage": 10} - }`) - if strings.Contains(line, "$") { - t.Errorf("line %q renders a cost segment without cost data", line) - } -} - -func TestRunNullPercentageOmitsSegment(t *testing.T) { - line := render(t, `{ - "model": {"display_name": "Opus"}, - "context_window": {"used_percentage": null}, - "cost": {"total_cost_usd": 0.5} - }`) - if strings.Contains(line, "ctx:") { - t.Errorf("line %q renders ctx segment for null percentage", line) - } - if !strings.Contains(line, "$0.50") { - t.Errorf("line %q missing cost segment", line) - } -} - -func TestRunOutOfRangePercentageDropped(t *testing.T) { - line := render(t, `{ - "context_window": {"used_percentage": 250} - }`) - if strings.Contains(line, "ctx:") { - t.Errorf("line %q renders out-of-range percentage", line) - } -} - -func TestRunSanitizesEscapedControlChars(t *testing.T) { - // ANSI escape encoded as a legal JSON \u escape: the payload - // parses, and sanitize must strip the ESC byte from the output. - line := render(t, `{ - "model": {"display_name": "\u001b[31mOpus\u001b[0m\nInjected"} - }`) - if strings.ContainsAny(line, "\x1b\n\r\x07") { - t.Errorf("line %q contains control bytes", line) - } - if !strings.Contains(line, "Opus") { - t.Errorf("line %q lost the printable model name", line) - } -} - -func TestRunRawControlBytesDegrade(t *testing.T) { - // A raw ESC byte inside a JSON string is invalid JSON. The - // payload must fail closed: degraded line, no control bytes. - line := render(t, "{\"model\": {\"display_name\": \"\x1b[31mOpus\"}}") - if strings.ContainsAny(line, "\x1b\n\r\x07") { - t.Errorf("line %q contains control bytes", line) - } - if strings.Contains(line, "Opus") { - t.Errorf("line %q rendered a field from invalid JSON", line) - } -} - -func TestRunCapsLineLength(t *testing.T) { - line := render(t, `{ - "model": {"display_name": "`+strings.Repeat("m", 500)+`"} - }`) - if len(line) > cfgStatusline.MaxLineLen { - t.Errorf("line length %d exceeds cap %d", - len(line), cfgStatusline.MaxLineLen) - } -} - -func TestRunDisabledRendersBlankLine(t *testing.T) { - tmpDir, mkErr := os.MkdirTemp("", "ctx-statusline-off-*") - if mkErr != nil { - t.Fatalf("failed to create temp dir: %v", mkErr) - } - defer func() { _ = os.RemoveAll(tmpDir) }() - - if mkdirErr := os.Mkdir(filepath.Join(tmpDir, ".context"), 0o750); mkdirErr != nil { - t.Fatalf("failed to create .context: %v", mkdirErr) - } - rcBody := "statusline:\n enabled: false\n" - if writeErr := os.WriteFile( - filepath.Join(tmpDir, ".ctxrc"), []byte(rcBody), 0o600, - ); writeErr != nil { - t.Fatalf("failed to write .ctxrc: %v", writeErr) - } - - origDir, _ := os.Getwd() - if chdirErr := os.Chdir(tmpDir); chdirErr != nil { - t.Fatalf("failed to chdir: %v", chdirErr) - } - defer func() { _ = os.Chdir(origDir) }() - rc.Reset() - defer rc.Reset() - - line := render(t, `{"model": {"display_name": "Opus"}}`) - if line != "" { - t.Errorf("disabled statusline rendered %q; want empty", line) - } -} - -func TestRunShowCostFalseSuppressesCost(t *testing.T) { - tmpDir, mkErr := os.MkdirTemp("", "ctx-statusline-*") - if mkErr != nil { - t.Fatalf("failed to create temp dir: %v", mkErr) - } - defer func() { _ = os.RemoveAll(tmpDir) }() - - // .ctxrc is only read when $PWD/.context/ exists (cwd-anchored - // resolution model). - if mkdirErr := os.Mkdir(filepath.Join(tmpDir, ".context"), 0o750); mkdirErr != nil { - t.Fatalf("failed to create .context: %v", mkdirErr) - } - rcPath := filepath.Join(tmpDir, ".ctxrc") - rcBody := "statusline:\n show_cost: false\n" - if writeErr := os.WriteFile(rcPath, []byte(rcBody), 0o600); writeErr != nil { - t.Fatalf("failed to write .ctxrc: %v", writeErr) - } - - origDir, _ := os.Getwd() - if chdirErr := os.Chdir(tmpDir); chdirErr != nil { - t.Fatalf("failed to chdir: %v", chdirErr) - } - defer func() { _ = os.Chdir(origDir) }() - rc.Reset() - defer rc.Reset() - - line := render(t, `{ - "model": {"display_name": "Opus"}, - "cost": {"total_cost_usd": 9.99} - }`) - if strings.Contains(line, "$") { - t.Errorf("line %q renders cost despite show_cost: false", line) - } - if !strings.Contains(line, "Opus") { - t.Errorf("line %q lost non-cost segments", line) - } -} diff --git a/internal/cli/system/core/session/session_token.go b/internal/cli/system/core/session/session_token.go index 644baabd5..30610fb4f 100644 --- a/internal/cli/system/core/session/session_token.go +++ b/internal/cli/system/core/session/session_token.go @@ -222,16 +222,11 @@ func ModelContextWindow(model string) int { lower := i18n.Fold(model) - // 1M models: explicit [1m] suffix OR families that are always 1M - // (Opus 4.6+, Sonnet 5+, and the Claude 5 Mythos-class: - // Fable/Mythos). + // 1M models: explicit [1m] suffix OR Opus 4.6+ (always 1M). if strings.Contains(lower, claude.ModelSuffix1M) { return claude.ContextWindow1M } - if strings.Contains(lower, claude.ModelOpus) || - strings.Contains(lower, claude.ModelFable) || - strings.Contains(lower, claude.ModelMythos) || - strings.Contains(lower, claude.ModelSonnet5) { + if strings.Contains(lower, claude.ModelOpus) { return claude.ContextWindow1M } diff --git a/internal/cli/system/core/session/session_token_test.go b/internal/cli/system/core/session/session_token_test.go index 67043f558..c8c59f896 100644 --- a/internal/cli/system/core/session/session_token_test.go +++ b/internal/cli/system/core/session/session_token_test.go @@ -39,21 +39,6 @@ func TestModelContextWindow(t *testing.T) { model: "claude-sonnet-4-6-20260205", want: rc.DefaultContextWindow, }, - { - name: "claude fable is always 1M", - model: "claude-fable-5", - want: claude.ContextWindow1M, - }, - { - name: "claude mythos is always 1M", - model: "claude-mythos-5", - want: claude.ContextWindow1M, - }, - { - name: "claude sonnet 5 is 1M as standard", - model: "claude-sonnet-5", - want: claude.ContextWindow1M, - }, { name: "claude with 1m suffix", model: "claude-opus-4-6[1m]", diff --git a/internal/cli/system/core/statusline/doc.go b/internal/cli/system/core/statusline/doc.go deleted file mode 100644 index 148e0e47a..000000000 --- a/internal/cli/system/core/statusline/doc.go +++ /dev/null @@ -1,19 +0,0 @@ -// / ctx: https://ctx.ist -// ,'`./ do you remember? -// `.,'\ -// \ Copyright 2026-present Context contributors. -// SPDX-License-Identifier: Apache-2.0 - -// Package statusline renders the segments of the ctx status line -// from Claude Code's statusLine stdin payload. -// -// The cmd-layer package (cli/system/cmd/statusline) owns mode -// decisions (enabled, show_cost) and output; this core package owns -// the pure rendering: payload modeling, location resolution, path -// abbreviation, and printable-ASCII sanitization. -// -// All rendering degrades instead of failing: missing payload fields -// yield empty segments, and hostile content is stripped to bounded -// printable ASCII so it cannot corrupt the terminal -// (specs/statusline.md). -package statusline diff --git a/internal/cli/system/core/statusline/render.go b/internal/cli/system/core/statusline/render.go deleted file mode 100644 index 1006965df..000000000 --- a/internal/cli/system/core/statusline/render.go +++ /dev/null @@ -1,138 +0,0 @@ -// / ctx: https://ctx.ist -// ,'`./ do you remember? -// `.,'\ -// \ Copyright 2026-present Context contributors. -// SPDX-License-Identifier: Apache-2.0 - -package statusline - -import ( - "os" - "os/user" - "path/filepath" - "strings" - - "github.com/ActiveMemory/ctx/internal/config/env" - cfgStatusline "github.com/ActiveMemory/ctx/internal/config/statusline" - "github.com/ActiveMemory/ctx/internal/config/token" -) - -// LocationSegment renders "user@host dir" from the process -// environment and the payload's working directory. Any part that -// cannot be determined is omitted; an empty result drops the whole -// segment. -// -// Parameters: -// - p: parsed status line payload -// -// Returns: -// - string: location segment, or "" when nothing is resolvable -func LocationSegment(p *Payload) string { - userHost := UserAtHost() - dir := ShortDir(WorkingDir(p)) - switch { - case userHost != "" && dir != "": - return userHost + token.Space + dir - case userHost != "": - return userHost - default: - return dir - } -} - -// UserAtHost renders the "user@host" prefix from the process -// environment. -// -// Returns: -// - string: "user@host", a lone part when only one resolves, or "" -func UserAtHost() string { - name := os.Getenv(env.User) - if name == "" { - if u, userErr := user.Current(); userErr == nil { - name = u.Username - } - } - host, hostErr := os.Hostname() - if hostErr == nil { - // Short hostname: the domain suffix is noise at status-line - // widths. - host, _, _ = strings.Cut(host, cfgStatusline.HostDomainSeparator) - } - name = Sanitize(name) - host = Sanitize(host) - switch { - case name != "" && host != "": - return name + cfgStatusline.UserHostSeparator + host - case name != "": - return name - default: - return host - } -} - -// WorkingDir picks the payload's directory, preferring -// workspace.current_dir over the legacy cwd duplicate. -// -// Parameters: -// - p: parsed status line payload -// -// Returns: -// - string: working directory, or "" when the payload has none -func WorkingDir(p *Payload) string { - if p.Workspace.CurrentDir != "" { - return p.Workspace.CurrentDir - } - return p.Cwd -} - -// ShortDir home-abbreviates a path and collapses overlong results so -// deep trees do not crowd out the other segments. -// -// Parameters: -// - path: absolute directory path from the payload -// -// Returns: -// - string: display form of the path, or "" for empty input -func ShortDir(path string) string { - if path == "" { - return "" - } - if home, homeErr := os.UserHomeDir(); homeErr == nil && home != "" { - if rel, relErr := filepath.Rel(home, path); relErr == nil && - !strings.HasPrefix(rel, cfgStatusline.RelParentPrefix) { - if rel == cfgStatusline.RelSelf { - path = cfgStatusline.HomeAbbrev - } else { - path = cfgStatusline.HomeAbbrevPrefix + rel - } - } - } - path = Sanitize(path) - if len(path) > cfgStatusline.MaxDirLen { - path = cfgStatusline.TruncatedDirPrefix + filepath.Base(path) - } - return path -} - -// Sanitize reduces a payload-derived string to bounded printable -// ASCII. Control bytes, ANSI escapes, and multi-byte runes are -// stripped rather than replaced; the result is trimmed and capped at -// the segment bound. -// -// Parameters: -// - s: raw string from the payload or environment -// -// Returns: -// - string: printable-ASCII form, at most MaxSegmentLen bytes -func Sanitize(s string) string { - var b strings.Builder - b.Grow(len(s)) - for i := 0; i < len(s) && b.Len() < cfgStatusline.MaxSegmentLen; i++ { - c := s[i] - if c >= cfgStatusline.ASCIIPrintableMin && - c <= cfgStatusline.ASCIIPrintableMax { - b.WriteByte(c) - } - } - return strings.TrimSpace(b.String()) -} diff --git a/internal/cli/system/core/statusline/types.go b/internal/cli/system/core/statusline/types.go deleted file mode 100644 index 0436631b9..000000000 --- a/internal/cli/system/core/statusline/types.go +++ /dev/null @@ -1,36 +0,0 @@ -// / ctx: https://ctx.ist -// ,'`./ do you remember? -// `.,'\ -// \ Copyright 2026-present Context contributors. -// SPDX-License-Identifier: Apache-2.0 - -package statusline - -// Payload models the subset of Claude Code's status line stdin JSON -// that the ctx status line renders. Pointer fields distinguish absent -// or null values (segment dropped) from legitimate zeroes. -// -// Schema reference: https://code.claude.com/docs/en/statusline -// -// Fields: -// - Model: model identity; DisplayName feeds the model segment -// - Workspace: working directory (preferred over the legacy Cwd) -// - Cwd: legacy duplicate of Workspace.CurrentDir -// - Cost: session cost figures; TotalCostUSD feeds the $ segment -// - ContextWindow: context usage; UsedPercentage feeds the ctx% -// segment and may be null early in a session -type Payload struct { - Model struct { - DisplayName string `json:"display_name"` - } `json:"model"` - Workspace struct { - CurrentDir string `json:"current_dir"` - } `json:"workspace"` - Cwd string `json:"cwd"` - Cost struct { - TotalCostUSD *float64 `json:"total_cost_usd"` - } `json:"cost"` - ContextWindow struct { - UsedPercentage *float64 `json:"used_percentage"` - } `json:"context_window"` -} diff --git a/internal/cli/system/doc.go b/internal/cli/system/doc.go index da94d4106..77144a6fb 100644 --- a/internal/cli/system/doc.go +++ b/internal/cli/system/doc.go @@ -29,8 +29,6 @@ // - session-event: record session lifecycle events // - pause: session-scoped hook suppression // - resume: session-scoped hook re-enable -// - statusline: render the Claude Code status line -// from the statusLine stdin payload // // # Hook Subcommands // diff --git a/internal/cli/system/system.go b/internal/cli/system/system.go index 2342d2405..bde752c06 100644 --- a/internal/cli/system/system.go +++ b/internal/cli/system/system.go @@ -36,7 +36,6 @@ import ( "github.com/ActiveMemory/ctx/internal/cli/system/cmd/resume" sessEvent "github.com/ActiveMemory/ctx/internal/cli/system/cmd/sessionevent" "github.com/ActiveMemory/ctx/internal/cli/system/cmd/specsnudge" - "github.com/ActiveMemory/ctx/internal/cli/system/cmd/statusline" "github.com/ActiveMemory/ctx/internal/cli/unknown" "github.com/ActiveMemory/ctx/internal/config/embed/cmd" ) @@ -83,7 +82,6 @@ func Cmd() *cobra.Command { resume.Cmd(), sessEvent.Cmd(), specsnudge.Cmd(), - statusline.Cmd(), ) // An unknown `ctx system ` must fail loud — emit a verbatim // relay and exit non-zero — instead of dumping help at exit 0, diff --git a/internal/compliance/ai_boundary_test.go b/internal/compliance/ai_boundary_test.go new file mode 100644 index 000000000..0dbd8d5cb --- /dev/null +++ b/internal/compliance/ai_boundary_test.go @@ -0,0 +1,74 @@ +// / Context: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package compliance + +import ( + "go/parser" + "go/token" + "os" + "path/filepath" + "strings" + "testing" +) + +func TestDeterministicCoreDoesNotDependOnAIBackends(t *testing.T) { + root := projectRoot(t) + guardedPrefixes := []string{ + "internal/cli/agent/", + "internal/cli/status/", + "internal/cli/hook/", + } + + for _, path := range nonTestGoFiles(t, root) { + rel, relErr := filepath.Rel(root, path) + if relErr != nil { + t.Fatalf("filepath.Rel: %v", relErr) + } + rel = filepath.ToSlash(rel) + if !hasGuardedPrefix(rel, guardedPrefixes) { + continue + } + + assertNoBackendImport(t, path, rel) + assertNoAIInvocation(t, path, rel) + } +} + +func hasGuardedPrefix(path string, prefixes []string) bool { + for _, prefix := range prefixes { + if strings.HasPrefix(path, prefix) { + return true + } + } + return false +} + +func assertNoBackendImport(t *testing.T, path string, rel string) { + t.Helper() + fset := token.NewFileSet() + file, parseErr := parser.ParseFile(fset, path, nil, parser.ImportsOnly) + if parseErr != nil { + t.Fatalf("parser.ParseFile(%s): %v", rel, parseErr) + } + for _, imported := range file.Imports { + importPath := strings.Trim(imported.Path.Value, "\"") + if importPath == "github.com/ActiveMemory/ctx/internal/backend" { + t.Fatalf("%s imports internal/backend", rel) + } + } +} + +func assertNoAIInvocation(t *testing.T, path string, rel string) { + t.Helper() + data, readErr := os.ReadFile(filepath.Clean(path)) + if readErr != nil { + t.Fatalf("os.ReadFile(%s): %v", rel, readErr) + } + if strings.Contains(string(data), "ctx ai") { + t.Fatalf("%s invokes or documents ctx ai from deterministic core", rel) + } +} diff --git a/internal/config/ai/ai.go b/internal/config/ai/ai.go new file mode 100644 index 000000000..3a565a9bb --- /dev/null +++ b/internal/config/ai/ai.go @@ -0,0 +1,41 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package ai + +// Output labels and proposal constants. +const ( + ArtifactExtJSON = ".json" + ArtifactNonceFormat = "-%06d" + ArtifactPrefix = "proposal-" + DirAI = "ai" + DirProposals = "proposals" + ErrEmitRequired = "emit is required" + ErrInvalidArtifact = "invalid proposal artifact" + ErrInvalidArtifactResponse = "invalid proposal artifact response" + EmitSeparator = "," + KindProposedPatch = "proposed-patch" + PromptPrefix = "Return JSON for requested emit kinds: " + SchemaProposalName = "proposal" + StatusProposed = "proposed" + TimestampLayout = "20060102T150405.000000000Z07:00" + WritePingFormat = "backend: %s\nendpoint: %s\nfirst_model: %s\n" +) + +// ProposalSchema is the structured response schema for `ctx ai propose`. +const ProposalSchema = `{"type":"object","required":["rows","metadata"],` + + `"properties":{"rows":{"type":"array","minItems":1,` + + `"items":{"type":"object","required":["emit","text"],` + + `"properties":{"emit":{"type":"string"},` + + `"text":{"type":"string"},` + + `"start":{"type":"integer"},"end":{"type":"integer"}},` + + `"additionalProperties":false}},` + + `"metadata":{"type":"object",` + + `"required":["backend","model","input","status"],` + + `"properties":{"backend":{"type":"string"},` + + `"model":{"type":"string"},"input":{"type":"string"},` + + `"status":{"type":"string"}},"additionalProperties":false}},` + + `"additionalProperties":false}` diff --git a/internal/config/ai/doc.go b/internal/config/ai/doc.go new file mode 100644 index 000000000..777edc919 --- /dev/null +++ b/internal/config/ai/doc.go @@ -0,0 +1,12 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +// Package ai defines constants for the ctx ai command surface. +// +// Constants here keep command output labels, proposal artifact names, +// and schema placeholders out of implementation packages. It is a +// constants-only package for CLI-facing AI behavior. +package ai diff --git a/internal/config/backend/backend.go b/internal/config/backend/backend.go new file mode 100644 index 000000000..97ceef669 --- /dev/null +++ b/internal/config/backend/backend.go @@ -0,0 +1,68 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import "time" + +// Backend names for built-in backend factories. +const ( + NameAnthropic = "anthropic" + NameLMStudio = "lmstudio" + NameOllama = "ollama" + NameOpenAI = "openai" + NameOpenAICompatible = "openai-compatible" + NameVLLM = "vllm" +) + +// Default endpoints for built-in backend factories. +const ( + DefaultEndpointAnthropic = "https://api.anthropic.com" + DefaultEndpointLMStudio = "http://localhost:1234" + DefaultEndpointOllama = "http://localhost:11434" + DefaultEndpointOpenAI = "https://api.openai.com" + DefaultEndpointVLLM = "http://localhost:8000" +) + +// Default API key environment variables for backend factories. +const ( + DefaultAPIKeyEnvAnthropic = "ANTHROPIC_API_KEY" + DefaultAPIKeyEnvOpenAI = "OPENAI_API_KEY" +) + +// HTTP constants for OpenAI-compatible backends. +const ( + AuthorizationBearerPrefix = "Bearer " + ChatCompletionsPath = "/v1/chat/completions" + ContentTypeJSON = "application/json" + MaxResponseBytes = 1 << 20 + ResponseFormatJSONSchema = "json_schema" + HeaderAuthorization = "Authorization" + HeaderContentType = "Content-Type" + HTTPMethodGet = "GET" + HTTPMethodPost = "POST" + ModelsPath = "/v1/models" + RoleUser = "user" +) + +// DefaultTimeout is the fallback timeout for backend HTTP calls. +const DefaultTimeout = 30 * time.Second + +// Error messages for backend registry and HTTP failures. +const ( + ErrBadRequest = "backend request failed: " + ErrDuplicateRegistration = "backend already registered: " + ErrFactory = "backend factory failed: " + ErrInvalidEndpoint = "backend endpoint invalid: " + ErrInvalidResponseShape = "invalid structured response shape" + ErrMissingBackend = "backend not registered: " + ErrMultipleBackends = "multiple backends configured; pass --backend " + + "or set backends.default" + ErrNoBackendConfigured = "no backend configured; run ctx setup --backend" + FmtUpstreamStatusBody = "%d: %s" + ErrUnreachable = "backend unreachable: " + ErrUpstream = "backend upstream returned: " +) diff --git a/internal/config/backend/doc.go b/internal/config/backend/doc.go new file mode 100644 index 000000000..721ad1781 --- /dev/null +++ b/internal/config/backend/doc.go @@ -0,0 +1,13 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +// Package backend defines constants for the internal AI backend +// registry. +// +// These constants keep registry names, error fragments, and future +// configuration keys out of implementation packages. The package has no +// behavior and exists only as the canonical constants home. +package backend diff --git a/internal/config/claude/claude.go b/internal/config/claude/claude.go index 0a82f8058..efbfbf331 100644 --- a/internal/config/claude/claude.go +++ b/internal/config/claude/claude.go @@ -38,16 +38,6 @@ const ( const ( // ModelOpus is the substring identifying Opus models (always 1M). ModelOpus = "opus" - // ModelFable is the substring identifying Fable models - // (Claude 5 family, Mythos-class; always 1M). - ModelFable = "fable" - // ModelMythos is the substring identifying Mythos models - // (same underlying model as Fable; always 1M). - ModelMythos = "mythos" - // ModelSonnet5 is the substring identifying Sonnet 5+ models, - // which carry a 1M window as standard (earlier Sonnets gate 1M - // behind the [1m] opt-in, covered by ModelSuffix1M). - ModelSonnet5 = "sonnet-5" ) // Context window sizes. diff --git a/internal/config/claude/doc.go b/internal/config/claude/doc.go index 310342e1d..7de4efa5f 100644 --- a/internal/config/claude/doc.go +++ b/internal/config/claude/doc.go @@ -22,10 +22,6 @@ // context window. // - [ModelOpus] detects Opus-family models, which // always have 1M context. -// - [ModelFable] and [ModelMythos] detect the Claude 5 -// Mythos-class families, which always have 1M context. -// - [ModelSonnet5] detects Sonnet 5+, which carries a 1M -// window as standard. // - [ContextWindow1M] is the numeric window size used // for budget calculations. // diff --git a/internal/config/claude/integ.go b/internal/config/claude/integ.go index 35b91a77d..cc5588b41 100644 --- a/internal/config/claude/integ.go +++ b/internal/config/claude/integ.go @@ -21,19 +21,6 @@ const ( // SettingsGolden is the golden image of the Claude Code settings. SettingsGolden = ".claude/settings.golden.json" - // FieldPermissions is the settings.local.json key for permissions. - FieldPermissions = "permissions" - // FieldStatusLine is the settings.local.json key for the status line. - FieldStatusLine = "statusLine" - - // StatusLineType is the statusLine entry type for executable commands. - StatusLineType = "command" - // StatusLineCommand is the command ctx deploys as the status line. - StatusLineCommand = "ctx system statusline" - // PreviousStatusLine is the backup file (under .context/state/) holding - // a pre-existing statusLine entry displaced by ctx init. - PreviousStatusLine = "previous-statusline.json" - // GlobalSettings is the Claude Code global settings file. // Located at ~/.claude/settings.json (not the project-local one). GlobalSettings = "settings.json" diff --git a/internal/config/embed/cmd/base.go b/internal/config/embed/cmd/base.go index f383d7c58..99818efd3 100644 --- a/internal/config/embed/cmd/base.go +++ b/internal/config/embed/cmd/base.go @@ -10,6 +10,8 @@ package cmd const ( // UseAgent is the cobra Use string for the agent command. UseAgent = "agent" + // UseAI is the cobra Use string for the ai command. + UseAI = "ai" // UseChange is the cobra Use string for the change command. UseChange = "change" // UseCompact is the cobra Use string for the compact command. @@ -64,12 +66,22 @@ const ( UseWatch = "watch" // UseWhy is the cobra Use string for the why command. UseWhy = "why [DOCUMENT]" + // UseAIPing is the cobra Use string for the ai ping command. + UseAIPing = "ping" + // UseAIPropose is the cobra Use string for the ai propose command. + UseAIPropose = "propose " ) // DescKeys for base commands. const ( // DescKeyAgent is the description key for the agent command. DescKeyAgent = "agent" + // DescKeyAI is the description key for the ai command. + DescKeyAI = "ai" + // DescKeyAIPing is the description key for the ai ping command. + DescKeyAIPing = "ai.ping" + // DescKeyAIPropose is the description key for the ai propose command. + DescKeyAIPropose = "ai.propose" // DescKeyChange is the description key for the change command. DescKeyChange = "change" // DescKeyCompact is the description key for the compact command. diff --git a/internal/config/embed/cmd/system.go b/internal/config/embed/cmd/system.go index 10933bc81..a023e4ef2 100644 --- a/internal/config/embed/cmd/system.go +++ b/internal/config/embed/cmd/system.go @@ -91,9 +91,6 @@ const ( // UseSystemSpecsNudge is the cobra Use string for the system specs nudge // command. UseSystemSpecsNudge = "specs-nudge" - // UseSystemStatusline is the cobra Use string for the system statusline - // command. - UseSystemStatusline = "statusline" ) // DescKeys for system subcommands. @@ -176,7 +173,4 @@ const ( // DescKeySystemSpecsNudge is the description key for the system specs nudge // command. DescKeySystemSpecsNudge = "system.specsnudge" - // DescKeySystemStatusline is the description key for the system statusline - // command. - DescKeySystemStatusline = "system.statusline" ) diff --git a/internal/config/embed/flag/ai.go b/internal/config/embed/flag/ai.go new file mode 100644 index 000000000..e370fa227 --- /dev/null +++ b/internal/config/embed/flag/ai.go @@ -0,0 +1,15 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package flag + +// DescKeys for ai command flags. +const ( + // DescKeyAIBackend is the description key for ai backend selection. + DescKeyAIBackend = "ai.backend" + // DescKeyAIEmit is the description key for ai propose emit kinds. + DescKeyAIEmit = "ai.emit" +) diff --git a/internal/config/embed/flag/setup.go b/internal/config/embed/flag/setup.go new file mode 100644 index 000000000..ca7cd3d45 --- /dev/null +++ b/internal/config/embed/flag/setup.go @@ -0,0 +1,21 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package flag + +// DescKeys for setup command flags. +const ( + // DescKeySetupBackend is the description key for backend setup mode. + DescKeySetupBackend = "setup.backend" + // DescKeySetupEndpoint is the description key for backend endpoint setup. + DescKeySetupEndpoint = "setup.endpoint" + // DescKeySetupAPIKeyEnv is the description key for backend API key env setup. + DescKeySetupAPIKeyEnv = "setup.api-key-env" + // DescKeySetupModel is the description key for backend default model setup. + DescKeySetupModel = "setup.model" + // DescKeySetupTimeout is the description key for backend timeout setup. + DescKeySetupTimeout = "setup.timeout" +) diff --git a/internal/config/embed/text/initialize.go b/internal/config/embed/text/initialize.go index 8af62656c..a0c579816 100644 --- a/internal/config/embed/text/initialize.go +++ b/internal/config/embed/text/initialize.go @@ -34,18 +34,6 @@ const ( // DescKeyWriteInitFileExistsNoCtx is the text key for write init file exists // no ctx messages. DescKeyWriteInitFileExistsNoCtx = "write.init-file-exists-no-ctx" - // DescKeyWriteInitStatuslineDeployed is the text key for write init - // statusline deployed messages. - DescKeyWriteInitStatuslineDeployed = "write.init-statusline-deployed" - // DescKeyWriteInitStatuslineBackedUp is the text key for write init - // statusline backed up messages. - DescKeyWriteInitStatuslineBackedUp = "write.init-statusline-backed-up" - // DescKeyWriteInitStatuslineRestored is the text key for write init - // statusline restored messages. - DescKeyWriteInitStatuslineRestored = "write.init-statusline-restored" - // DescKeyWriteInitStatuslineRemoved is the text key for write init - // statusline removed messages. - DescKeyWriteInitStatuslineRemoved = "write.init-statusline-removed" ) // DescKeys for init gitignore output. @@ -275,9 +263,6 @@ const ( // DescKeyInitLabelPermissions is the text key for init label permissions // messages. DescKeyInitLabelPermissions = "init.label-permissions" - // DescKeyInitLabelStatusline is the text key for init label statusline - // messages. - DescKeyInitLabelStatusline = "init.label-statusline" // DescKeyInitLabelPluginEnable is the text key for init label plugin enable // messages. DescKeyInitLabelPluginEnable = "init.label-plugin-enable" diff --git a/internal/config/env/env.go b/internal/config/env/env.go index b19ccc391..a46d096ed 100644 --- a/internal/config/env/env.go +++ b/internal/config/env/env.go @@ -12,8 +12,6 @@ package env const ( // Home is the environment variable for the user's home directory. Home = "HOME" - // User is the environment variable for the current username. - User = "USER" // CtxTokenBudget is the environment variable for overriding // the token budget. //nolint:gosec // G101: env var name, not a credential diff --git a/internal/config/flag/flag.go b/internal/config/flag/flag.go index d5f0b0228..942616e1f 100644 --- a/internal/config/flag/flag.go +++ b/internal/config/flag/flag.go @@ -12,6 +12,8 @@ const PrefixLong = "--" // Add command flag names: used for both flag registration and error display. const ( Application = "application" + APIKeyEnv = "api-key-env" + Backend = "backend" Branch = "branch" Commit = "commit" Consequence = "consequence" @@ -64,6 +66,8 @@ const ( Days = "days" Dir = "dir" DryRun = "dry-run" + Endpoint = "endpoint" + Emit = "emit" Event = "event" IncludeHub = "include-hub" @@ -87,6 +91,7 @@ const ( Note = "note" Message = "message" Minimal = "minimal" + Model = "model" NoPluginEnable = "no-plugin-enable" NoSteeringInit = "no-steering-init" Out = "out" @@ -109,6 +114,7 @@ const ( Skills = "skills" Tag = "tag" Tool = "tool" + Timeout = "timeout" Token = "token" Type = "type" Variant = "variant" diff --git a/internal/config/opencode/doc.go b/internal/config/opencode/doc.go new file mode 100644 index 000000000..e3600fdd2 --- /dev/null +++ b/internal/config/opencode/doc.go @@ -0,0 +1,11 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +// Package opencode defines shared constants for OpenCode config integration. +// It keeps provider keys and IDs centralized for setup-time config writes. +// This avoids duplicating OpenCode-specific strings across CLI setup code. +// It also gives setup and tests one canonical source of provider metadata. +package opencode diff --git a/internal/config/opencode/opencode.go b/internal/config/opencode/opencode.go new file mode 100644 index 000000000..66dfee046 --- /dev/null +++ b/internal/config/opencode/opencode.go @@ -0,0 +1,25 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package opencode + +// OpenCode config keys and provider identifiers. +const ( + // KeyProvider is the top-level provider map key. + KeyProvider = "provider" + // KeyBaseURL is the provider option storing the backend endpoint. + KeyBaseURL = "baseURL" + // KeyNPM is the optional custom provider package key. + KeyNPM = "npm" + // KeyOptions is the provider options object key. + KeyOptions = "options" + // ProviderIDAnthropic is the built-in Anthropic provider ID. + ProviderIDAnthropic = "anthropic" + // ProviderIDOpenAI is the built-in OpenAI provider ID. + ProviderIDOpenAI = "openai" + // ProviderNPMOpenAICompatible is the package for OpenAI-compatible providers. + ProviderNPMOpenAICompatible = "@ai-sdk/openai-compatible" +) diff --git a/internal/config/rc/rc.go b/internal/config/rc/rc.go index 630ced9cf..8c3ff332a 100644 --- a/internal/config/rc/rc.go +++ b/internal/config/rc/rc.go @@ -14,4 +14,32 @@ const ( // fmt.Errorf(FmtWrapColon, ErrFoo, "tailored detail") // ↦ ": tailored detail". FmtWrapColon = "%w: %s" + + // ErrBackendsMapping reports a non-mapping backends value. + ErrBackendsMapping = "backends must be a mapping" + // ErrBackendsDefaultScalar reports a non-scalar default backend value. + ErrBackendsDefaultScalar = "backends.default must be a scalar" + // ErrBackendsDefaultMissing reports a default backend with no definition. + ErrBackendsDefaultMissing = "backends.default references missing backend: " + // ErrBackendsEndpointRequired reports a backend missing its endpoint. + ErrBackendsEndpointRequired = "backends.%s.endpoint is required" + // ErrBackendsEndpointScheme reports a backend endpoint with invalid scheme. + ErrBackendsEndpointScheme = "backends.%s.endpoint must be http or https" + // ErrBackendsUnknownField reports an unknown key under a named backend. + ErrBackendsUnknownField = "backends.%s.%s" + + // BackendDefaultKey is the reserved key for default backend selection. + BackendDefaultKey = "default" + // BackendsKey is the top-level backend configuration key. + BackendsKey = "backends" + // BackendTypeKey is the backend implementation type key. + BackendTypeKey = "type" + // BackendEndpointKey is the endpoint URL key. + BackendEndpointKey = "endpoint" + // BackendAPIKeyEnvKey is the credential environment variable key. + BackendAPIKeyEnvKey = "api_key_env" + // BackendTimeoutKey is the request timeout key. + BackendTimeoutKey = "timeout" + // BackendDefaultModelKey is the default model key. + BackendDefaultModelKey = "default_model" ) diff --git a/internal/config/setup/setup.go b/internal/config/setup/setup.go index ee20e51b9..aaa104c0c 100644 --- a/internal/config/setup/setup.go +++ b/internal/config/setup/setup.go @@ -6,6 +6,26 @@ package setup +import "github.com/ActiveMemory/ctx/internal/config/token" + +// Root setup file paths. +const ( + // FileCtxRC is the project rc file name. + FileCtxRC = ".ctxrc" +) + +// Backend setup output strings. +const ( + BackendDryRunPrefix = "Add this backend configuration to .ctxrc:\n" + BackendEndpointRequired = "%s endpoint is required" + BackendEndpointScheme = "%s endpoint must be http or https" + BackendEnvWarn = "warning: environment variable already set: " + BackendEnvWarnEnd = token.NewlineLF + BackendRCMapping = ".ctxrc must be a mapping" + BackendUnsupported = "unsupported backend: " + BackendWriteDone = "Updated .ctxrc backend configuration\n" +) + // Display names for supported integration tools. const ( // DisplayKiro is the display name for Kiro. diff --git a/internal/config/statusline/doc.go b/internal/config/statusline/doc.go deleted file mode 100644 index 35b596c07..000000000 --- a/internal/config/statusline/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// / ctx: https://ctx.ist -// ,'`./ do you remember? -// `.,'\ -// \ Copyright 2026-present Context contributors. -// SPDX-License-Identifier: Apache-2.0 - -// Package statusline holds display constants for the -// "ctx system statusline" renderer (specs/statusline.md). -// -// The status line is informational only: it renders model, context -// usage, and session cost from the payload Claude Code provides. -// There is deliberately no cost gating and no model-switch nudging; -// the spec's Decisions section records why. -// -// Constants are grouped as rendering limits (segment/line/path -// bounds), segment formats and separators, path display tokens, and -// the printable-ASCII sanitization range. -package statusline diff --git a/internal/config/statusline/statusline.go b/internal/config/statusline/statusline.go deleted file mode 100644 index ecee74076..000000000 --- a/internal/config/statusline/statusline.go +++ /dev/null @@ -1,89 +0,0 @@ -// / ctx: https://ctx.ist -// ,'`./ do you remember? -// `.,'\ -// \ Copyright 2026-present Context contributors. -// SPDX-License-Identifier: Apache-2.0 - -package statusline - -// Rendering limits. -const ( - // MaxSegmentLen bounds each rendered segment so a hostile or - // degenerate payload field cannot flood the status line. - MaxSegmentLen = 80 - - // MaxLineLen bounds the full rendered line. Claude Code displays - // a single line; anything longer is terminal noise. - MaxLineLen = 200 - - // MaxDirLen bounds the directory portion of the location segment; - // longer paths collapse to TruncatedDirPrefix + base. - MaxDirLen = 32 - - // MaxPayloadBytes bounds how much stdin is read; the status line - // payload is a few kilobytes, so anything near this limit is - // garbage. - MaxPayloadBytes = 1 << 20 -) - -// Segment formats and separators. -const ( - // SegmentCapacity is the number of segments a full line renders - // (location, model, context usage, cost). - SegmentCapacity = 4 - - // PercentMax is the upper bound of a plausible context-usage - // percentage; payload values outside [0, PercentMax] are dropped. - PercentMax = 100 - - // SegmentSeparator joins the rendered segments. - SegmentSeparator = " | " - - // ContextFormat renders the context-usage percentage segment. - ContextFormat = "ctx: %.0f%%" - - // CostFormat renders the session-cost segment as a plain dollar - // figure. Informational only: there is deliberately no - // gating or model-switch nudging attached to it. - CostFormat = "$%.2f" - - // UserHostSeparator joins username and hostname. - UserHostSeparator = "@" -) - -// Path display tokens. -const ( - // HostDomainSeparator splits a fully-qualified hostname; only the - // short name is rendered at status-line widths. - HostDomainSeparator = "." - - // RelSelf is filepath.Rel's answer when the path is the home - // directory itself. - RelSelf = "." - - // RelParentPrefix marks a filepath.Rel result that escapes the - // home directory (no home abbreviation applies). - RelParentPrefix = ".." - - // HomeAbbrev is the home-directory abbreviation. - HomeAbbrev = "~" - - // HomeAbbrevPrefix prefixes paths under the home directory. - HomeAbbrevPrefix = "~/" - - // TruncatedDirPrefix replaces overlong directory paths ahead of - // the final path element. - TruncatedDirPrefix = ".../" -) - -// Bounds of the byte range kept by output sanitization: printable -// ASCII only, per the behavior contract in specs/statusline.md. -// Control bytes, ANSI escapes, and multi-byte runes are stripped so -// payload content cannot corrupt the terminal. -const ( - // ASCIIPrintableMin is the lowest byte kept. - ASCIIPrintableMin = 0x20 - - // ASCIIPrintableMax is the highest byte kept. - ASCIIPrintableMax = 0x7E -) diff --git a/internal/err/ai/ai.go b/internal/err/ai/ai.go new file mode 100644 index 000000000..8acc83d4d --- /dev/null +++ b/internal/err/ai/ai.go @@ -0,0 +1,37 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\\ +// \\ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package ai + +import ( + "errors" + + cfgAI "github.com/ActiveMemory/ctx/internal/config/ai" +) + +// EmitRequired reports that ctx ai propose requires a non-empty --emit value. +// +// Returns: +// - error: "emit is required" +func EmitRequired() error { + return errors.New(cfgAI.ErrEmitRequired) +} + +// InvalidArtifact reports that a proposal artifact is structurally invalid. +// +// Returns: +// - error: "invalid proposal artifact" +func InvalidArtifact() error { + return errors.New(cfgAI.ErrInvalidArtifact) +} + +// InvalidArtifactResponse reports that a proposal response payload is invalid. +// +// Returns: +// - error: "invalid proposal artifact response" +func InvalidArtifactResponse() error { + return errors.New(cfgAI.ErrInvalidArtifactResponse) +} diff --git a/internal/err/ai/doc.go b/internal/err/ai/doc.go new file mode 100644 index 000000000..cd06653c0 --- /dev/null +++ b/internal/err/ai/doc.go @@ -0,0 +1,12 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +// Package ai provides constructors for ctx ai command errors. +// +// It centralizes proposal validation failures so command code can reuse +// them and satisfy repository audit rules without naked errors. +// The package is intentionally narrow and only covers ctx ai surfaces. +package ai diff --git a/internal/err/backend/backend.go b/internal/err/backend/backend.go new file mode 100644 index 000000000..9025812c4 --- /dev/null +++ b/internal/err/backend/backend.go @@ -0,0 +1,203 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package backend + +import "fmt" + +import cfgBackend "github.com/ActiveMemory/ctx/internal/config/backend" + +// DuplicateRegistration reports a duplicate backend registration. +// +// Fields: +// - Name: duplicate backend name +type DuplicateRegistration struct { + Name string +} + +// Error formats the duplicate registration error. +// +// Returns: +// - string: formatted duplicate registration message +func (err DuplicateRegistration) Error() string { + return cfgBackend.ErrDuplicateRegistration + err.Name +} + +// MissingBackend reports a requested backend that is not registered. +// +// Fields: +// - Name: missing backend name +type MissingBackend struct { + Name string +} + +// Error formats the missing backend error. +// +// Returns: +// - string: formatted missing backend message +func (err MissingBackend) Error() string { + return cfgBackend.ErrMissingBackend + err.Name +} + +// MultipleBackends reports an ambiguous default backend selection. +type MultipleBackends struct{} + +// Error formats the multiple backends error. +// +// Returns: +// - string: formatted multiple backends message +func (err MultipleBackends) Error() string { + return cfgBackend.ErrMultipleBackends +} + +// NoBackendConfigured reports that the registry is empty. +type NoBackendConfigured struct{} + +// Error formats the empty registry error. +// +// Returns: +// - string: formatted empty registry message +func (err NoBackendConfigured) Error() string { + return cfgBackend.ErrNoBackendConfigured +} + +// Factory reports a backend factory failure. +// +// Fields: +// - Name: backend name whose factory failed +// - Cause: underlying factory error +type Factory struct { + Name string + Cause error +} + +// Error formats the factory failure. +// +// Returns: +// - string: formatted factory failure message +func (err Factory) Error() string { + return cfgBackend.ErrFactory + err.Name +} + +// Unwrap returns the underlying factory error. +// +// Returns: +// - error: underlying factory error +func (err Factory) Unwrap() error { + return err.Cause +} + +// InvalidEndpoint reports an endpoint URL that cannot be used. +// +// Fields: +// - Endpoint: configured endpoint value +// - Cause: underlying parse or request construction failure +type InvalidEndpoint struct { + Endpoint string + Cause error +} + +// Error formats the invalid endpoint error. +// +// Returns: +// - string: formatted invalid endpoint message +func (err InvalidEndpoint) Error() string { + return cfgBackend.ErrInvalidEndpoint + err.Endpoint +} + +// Unwrap returns the underlying endpoint error. +// +// Returns: +// - error: underlying endpoint error +func (err InvalidEndpoint) Unwrap() error { + return err.Cause +} + +// Unreachable reports a failed backend HTTP request. +// +// Fields: +// - Name: backend name +// - Endpoint: configured endpoint value +// - Cause: underlying HTTP error +type Unreachable struct { + Name string + Endpoint string + Cause error +} + +// Error formats the unreachable backend error. +// +// Returns: +// - string: formatted unreachable backend message +func (err Unreachable) Error() string { + return cfgBackend.ErrUnreachable + err.Name +} + +// Unwrap returns the underlying HTTP error. +// +// Returns: +// - error: underlying HTTP error +func (err Unreachable) Unwrap() error { + return err.Cause +} + +// Upstream reports a non-success status from the backend. +// +// Fields: +// - Name: backend name +// - StatusCode: upstream HTTP status code +// - Body: upstream response body +type Upstream struct { + Name string + StatusCode int + Body string +} + +// Error formats the upstream status error. +// +// Returns: +// - string: formatted upstream response message +func (err Upstream) Error() string { + return cfgBackend.ErrUpstream + fmt.Sprintf( + cfgBackend.FmtUpstreamStatusBody, + err.StatusCode, + err.Body, + ) +} + +// BadRequest wraps a local request encoding or decode failure. +// +// Fields: +// - Name: backend name +// - Cause: underlying request error +type BadRequest struct { + Name string + Cause error +} + +// Error formats the backend request failure. +// +// Returns: +// - string: formatted request failure message +func (err BadRequest) Error() string { + return cfgBackend.ErrBadRequest + err.Name +} + +// Unwrap returns the underlying request failure. +// +// Returns: +// - error: underlying request failure +func (err BadRequest) Unwrap() error { + return err.Cause +} + +// InvalidResponseShape reports a structurally incomplete provider response. +// +// Returns: +// - error: "invalid structured response shape" +func InvalidResponseShape() error { + return fmt.Errorf(cfgBackend.ErrInvalidResponseShape) +} diff --git a/internal/err/backend/doc.go b/internal/err/backend/doc.go new file mode 100644 index 000000000..57998e840 --- /dev/null +++ b/internal/err/backend/doc.go @@ -0,0 +1,13 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +// Package backend provides typed errors for AI backend registry +// failures. +// +// Callers can match these errors with errors.As while still receiving +// stable user-facing messages from the config layer. The package avoids +// sentinel strings in backend implementation code. +package backend diff --git a/internal/err/rc/doc.go b/internal/err/rc/doc.go new file mode 100644 index 000000000..57a372a73 --- /dev/null +++ b/internal/err/rc/doc.go @@ -0,0 +1,12 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +// Package rc provides constructors for .ctxrc validation errors. +// +// It centralizes rc validation formatting so loader and validator code can +// satisfy repository audit rules without naked errors. +// The package is intentionally narrow and only covers rc-specific surfaces. +package rc diff --git a/internal/err/rc/rc.go b/internal/err/rc/rc.go new file mode 100644 index 000000000..aa8ec7f24 --- /dev/null +++ b/internal/err/rc/rc.go @@ -0,0 +1,23 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\\ +// \\ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package rc + +import "fmt" + +import cfgRC "github.com/ActiveMemory/ctx/internal/config/rc" + +// InvalidBackendEndpointScheme reports a backend endpoint with a non-http(s) +// scheme. +// +// Parameters: +// - name: backend name under backends.* +// +// Returns: +// - error: invalid endpoint scheme message for that backend +func InvalidBackendEndpointScheme(name string) error { + return fmt.Errorf(cfgRC.ErrBackendsEndpointScheme, name) +} diff --git a/internal/err/setup/setup.go b/internal/err/setup/setup.go index d0299709f..563fcdadf 100644 --- a/internal/err/setup/setup.go +++ b/internal/err/setup/setup.go @@ -11,6 +11,8 @@ import ( "github.com/ActiveMemory/ctx/internal/assets/read/desc" "github.com/ActiveMemory/ctx/internal/config/embed/text" + cfgSetup "github.com/ActiveMemory/ctx/internal/config/setup" + "github.com/ActiveMemory/ctx/internal/config/token" ) // CreateDir wraps a failure to create a setup directory. @@ -82,3 +84,44 @@ func MissingEmbeddedAsset(name string) error { desc.Text(text.DescKeyErrSetupMissingEmbeddedAsset), name, ) } + +// UnsupportedBackend reports an unrecognized backend setup name. +// +// Parameters: +// - name: backend name passed to --backend +// +// Returns: +// - error: unsupported backend message +func UnsupportedBackend(name string) error { + return fmt.Errorf(cfgSetup.BackendUnsupported+token.FormatString, name) +} + +// BackendRCMapping reports that .ctxrc must decode to a root mapping. +// +// Returns: +// - error: ".ctxrc must be a mapping" +func BackendRCMapping() error { + return fmt.Errorf(cfgSetup.BackendRCMapping) +} + +// BackendEndpointRequired reports that setup needs an explicit endpoint. +// +// Parameters: +// - name: backend name passed to --backend +// +// Returns: +// - error: missing endpoint message for that backend +func BackendEndpointRequired(name string) error { + return fmt.Errorf(cfgSetup.BackendEndpointRequired, name) +} + +// BackendEndpointScheme reports that setup received a non-http(s) endpoint. +// +// Parameters: +// - name: backend name passed to --backend +// +// Returns: +// - error: invalid endpoint scheme message for that backend +func BackendEndpointScheme(name string) error { + return fmt.Errorf(cfgSetup.BackendEndpointScheme, name) +} diff --git a/internal/rc/load.go b/internal/rc/load.go index e57a0e6d0..7737ec0e0 100644 --- a/internal/rc/load.go +++ b/internal/rc/load.go @@ -48,8 +48,10 @@ func load() *CtxRC { case pathErr == nil: data, readErr := ctxIo.SafeReadUserFile(rcPath) if readErr == nil { - if yamlErr := yaml.Unmarshal(data, cfg); yamlErr != nil { + if _, yamlErr := Validate(data); yamlErr != nil { writeRC.ParseWarning(rcPath, yamlErr) + } else if decodeErr := yaml.Unmarshal(data, cfg); decodeErr != nil { + writeRC.ParseWarning(rcPath, decodeErr) } } case errors.Is(pathErr, errCtx.ErrNoCtxHere): diff --git a/internal/rc/rc.go b/internal/rc/rc.go index 3c9522aad..1f66fb0c9 100644 --- a/internal/rc/rc.go +++ b/internal/rc/rc.go @@ -587,40 +587,6 @@ func HooksEnabled() bool { return true } -// StatuslineEnabled returns whether the ctx status line is enabled. -// -// Returns true (default) when the statusline section is not configured -// or when the enabled field is not explicitly set. Returns false only -// when statusline.enabled is explicitly set to false in .ctxrc. -// -// Returns: -// - bool: True if the status line is enabled -func StatuslineEnabled() bool { - cfg := RC() - if cfg.Statusline != nil && cfg.Statusline.Enabled != nil { - return *cfg.Statusline.Enabled - } - return true -} - -// StatuslineShowCost returns whether the status line renders the cost -// segment. -// -// Returns true (default) when the statusline section is not configured -// or when the show_cost field is not explicitly set. Users disable it -// for screen-sharing or recorded demos where an on-screen dollar -// figure is unwanted. -// -// Returns: -// - bool: True if the cost segment should be rendered -func StatuslineShowCost() bool { - cfg := RC() - if cfg.Statusline != nil && cfg.Statusline.ShowCost != nil { - return *cfg.Statusline.ShowCost - } - return true -} - // Reset clears the cached configuration, forcing // reload on the next access. func Reset() { diff --git a/internal/rc/types.go b/internal/rc/types.go index 47af54682..ff3dc9d77 100644 --- a/internal/rc/types.go +++ b/internal/rc/types.go @@ -6,7 +6,14 @@ package rc -import cfgMemory "github.com/ActiveMemory/ctx/internal/config/memory" +import ( + "fmt" + + "gopkg.in/yaml.v3" + + cfgMemory "github.com/ActiveMemory/ctx/internal/config/memory" + cfgRC "github.com/ActiveMemory/ctx/internal/config/rc" +) // CtxRC represents the configuration from the .ctxrc file. // @@ -62,6 +69,7 @@ import cfgMemory "github.com/ActiveMemory/ctx/internal/config/memory" // English list to keep applying. // - Tool: Active AI tool identifier (e.g., claude, // cursor, cline, kiro, codex) +// - Backends: Optional AI backend definitions for ctx ai commands // - Steering: Steering layer configuration overrides // - Hooks: Hook system configuration overrides // - ProvenanceRequired: Per-project relaxation of @@ -93,29 +101,94 @@ type CtxRC struct { SpecNudgeMinLen int `yaml:"spec_nudge_min_len"` Placeholders []string `yaml:"placeholders"` Notify *NotifyConfig `yaml:"notify"` + Backends BackendsRC `yaml:"backends"` Steering *SteeringRC `yaml:"steering"` Hooks *HooksRC `yaml:"hooks"` - Statusline *StatuslineRC `yaml:"statusline"` ProvenanceRequired *ProvenanceConfig `yaml:"provenance_required"` Dream *DreamRC `yaml:"dream"` } -// StatuslineRC holds status line configuration from .ctxrc. +// BackendsRC holds optional AI backend configuration from .ctxrc. +// +// Fields: +// - Default: optional backend selected when a ctx ai command does not pass +// --backend +// - Configs: named backend definitions keyed by backend name +type BackendsRC struct { + Default string `yaml:"default"` + Configs map[string]BackendRC `yaml:",inline"` +} + +// UnmarshalYAML decodes the mixed backends mapping shape. +// +// Parameters: +// - value: YAML node for the backends value // -// The status line is informational only: it renders model, context -// usage, and session cost from the payload Claude Code provides. -// There is deliberately no cost gating or model-switch nudging -// (see specs/statusline.md, Decisions). +// Returns: +// - error: decode failure, or nil when valid YAML shape was decoded +func (backends *BackendsRC) UnmarshalYAML(value *yaml.Node) error { + if value.Kind != yaml.MappingNode { + return &yaml.TypeError{Errors: []string{cfgRC.ErrBackendsMapping}} + } + + backends.Configs = make(map[string]BackendRC) + for idx := 0; idx < len(value.Content); idx += 2 { + key := value.Content[idx] + val := value.Content[idx+1] + if key.Value == cfgRC.BackendDefaultKey { + if val.Kind != yaml.ScalarNode { + return &yaml.TypeError{Errors: []string{cfgRC.ErrBackendsDefaultScalar}} + } + backends.Default = val.Value + continue + } + + if val.Kind != yaml.MappingNode { + return &yaml.TypeError{Errors: []string{cfgRC.ErrBackendsMapping}} + } + + backend := BackendRC{} + for backendIdx := 0; backendIdx < len(val.Content); backendIdx += 2 { + backendKey := val.Content[backendIdx].Value + backendVal := val.Content[backendIdx+1].Value + switch backendKey { + case cfgRC.BackendTypeKey: + backend.Type = backendVal + case cfgRC.BackendEndpointKey: + backend.Endpoint = backendVal + case cfgRC.BackendAPIKeyEnvKey: + backend.APIKeyEnv = backendVal + case cfgRC.BackendTimeoutKey: + backend.Timeout = backendVal + case cfgRC.BackendDefaultModelKey: + backend.DefaultModel = backendVal + default: + return &yaml.TypeError{Errors: []string{ + fmt.Sprintf(cfgRC.ErrBackendsUnknownField, key.Value, backendKey), + }} + } + } + backends.Configs[key.Value] = backend + } + + return nil +} + +// BackendRC holds one named AI backend definition from .ctxrc. // // Fields: -// - Enabled: Whether ctx init deploys (and keeps) the statusLine -// entry in .claude/settings.local.json (default true). Pointer -// type distinguishes unset (nil → true) from explicit false. -// - ShowCost: Whether the $ segment is rendered (default true). -// Disable for screen-sharing or recorded demos. -type StatuslineRC struct { - Enabled *bool `yaml:"enabled"` - ShowCost *bool `yaml:"show_cost"` +// - Type: optional registered implementation type when it differs from the +// backend name +// - Endpoint: OpenAI-compatible HTTP endpoint URL +// - APIKeyEnv: optional environment variable name containing credentials +// - Timeout: optional request timeout duration string +// - DefaultModel: optional model selected by default for this backend +type BackendRC struct { + Type string `yaml:"type"` + Endpoint string `yaml:"endpoint"` + APIKeyEnv string `yaml:"api_key_env"` + Timeout string `yaml:"timeout"` + DefaultModel string `yaml:"default_model"` } // DreamRC holds the ctx-dream configuration from .ctxrc. The dream is diff --git a/internal/rc/validate.go b/internal/rc/validate.go index cf1096abb..ea575f2bc 100644 --- a/internal/rc/validate.go +++ b/internal/rc/validate.go @@ -12,12 +12,16 @@ import ( "io" "gopkg.in/yaml.v3" + + errCtx "github.com/ActiveMemory/ctx/internal/err/context" + ctxIo "github.com/ActiveMemory/ctx/internal/io" ) // Validate performs strict YAML decoding of .ctxrc content. // // Unknown fields are returned as warnings (not errors) so callers can -// distinguish typos from genuinely broken YAML. +// distinguish typos from genuinely broken YAML. Backend configuration is +// stricter: malformed `backends:` keys fail validation. // // Parameters: // - data: Raw YAML content from a .ctxrc file @@ -38,6 +42,9 @@ func Validate(data []byte) (warnings []string, err error) { // yaml.v3 returns *yaml.TypeError for unknown fields. if te, ok := errors.AsType[*yaml.TypeError](decErr); ok { + if backendsShapeError(te.Errors) { + return nil, decErr + } return te.Errors, nil } @@ -45,5 +52,31 @@ func Validate(data []byte) (warnings []string, err error) { return nil, decErr } + if cfgErr := cfg.validateBackends(); cfgErr != nil { + return nil, cfgErr + } + return nil, nil } + +// ValidateCurrent validates the cwd-anchored `.ctxrc` file, when one is +// available. +// +// Returns: +// - error: validation failure for the current `.ctxrc`; nil when the file is +// absent, unreadable, or valid. +func ValidateCurrent() error { + rcPath, pathErr := ctxrcPath() + if pathErr != nil { + if errors.Is(pathErr, errCtx.ErrNoCtxHere) { + return nil + } + return nil + } + data, readErr := ctxIo.SafeReadUserFile(rcPath) + if readErr != nil { + return nil + } + _, validateErr := Validate(data) + return validateErr +} diff --git a/internal/rc/validate_internal.go b/internal/rc/validate_internal.go new file mode 100644 index 000000000..104943c28 --- /dev/null +++ b/internal/rc/validate_internal.go @@ -0,0 +1,74 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package rc + +import ( + "fmt" + "net/url" + "strings" + + "gopkg.in/yaml.v3" + + cfgHTTP "github.com/ActiveMemory/ctx/internal/config/http" + cfgRC "github.com/ActiveMemory/ctx/internal/config/rc" + "github.com/ActiveMemory/ctx/internal/config/token" + errRC "github.com/ActiveMemory/ctx/internal/err/rc" +) + +// validateBackends checks semantic requirements for .ctxrc backends. +// +// Returns: +// - error: validation failure, or nil when configuration is valid +func (cfg CtxRC) validateBackends() error { + backends := cfg.Backends + if len(backends.Configs) == 0 { + return nil + } + + if backends.Default != "" { + if _, ok := backends.Configs[backends.Default]; !ok { + return &yaml.TypeError{Errors: []string{ + cfgRC.ErrBackendsDefaultMissing + backends.Default, + }} + } + } + + for name, backend := range backends.Configs { + if backend.Endpoint == "" { + return &yaml.TypeError{Errors: []string{ + fmt.Sprintf(cfgRC.ErrBackendsEndpointRequired, name), + }} + } + parsed, parseErr := url.Parse(backend.Endpoint) + if parseErr != nil || + (parsed.Scheme != cfgHTTP.SchemeHTTP && + parsed.Scheme != cfgHTTP.SchemeHTTPS) { + return errRC.InvalidBackendEndpointScheme(name) + } + } + + return nil +} + +// backendsShapeError reports whether type errors are malformed backends shape. +// +// Parameters: +// - errs: YAML type error strings +// +// Returns: +// - bool: true when the error should fail validation, not warn +func backendsShapeError(errs []string) bool { + for _, msg := range errs { + if strings.Contains(msg, cfgRC.ErrBackendsMapping) || + strings.Contains(msg, cfgRC.ErrBackendsDefaultScalar) || + strings.HasPrefix(msg, cfgRC.BackendsKey+token.Dot) { + return true + } + } + + return false +} diff --git a/internal/rc/validate_test.go b/internal/rc/validate_test.go index 748c32006..0ac4bdaa5 100644 --- a/internal/rc/validate_test.go +++ b/internal/rc/validate_test.go @@ -110,3 +110,115 @@ notify: t.Errorf("expected no warnings for full valid config, got %v", warnings) } } + +func TestValidate_BackendsWellFormed(t *testing.T) { + data := []byte(`backends: + default: vllm + vllm: + type: openai-compatible + endpoint: http://localhost:8000 + api_key_env: "" + timeout: 30s + default_model: openai/gpt-oss-120b +`) + warnings, err := Validate(data) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(warnings) != 0 { + t.Errorf("expected no warnings, got %v", warnings) + } +} + +func TestValidate_BackendsMissingEndpoint(t *testing.T) { + data := []byte(`backends: + vllm: + timeout: 30s +`) + _, err := Validate(data) + if err == nil { + t.Fatal("expected error for missing endpoint") + } + if !strings.Contains(err.Error(), "vllm") { + t.Errorf("error should mention backend name, got: %v", err) + } +} + +func TestValidate_BackendsMalformedShape(t *testing.T) { + data := []byte(`backends: + - vllm +`) + _, err := Validate(data) + if err == nil { + t.Fatal("expected error for malformed backends shape") + } +} + +func TestValidate_BackendsDefaultMissing(t *testing.T) { + data := []byte(`backends: + default: openai + vllm: + endpoint: http://localhost:8000 +`) + _, err := Validate(data) + if err == nil { + t.Fatal("expected error for missing default backend") + } + if !strings.Contains(err.Error(), "openai") { + t.Errorf("error should mention missing default, got: %v", err) + } +} + +func TestValidate_BackendsMultipleWithoutDefault(t *testing.T) { + data := []byte(`backends: + vllm: + endpoint: http://localhost:8000 + openai: + endpoint: https://api.openai.com + api_key_env: OPENAI_API_KEY +`) + warnings, err := Validate(data) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(warnings) != 0 { + t.Errorf("expected no warnings, got %v", warnings) + } +} + +func TestValidate_BackendsUnknownNestedField(t *testing.T) { + data := []byte(`backends: + vllm: + endpoint: http://localhost:8000 + api_token: nope +`) + _, err := Validate(data) + if err == nil { + t.Fatal("expected error for unknown backend field") + } + if !strings.Contains(err.Error(), "backends.vllm.api_token") { + t.Errorf("error should mention full backend field path, got: %v", err) + } +} + +func TestValidate_BackendsInvalidEndpointScheme(t *testing.T) { + data := []byte(`backends: + vllm: + endpoint: file:///tmp/socket +`) + _, err := Validate(data) + if err == nil { + t.Fatal("expected error for invalid endpoint scheme") + } +} + +func TestValidate_BackendsEmptyOK(t *testing.T) { + data := []byte("backends: {}\n") + warnings, err := Validate(data) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(warnings) != 0 { + t.Errorf("expected no warnings, got %v", warnings) + } +} diff --git a/internal/write/ai/ai.go b/internal/write/ai/ai.go new file mode 100644 index 000000000..97160e2ae --- /dev/null +++ b/internal/write/ai/ai.go @@ -0,0 +1,40 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +package ai + +import ( + "fmt" + "io" + + cfgAI "github.com/ActiveMemory/ctx/internal/config/ai" +) + +// Ping writes backend ping information. +// +// Parameters: +// - out: destination writer +// - backend: backend name +// - endpoint: configured endpoint +// - firstModel: first model from model listing +// +// Returns: +// - error: write failure +func Ping( + out io.Writer, + backend string, + endpoint string, + firstModel string, +) error { + _, writeErr := fmt.Fprintf( + out, + cfgAI.WritePingFormat, + backend, + endpoint, + firstModel, + ) + return writeErr +} diff --git a/internal/write/ai/doc.go b/internal/write/ai/doc.go new file mode 100644 index 000000000..41e5e2caa --- /dev/null +++ b/internal/write/ai/doc.go @@ -0,0 +1,12 @@ +// / ctx: https://ctx.ist +// ,'`./ do you remember? +// `.,'\ +// \ Copyright 2026-present Context contributors. +// SPDX-License-Identifier: Apache-2.0 + +// Package ai writes ctx ai command output. +// +// It owns stdout formatting for the ai command family. Command packages +// delegate here so they do not print directly. +// The package has no business logic and only formats terminal output. +package ai diff --git a/internal/write/initialize/statusline.go b/internal/write/initialize/statusline.go deleted file mode 100644 index c0155db31..000000000 --- a/internal/write/initialize/statusline.go +++ /dev/null @@ -1,63 +0,0 @@ -// / ctx: https://ctx.ist -// ,'`./ do you remember? -// `.,'\ -// \ Copyright 2026-present Context contributors. -// SPDX-License-Identifier: Apache-2.0 - -package initialize - -import ( - "fmt" - - "github.com/spf13/cobra" - - "github.com/ActiveMemory/ctx/internal/assets/read/desc" - "github.com/ActiveMemory/ctx/internal/config/embed/text" -) - -// StatuslineDeployed reports the ctx status line wired into settings. -// -// Parameters: -// - cmd: Cobra command for output -// - path: settings file path -func StatuslineDeployed(cmd *cobra.Command, path string) { - cmd.Println(fmt.Sprintf( - desc.Text(text.DescKeyWriteInitStatuslineDeployed), path, - )) -} - -// StatuslineBackedUp reports a displaced statusLine entry saved to the -// state directory. -// -// Parameters: -// - cmd: Cobra command for output -// - path: backup file path -func StatuslineBackedUp(cmd *cobra.Command, path string) { - cmd.Println(fmt.Sprintf( - desc.Text(text.DescKeyWriteInitStatuslineBackedUp), path, - )) -} - -// StatuslineRestored reports a backed-up statusLine entry restored -// after statusline.enabled was set to false. -// -// Parameters: -// - cmd: Cobra command for output -// - path: backup file path the entry was restored from -func StatuslineRestored(cmd *cobra.Command, path string) { - cmd.Println(fmt.Sprintf( - desc.Text(text.DescKeyWriteInitStatuslineRestored), path, - )) -} - -// StatuslineRemoved reports the ctx statusLine entry dropped after -// statusline.enabled was set to false with no backup to restore. -// -// Parameters: -// - cmd: Cobra command for output -// - path: settings file path -func StatuslineRemoved(cmd *cobra.Command, path string) { - cmd.Println(fmt.Sprintf( - desc.Text(text.DescKeyWriteInitStatuslineRemoved), path, - )) -} diff --git a/internal/write/statusline/doc.go b/internal/write/statusline/doc.go deleted file mode 100644 index f717cf8f9..000000000 --- a/internal/write/statusline/doc.go +++ /dev/null @@ -1,25 +0,0 @@ -// / ctx: https://ctx.ist -// ,'`./ do you remember? -// `.,'\ -// \ Copyright 2026-present Context contributors. -// SPDX-License-Identifier: Apache-2.0 - -// Package statusline emits the rendered status line for the hidden -// "ctx system statusline" command. -// -// Claude Code displays the first stdout line of the configured -// statusLine command; these primitives are the single place that -// line is written. -// -// # Exported Functions -// -// [Line] prints the assembled status line. -// -// [Blank] prints an empty line, used when statusline.enabled is -// false so the displayed status line goes blank without a non-zero -// exit. -// -// # Message Categories -// -// - Info: the rendered status line -package statusline diff --git a/internal/write/statusline/print.go b/internal/write/statusline/print.go deleted file mode 100644 index c7c934b54..000000000 --- a/internal/write/statusline/print.go +++ /dev/null @@ -1,27 +0,0 @@ -// / ctx: https://ctx.ist -// ,'`./ do you remember? -// `.,'\ -// \ Copyright 2026-present Context contributors. -// SPDX-License-Identifier: Apache-2.0 - -package statusline - -import "github.com/spf13/cobra" - -// Line prints the assembled status line to the command's output. -// -// Parameters: -// - cmd: Cobra command for output -// - line: rendered status line -func Line(cmd *cobra.Command, line string) { - cmd.Println(line) -} - -// Blank prints an empty status line, blanking the display when the -// status line is disabled in .ctxrc. -// -// Parameters: -// - cmd: Cobra command for output -func Blank(cmd *cobra.Command) { - cmd.Println() -} diff --git a/site/404.html b/site/404.html index 119c74a4f..b73109882 100644 --- a/site/404.html +++ b/site/404.html @@ -19,7 +19,7 @@ - + @@ -30,7 +30,7 @@ - + @@ -56,7 +56,7 @@ - + @@ -225,15 +225,6 @@ - - - - - - - - -
  • @@ -253,27 +244,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -293,29 +263,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -335,29 +282,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -377,29 +301,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -418,23 +319,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -454,23 +338,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -551,7 +418,8 @@ - Manifesto + Manifesto + @@ -579,7 +447,8 @@ - The Thesis + The Thesis + @@ -631,7 +500,8 @@ - Blog + Blog + @@ -701,7 +571,8 @@ - Home + Home + @@ -773,7 +644,8 @@ - Recipes + Recipes + @@ -845,7 +717,8 @@ - CLI + CLI + @@ -917,7 +790,8 @@ - Reference + Reference + @@ -983,7 +857,8 @@ - Operations + Operations + @@ -1049,7 +924,8 @@ - Security + Security + @@ -1201,10 +1077,10 @@

    404 - Not found

    - + - + diff --git a/site/assets/javascripts/bundle.63456bd9.min.js b/site/assets/javascripts/bundle.63456bd9.min.js new file mode 100644 index 000000000..38f0ece6e --- /dev/null +++ b/site/assets/javascripts/bundle.63456bd9.min.js @@ -0,0 +1,3 @@ +"use strict";(()=>{var xc=Object.create;var kn=Object.defineProperty,wc=Object.defineProperties,Ec=Object.getOwnPropertyDescriptor,Tc=Object.getOwnPropertyDescriptors,Sc=Object.getOwnPropertyNames,Dr=Object.getOwnPropertySymbols,Oc=Object.getPrototypeOf,An=Object.prototype.hasOwnProperty,Fo=Object.prototype.propertyIsEnumerable;var jo=(e,t,r)=>t in e?kn(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,H=(e,t)=>{for(var r in t||(t={}))An.call(t,r)&&jo(e,r,t[r]);if(Dr)for(var r of Dr(t))Fo.call(t,r)&&jo(e,r,t[r]);return e},He=(e,t)=>wc(e,Tc(t));var gr=(e,t)=>{var r={};for(var n in e)An.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&Dr)for(var n of Dr(e))t.indexOf(n)<0&&Fo.call(e,n)&&(r[n]=e[n]);return r};var Cn=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Lc=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Sc(t))!An.call(e,o)&&o!==r&&kn(e,o,{get:()=>t[o],enumerable:!(n=Ec(t,o))||n.enumerable});return e};var _r=(e,t,r)=>(r=e!=null?xc(Oc(e)):{},Lc(t||!e||!e.__esModule?kn(r,"default",{value:e,enumerable:!0}):r,e));var Uo=(e,t,r)=>new Promise((n,o)=>{var i=c=>{try{s(r.next(c))}catch(l){o(l)}},a=c=>{try{s(r.throw(c))}catch(l){o(l)}},s=c=>c.done?n(c.value):Promise.resolve(c.value).then(i,a);s((r=r.apply(e,t)).next())});var Do=Cn((Hn,No)=>{(function(e,t){typeof Hn=="object"&&typeof No!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Hn,(function(){"use strict";function e(r){var n=!0,o=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(_){return!!(_&&_!==document&&_.nodeName!=="HTML"&&_.nodeName!=="BODY"&&"classList"in _&&"contains"in _.classList)}function c(_){var de=_.type,be=_.tagName;return!!(be==="INPUT"&&a[de]&&!_.readOnly||be==="TEXTAREA"&&!_.readOnly||_.isContentEditable)}function l(_){_.classList.contains("focus-visible")||(_.classList.add("focus-visible"),_.setAttribute("data-focus-visible-added",""))}function u(_){_.hasAttribute("data-focus-visible-added")&&(_.classList.remove("focus-visible"),_.removeAttribute("data-focus-visible-added"))}function p(_){_.metaKey||_.altKey||_.ctrlKey||(s(r.activeElement)&&l(r.activeElement),n=!0)}function d(_){n=!1}function m(_){s(_.target)&&(n||c(_.target))&&l(_.target)}function h(_){s(_.target)&&(_.target.classList.contains("focus-visible")||_.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(_.target))}function v(_){document.visibilityState==="hidden"&&(o&&(n=!0),x())}function x(){document.addEventListener("mousemove",E),document.addEventListener("mousedown",E),document.addEventListener("mouseup",E),document.addEventListener("pointermove",E),document.addEventListener("pointerdown",E),document.addEventListener("pointerup",E),document.addEventListener("touchmove",E),document.addEventListener("touchstart",E),document.addEventListener("touchend",E)}function w(){document.removeEventListener("mousemove",E),document.removeEventListener("mousedown",E),document.removeEventListener("mouseup",E),document.removeEventListener("pointermove",E),document.removeEventListener("pointerdown",E),document.removeEventListener("pointerup",E),document.removeEventListener("touchmove",E),document.removeEventListener("touchstart",E),document.removeEventListener("touchend",E)}function E(_){_.target.nodeName&&_.target.nodeName.toLowerCase()==="html"||(n=!1,w())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",d,!0),document.addEventListener("pointerdown",d,!0),document.addEventListener("touchstart",d,!0),document.addEventListener("visibilitychange",v,!0),x(),r.addEventListener("focus",m,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)}))});var So=Cn((M0,vs)=>{"use strict";var Gu=/["'&<>]/;vs.exports=Ju;function Ju(e){var t=""+e,r=Gu.exec(t);if(!r)return t;var n,o="",i=0,a=0;for(i=r.index;i{(function(t,r){typeof jr=="object"&&typeof Lo=="object"?Lo.exports=r():typeof define=="function"&&define.amd?define([],r):typeof jr=="object"?jr.ClipboardJS=r():t.ClipboardJS=r()})(jr,function(){return(function(){var e={686:(function(n,o,i){"use strict";i.d(o,{default:function(){return vr}});var a=i(279),s=i.n(a),c=i(370),l=i.n(c),u=i(817),p=i.n(u);function d(B){try{return document.execCommand(B)}catch(C){return!1}}var m=function(C){var k=p()(C);return d("cut"),k},h=m;function v(B){var C=document.documentElement.getAttribute("dir")==="rtl",k=document.createElement("textarea");k.style.fontSize="12pt",k.style.border="0",k.style.padding="0",k.style.margin="0",k.style.position="absolute",k.style[C?"right":"left"]="-9999px";var D=window.pageYOffset||document.documentElement.scrollTop;return k.style.top="".concat(D,"px"),k.setAttribute("readonly",""),k.value=B,k}var x=function(C,k){var D=v(C);k.container.appendChild(D);var W=p()(D);return d("copy"),D.remove(),W},w=function(C){var k=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},D="";return typeof C=="string"?D=x(C,k):C instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(C==null?void 0:C.type)?D=x(C.value,k):(D=p()(C),d("copy")),D},E=w;function _(B){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?_=function(k){return typeof k}:_=function(k){return k&&typeof Symbol=="function"&&k.constructor===Symbol&&k!==Symbol.prototype?"symbol":typeof k},_(B)}var de=function(){var C=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},k=C.action,D=k===void 0?"copy":k,W=C.container,Z=C.target,We=C.text;if(D!=="copy"&&D!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(Z!==void 0)if(Z&&_(Z)==="object"&&Z.nodeType===1){if(D==="copy"&&Z.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(D==="cut"&&(Z.hasAttribute("readonly")||Z.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(We)return E(We,{container:W});if(Z)return D==="cut"?h(Z):E(Z,{container:W})},be=de;function M(B){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?M=function(k){return typeof k}:M=function(k){return k&&typeof Symbol=="function"&&k.constructor===Symbol&&k!==Symbol.prototype?"symbol":typeof k},M(B)}function O(B,C){if(!(B instanceof C))throw new TypeError("Cannot call a class as a function")}function N(B,C){for(var k=0;k0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof W.action=="function"?W.action:this.defaultAction,this.target=typeof W.target=="function"?W.target:this.defaultTarget,this.text=typeof W.text=="function"?W.text:this.defaultText,this.container=M(W.container)==="object"?W.container:document.body}},{key:"listenClick",value:function(W){var Z=this;this.listener=l()(W,"click",function(We){return Z.onClick(We)})}},{key:"onClick",value:function(W){var Z=W.delegateTarget||W.currentTarget,We=this.action(Z)||"copy",Gt=be({action:We,container:this.container,target:this.target(Z),text:this.text(Z)});this.emit(Gt?"success":"error",{action:We,text:Gt,trigger:Z,clearSelection:function(){Z&&Z.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(W){return Yt("action",W)}},{key:"defaultTarget",value:function(W){var Z=Yt("target",W);if(Z)return document.querySelector(Z)}},{key:"defaultText",value:function(W){return Yt("text",W)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(W){var Z=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return E(W,Z)}},{key:"cut",value:function(W){return h(W)}},{key:"isSupported",value:function(){var W=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Z=typeof W=="string"?[W]:W,We=!!document.queryCommandSupported;return Z.forEach(function(Gt){We=We&&!!document.queryCommandSupported(Gt)}),We}}]),k})(s()),vr=Mt}),828:(function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,c){for(;s&&s.nodeType!==o;){if(typeof s.matches=="function"&&s.matches(c))return s;s=s.parentNode}}n.exports=a}),438:(function(n,o,i){var a=i(828);function s(u,p,d,m,h){var v=l.apply(this,arguments);return u.addEventListener(d,v,h),{destroy:function(){u.removeEventListener(d,v,h)}}}function c(u,p,d,m,h){return typeof u.addEventListener=="function"?s.apply(null,arguments):typeof d=="function"?s.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return s(v,p,d,m,h)}))}function l(u,p,d,m){return function(h){h.delegateTarget=a(h.target,p),h.delegateTarget&&m.call(u,h)}}n.exports=c}),879:(function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}}),370:(function(n,o,i){var a=i(879),s=i(438);function c(d,m,h){if(!d&&!m&&!h)throw new Error("Missing required arguments");if(!a.string(m))throw new TypeError("Second argument must be a String");if(!a.fn(h))throw new TypeError("Third argument must be a Function");if(a.node(d))return l(d,m,h);if(a.nodeList(d))return u(d,m,h);if(a.string(d))return p(d,m,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function l(d,m,h){return d.addEventListener(m,h),{destroy:function(){d.removeEventListener(m,h)}}}function u(d,m,h){return Array.prototype.forEach.call(d,function(v){v.addEventListener(m,h)}),{destroy:function(){Array.prototype.forEach.call(d,function(v){v.removeEventListener(m,h)})}}}function p(d,m,h){return s(document.body,d,m,h)}n.exports=c}),817:(function(n){function o(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),l=document.createRange();l.selectNodeContents(i),c.removeAllRanges(),c.addRange(l),a=c.toString()}return a}n.exports=o}),279:(function(n){function o(){}o.prototype={on:function(i,a,s){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var c=this;function l(){c.off(i,l),a.apply(s,arguments)}return l._=a,this.on(i,l,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),c=0,l=s.length;for(c;c0&&i[i.length-1])&&(l[0]===6||l[0]===2)){r=0;continue}if(l[0]===3&&(!i||l[1]>i[0]&&l[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function te(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],a;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(s){a={error:s}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(a)throw a.error}}return i}function ne(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||c(m,v)})},h&&(o[m]=h(o[m])))}function c(m,h){try{l(n[m](h))}catch(v){d(i[0][3],v)}}function l(m){m.value instanceof kt?Promise.resolve(m.value.v).then(u,p):d(i[0][2],m)}function u(m){c("next",m)}function p(m){c("throw",m)}function d(m,h){m(h),i.shift(),i.length&&c(i[0][0],i[0][1])}}function zo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof $e=="function"?$e(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(a){return new Promise(function(s,c){a=e[i](a),o(s,c,a.done,a.value)})}}function o(i,a,s,c){Promise.resolve(c).then(function(l){i({value:l,done:s})},a)}}function F(e){return typeof e=="function"}function Jt(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var Vr=Jt(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function ct(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var rt=(function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a)if(this._parentage=null,Array.isArray(a))try{for(var s=$e(a),c=s.next();!c.done;c=s.next()){var l=c.value;l.remove(this)}}catch(v){t={error:v}}finally{try{c&&!c.done&&(r=s.return)&&r.call(s)}finally{if(t)throw t.error}}else a.remove(this);var u=this.initialTeardown;if(F(u))try{u()}catch(v){i=v instanceof Vr?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var d=$e(p),m=d.next();!m.done;m=d.next()){var h=m.value;try{qo(h)}catch(v){i=i!=null?i:[],v instanceof Vr?i=ne(ne([],te(i)),te(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{m&&!m.done&&(o=d.return)&&o.call(d)}finally{if(n)throw n.error}}}if(i)throw new Vr(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)qo(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&ct(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&ct(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=(function(){var t=new e;return t.closed=!0,t})(),e})();var Pn=rt.EMPTY;function zr(e){return e instanceof rt||e&&"closed"in e&&F(e.remove)&&F(e.add)&&F(e.unsubscribe)}function qo(e){F(e)?e():e.unsubscribe()}var Je={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var Xt={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,a=o.isStopped,s=o.observers;return i||a?Pn:(this.currentObservers=null,s.push(r),new rt(function(){n.currentObservers=null,ct(s,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,a=n.isStopped;o?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new U;return r.source=this,r},t.create=function(r,n){return new Qo(r,n)},t})(U);var Qo=(function(e){ue(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Pn},t})(I);var Un=(function(e){ue(t,e);function t(r){var n=e.call(this)||this;return n._value=r,n}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var n=e.prototype._subscribe.call(this,r);return!n.closed&&r.next(this._value),n},t.prototype.getValue=function(){var r=this,n=r.hasError,o=r.thrownError,i=r._value;if(n)throw o;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t})(I);var xr={now:function(){return(xr.delegate||Date).now()},delegate:void 0};var wr=(function(e){ue(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=xr);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,a=n._infiniteTimeWindow,s=n._timestampProvider,c=n._windowTime;o||(i.push(r),!a&&i.push(s.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,a=o._buffer,s=a.slice(),c=0;c0?e.prototype.schedule.call(this,r,n):(this.delay=n,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,n){return n>0||this.closed?e.prototype.execute.call(this,r,n):this._execute(r,n)},t.prototype.requestAsyncId=function(r,n,o){return o===void 0&&(o=0),o!=null&&o>0||o==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,n,o):(r.flush(this),0)},t})(tr);var ri=(function(e){ue(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t})(rr);var Wn=new ri(ti);var ni=(function(e){ue(t,e);function t(r,n){var o=e.call(this,r,n)||this;return o.scheduler=r,o.work=n,o}return t.prototype.requestAsyncId=function(r,n,o){return o===void 0&&(o=0),o!==null&&o>0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=er.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var a=r.actions;n!=null&&n===r._scheduled&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==n&&(er.cancelAnimationFrame(n),r._scheduled=void 0)},t})(tr);var oi=(function(e){ue(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n;r?n=r.id:(n=this._scheduled,this._scheduled=void 0);var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t})(rr);var je=new oi(ni);var y=new U(function(e){return e.complete()});function Br(e){return e&&F(e.schedule)}function Vn(e){return e[e.length-1]}function _t(e){return F(Vn(e))?e.pop():void 0}function qe(e){return Br(Vn(e))?e.pop():void 0}function Yr(e,t){return typeof Vn(e)=="number"?e.pop():t}var nr=(function(e){return e&&typeof e.length=="number"&&typeof e!="function"});function Gr(e){return F(e==null?void 0:e.then)}function Jr(e){return F(e[Qt])}function Xr(e){return Symbol.asyncIterator&&F(e==null?void 0:e[Symbol.asyncIterator])}function Zr(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Rc(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Qr=Rc();function en(e){return F(e==null?void 0:e[Qr])}function tn(e){return Vo(this,arguments,function(){var r,n,o,i;return Wr(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,kt(r.read())];case 3:return n=a.sent(),o=n.value,i=n.done,i?[4,kt(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,kt(o)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function rn(e){return F(e==null?void 0:e.getReader)}function q(e){if(e instanceof U)return e;if(e!=null){if(Jr(e))return jc(e);if(nr(e))return Fc(e);if(Gr(e))return Uc(e);if(Xr(e))return ii(e);if(en(e))return Nc(e);if(rn(e))return Dc(e)}throw Zr(e)}function jc(e){return new U(function(t){var r=e[Qt]();if(F(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function Fc(e){return new U(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?L(function(o,i){return e(o,i,n)}):Le,Me(1),r?ot(t):wi(function(){return new on}))}}function Gn(e){return e<=0?function(){return y}:S(function(t,r){var n=[];t.subscribe(T(r,function(o){n.push(o),e=2,!0))}function xe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new I}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,c=s===void 0?!0:s;return function(l){var u,p,d,m=0,h=!1,v=!1,x=function(){p==null||p.unsubscribe(),p=void 0},w=function(){x(),u=d=void 0,h=v=!1},E=function(){var _=u;w(),_==null||_.unsubscribe()};return S(function(_,de){m++,!v&&!h&&x();var be=d=d!=null?d:r();de.add(function(){m--,m===0&&!v&&!h&&(p=Jn(E,c))}),be.subscribe(de),!u&&m>0&&(u=new Ct({next:function(M){return be.next(M)},error:function(M){v=!0,x(),p=Jn(w,o,M),be.error(M)},complete:function(){h=!0,x(),p=Jn(w,a),be.complete()}}),q(_).subscribe(u))})(l)}}function Jn(e,t){for(var r=[],n=2;ne.next(document)),e}function P(e,t=document){return Array.from(t.querySelectorAll(e))}function G(e,t=document){let r=we(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function we(e,t=document){return t.querySelector(e)||void 0}function xt(){var e,t,r,n;return(n=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?n:void 0}var il=R(b(document.body,"focusin"),b(document.body,"focusout")).pipe(Be(1),J(void 0),f(()=>xt()||document.body),se(1));function ir(e){return il.pipe(f(t=>e.contains(t)),ie())}function Ft(e,t){let{matches:r}=matchMedia("(hover)");return j(()=>(r?R(b(e,"mouseenter").pipe(f(()=>!0)),b(e,"mouseleave").pipe(f(()=>!1))):R(b(e,"touchstart").pipe(f(()=>!0)),b(e,"touchend").pipe(f(()=>!1)),b(e,"touchcancel").pipe(f(()=>!1)))).pipe(t?Tr(o=>Ve(+!o*t)):Le,J(!0,e.matches(":hover"))))}function Oi(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)Oi(e,r)}function A(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)Oi(n,o);return n}function Li(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function ar(e){let t=A("script",{src:e});return j(()=>(document.head.appendChild(t),R(b(t,"load"),b(t,"error").pipe(g(()=>zn(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(f(()=>{}),V(()=>document.head.removeChild(t)),Me(1))))}var Mi=new I,al=j(()=>typeof ResizeObserver=="undefined"?ar("https://unpkg.com/resize-observer-polyfill"):Y(void 0)).pipe(f(()=>new ResizeObserver(e=>e.forEach(t=>Mi.next(t)))),g(e=>R(Ke,Y(e)).pipe(V(()=>e.disconnect()))),se(1));function Ae(e){return{width:e.offsetWidth,height:e.offsetHeight}}function Re(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return al.pipe($(r=>r.observe(t)),g(r=>Mi.pipe(L(n=>n.target===t),V(()=>r.unobserve(t)))),f(()=>Ae(e)),J(Ae(e)))}function Mr(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ki(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function Ai(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function wt(e){return{x:e.offsetLeft,y:e.offsetTop}}function Ci(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function Hi(e){return R(b(window,"load"),b(window,"resize")).pipe(Xe(0,je),f(()=>wt(e)),J(wt(e)))}function ln(e){return{x:e.scrollLeft,y:e.scrollTop}}function Ut(e){return R(b(e,"scroll"),b(window,"scroll"),b(window,"resize")).pipe(Xe(0,je),f(()=>ln(e)),J(ln(e)))}var $i=new I,sl=j(()=>Y(new IntersectionObserver(e=>{for(let t of e)$i.next(t)},{threshold:0}))).pipe(g(e=>R(Ke,Y(e)).pipe(V(()=>e.disconnect()))),se(1));function Et(e){return sl.pipe($(t=>t.observe(e)),g(t=>$i.pipe(L(({target:r})=>r===e),V(()=>t.unobserve(e)),f(({isIntersecting:r})=>r))))}var cl=Object.create,la=Object.defineProperty,ll=Object.getOwnPropertyDescriptor,ul=Object.getOwnPropertyNames,pl=Object.getPrototypeOf,fl=Object.prototype.hasOwnProperty,ml=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),dl=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ul(t))!fl.call(e,o)&&o!==r&&la(e,o,{get:()=>t[o],enumerable:!(n=ll(t,o))||n.enumerable});return e},hl=(e,t,r)=>(r=e!=null?cl(pl(e)):{},dl(t||!e||!e.__esModule?la(r,"default",{value:e,enumerable:!0}):r,e)),vl=ml((e,t)=>{var r="Expected a function",n=NaN,o="[object Symbol]",i=/^\s+|\s+$/g,a=/^[-+]0x[0-9a-f]+$/i,s=/^0b[01]+$/i,c=/^0o[0-7]+$/i,l=parseInt,u=typeof global=="object"&&global&&global.Object===Object&&global,p=typeof self=="object"&&self&&self.Object===Object&&self,d=u||p||Function("return this")(),m=Object.prototype,h=m.toString,v=Math.max,x=Math.min,w=function(){return d.Date.now()};function E(O,N,ee){var le,ce,Ne,bt,De,st,tt=0,Yt=!1,Mt=!1,vr=!0;if(typeof O!="function")throw new TypeError(r);N=M(N)||0,_(ee)&&(Yt=!!ee.leading,Mt="maxWait"in ee,Ne=Mt?v(M(ee.maxWait)||0,N):Ne,vr="trailing"in ee?!!ee.trailing:vr);function B(Se){var gt=le,br=ce;return le=ce=void 0,tt=Se,bt=O.apply(br,gt),bt}function C(Se){return tt=Se,De=setTimeout(W,N),Yt?B(Se):bt}function k(Se){var gt=Se-st,br=Se-tt,Ro=N-gt;return Mt?x(Ro,Ne-br):Ro}function D(Se){var gt=Se-st,br=Se-tt;return st===void 0||gt>=N||gt<0||Mt&&br>=Ne}function W(){var Se=w();if(D(Se))return Z(Se);De=setTimeout(W,k(Se))}function Z(Se){return De=void 0,vr&&le?B(Se):(le=ce=void 0,bt)}function We(){De!==void 0&&clearTimeout(De),tt=0,le=st=ce=De=void 0}function Gt(){return De===void 0?bt:Z(w())}function Nr(){var Se=w(),gt=D(Se);if(le=arguments,ce=this,st=Se,gt){if(De===void 0)return C(st);if(Mt)return De=setTimeout(W,N),B(st)}return De===void 0&&(De=setTimeout(W,N)),bt}return Nr.cancel=We,Nr.flush=Gt,Nr}function _(O){var N=typeof O;return!!O&&(N=="object"||N=="function")}function de(O){return!!O&&typeof O=="object"}function be(O){return typeof O=="symbol"||de(O)&&h.call(O)==o}function M(O){if(typeof O=="number")return O;if(be(O))return n;if(_(O)){var N=typeof O.valueOf=="function"?O.valueOf():O;O=_(N)?N+"":N}if(typeof O!="string")return O===0?O:+O;O=O.replace(i,"");var ee=s.test(O);return ee||c.test(O)?l(O.slice(2),ee?2:8):a.test(O)?n:+O}t.exports=E}),yn,K,ua,pa,Nt,Pi,fa,ma,da,lo,to,ro,bl,Ar={},ha=[],gl=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,Pr=Array.isArray;function pt(e,t){for(var r in t)e[r]=t[r];return e}function uo(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function Wt(e,t,r){var n,o,i,a={};for(i in t)i=="key"?n=t[i]:i=="ref"?o=t[i]:a[i]=t[i];if(arguments.length>2&&(a.children=arguments.length>3?yn.call(arguments,2):r),typeof e=="function"&&e.defaultProps!=null)for(i in e.defaultProps)a[i]===void 0&&(a[i]=e.defaultProps[i]);return fn(e,a,n,o,null)}function fn(e,t,r,n,o){var i={type:e,props:t,key:r,ref:n,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:o!=null?o:++ua,__i:-1,__u:0};return o==null&&K.vnode!=null&&K.vnode(i),i}function ft(e){return e.children}function at(e,t){this.props=e,this.context=t}function cr(e,t){if(t==null)return e.__?cr(e.__,e.__i+1):null;for(var r;ts&&Nt.sort(ma),e=Nt.shift(),s=Nt.length,e.__d&&(r=void 0,n=void 0,o=(n=(t=e).__v).__e,i=[],a=[],t.__P&&((r=pt({},n)).__v=n.__v+1,K.vnode&&K.vnode(r),po(t.__P,r,n,t.__n,t.__P.namespaceURI,32&n.__u?[o]:null,i,o!=null?o:cr(n),!!(32&n.__u),a),r.__v=n.__v,r.__.__k[r.__i]=r,_a(i,r,a),n.__e=n.__=null,r.__e!=o&&va(r)));vn.__r=0}function ba(e,t,r,n,o,i,a,s,c,l,u){var p,d,m,h,v,x,w,E=n&&n.__k||ha,_=t.length;for(c=_l(r,t,E,c,_),p=0;p<_;p++)(m=r.__k[p])!=null&&(d=m.__i==-1?Ar:E[m.__i]||Ar,m.__i=p,x=po(e,m,d,o,i,a,s,c,l,u),h=m.__e,m.ref&&d.ref!=m.ref&&(d.ref&&fo(d.ref,null,m),u.push(m.ref,m.__c||h,m)),v==null&&h!=null&&(v=h),(w=!!(4&m.__u))||d.__k===m.__k?c=ga(m,c,e,w):typeof m.type=="function"&&x!==void 0?c=x:h&&(c=h.nextSibling),m.__u&=-7);return r.__e=v,c}function _l(e,t,r,n,o){var i,a,s,c,l,u=r.length,p=u,d=0;for(e.__k=new Array(o),i=0;i0?fn(a.type,a.props,a.key,a.ref?a.ref:null,a.__v):a).__=e,a.__b=e.__b+1,s=null,(l=a.__i=yl(a,r,c,p))!=-1&&(p--,(s=r[l])&&(s.__u|=2)),s==null||s.__v==null?(l==-1&&(o>u?d--:oc?d--:d++,a.__u|=4))):e.__k[i]=null;if(p)for(i=0;i(u?1:0)){for(o=r-1,i=r+1;o>=0||i=0?o--:i++])!=null&&!(2&l.__u)&&s==l.key&&c==l.type)return a}return-1}function Ri(e,t,r){t[0]=="-"?e.setProperty(t,r!=null?r:""):e[t]=r==null?"":typeof r!="number"||gl.test(t)?r:r+"px"}function un(e,t,r,n,o){var i,a;e:if(t=="style")if(typeof r=="string")e.style.cssText=r;else{if(typeof n=="string"&&(e.style.cssText=n=""),n)for(t in n)r&&t in r||Ri(e.style,t,"");if(r)for(t in r)n&&r[t]==n[t]||Ri(e.style,t,r[t])}else if(t[0]=="o"&&t[1]=="n")i=t!=(t=t.replace(da,"$1")),a=t.toLowerCase(),t=a in e||t=="onFocusOut"||t=="onFocusIn"?a.slice(2):t.slice(2),e.l||(e.l={}),e.l[t+i]=r,r?n?r.u=n.u:(r.u=lo,e.addEventListener(t,i?ro:to,i)):e.removeEventListener(t,i?ro:to,i);else{if(o=="http://www.w3.org/2000/svg")t=t.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(t!="width"&&t!="height"&&t!="href"&&t!="list"&&t!="form"&&t!="tabIndex"&&t!="download"&&t!="rowSpan"&&t!="colSpan"&&t!="role"&&t!="popover"&&t in e)try{e[t]=r!=null?r:"";break e}catch(s){}typeof r=="function"||(r==null||r===!1&&t[4]!="-"?e.removeAttribute(t):e.setAttribute(t,t=="popover"&&r==1?"":r))}}function ji(e){return function(t){if(this.l){var r=this.l[t.type+e];if(t.t==null)t.t=lo++;else if(t.t0?e:Pr(e)?e.map(ya):pt({},e)}function xl(e,t,r,n,o,i,a,s,c){var l,u,p,d,m,h,v,x=r.props,w=t.props,E=t.type;if(E=="svg"?o="http://www.w3.org/2000/svg":E=="math"?o="http://www.w3.org/1998/Math/MathML":o||(o="http://www.w3.org/1999/xhtml"),i!=null){for(l=0;l=r.__.length&&r.__.push({}),r.__[e]}function bn(e){return $r=1,Tl(Ta,e)}function Tl(e,t,r){var n=mo(Hr++,2);if(n.t=e,!n.__c&&(n.__=[r?r(t):Ta(void 0,t),function(s){var c=n.__N?n.__N[0]:n.__[0],l=n.t(c,s);c!==l&&(n.__N=[l,n.__[1]],n.__c.setState({}))}],n.__c=ve,!ve.__f)){var o=function(s,c,l){if(!n.__c.__H)return!0;var u=n.__c.__H.__.filter(function(d){return!!d.__c});if(u.every(function(d){return!d.__N}))return!i||i.call(this,s,c,l);var p=n.__c.props!==s;return u.forEach(function(d){if(d.__N){var m=d.__[0];d.__=d.__N,d.__N=void 0,m!==d.__[0]&&(p=!0)}}),i&&i.call(this,s,c,l)||p};ve.__f=!0;var i=ve.shouldComponentUpdate,a=ve.componentWillUpdate;ve.componentWillUpdate=function(s,c,l){if(this.__e){var u=i;i=void 0,o(s,c,l),i=u}a&&a.call(this,s,c,l)},ve.shouldComponentUpdate=o}return n.__N||n.__}function mt(e,t){var r=mo(Hr++,3);!Ee.__s&&Ea(r.__H,t)&&(r.__=e,r.u=t,ve.__H.__h.push(r))}function Vt(e){return $r=5,ur(function(){return{current:e}},[])}function ur(e,t){var r=mo(Hr++,7);return Ea(r.__H,t)&&(r.__=e(),r.__H=t,r.__h=e),r.__}function Sl(e,t){return $r=8,ur(function(){return e},t)}function Ol(){for(var e;e=wa.shift();)if(e.__P&&e.__H)try{e.__H.__h.forEach(mn),e.__H.__h.forEach(oo),e.__H.__h=[]}catch(t){e.__H.__h=[],Ee.__e(t,e.__v)}}Ee.__b=function(e){ve=null,Ui&&Ui(e)},Ee.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),zi&&zi(e,t)},Ee.__r=function(e){Ni&&Ni(e),Hr=0;var t=(ve=e.__c).__H;t&&(Zn===ve?(t.__h=[],ve.__h=[],t.__.forEach(function(r){r.__N&&(r.__=r.__N),r.u=r.__N=void 0})):(t.__h.forEach(mn),t.__h.forEach(oo),t.__h=[],Hr=0)),Zn=ve},Ee.diffed=function(e){Di&&Di(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(wa.push(t)!==1&&Fi===Ee.requestAnimationFrame||((Fi=Ee.requestAnimationFrame)||Ll)(Ol)),t.__H.__.forEach(function(r){r.u&&(r.__H=r.u),r.u=void 0})),Zn=ve=null},Ee.__c=function(e,t){t.some(function(r){try{r.__h.forEach(mn),r.__h=r.__h.filter(function(n){return!n.__||oo(n)})}catch(n){t.some(function(o){o.__h&&(o.__h=[])}),t=[],Ee.__e(n,r.__v)}}),Wi&&Wi(e,t)},Ee.unmount=function(e){Vi&&Vi(e);var t,r=e.__c;r&&r.__H&&(r.__H.__.forEach(function(n){try{mn(n)}catch(o){t=o}}),r.__H=void 0,t&&Ee.__e(t,r.__v))};var qi=typeof requestAnimationFrame=="function";function Ll(e){var t,r=function(){clearTimeout(n),qi&&cancelAnimationFrame(t),setTimeout(e)},n=setTimeout(r,35);qi&&(t=requestAnimationFrame(r))}function mn(e){var t=ve,r=e.__c;typeof r=="function"&&(e.__c=void 0,r()),ve=t}function oo(e){var t=ve;e.__c=e.__(),ve=t}function Ea(e,t){return!e||e.length!==t.length||t.some(function(r,n){return r!==e[n]})}function Ta(e,t){return typeof t=="function"?t(e):t}function Ml(e,t){for(var r in t)e[r]=t[r];return e}function Ki(e,t){for(var r in e)if(r!=="__source"&&!(r in t))return!0;for(var n in t)if(n!=="__source"&&e[n]!==t[n])return!0;return!1}function Bi(e,t){this.props=e,this.context=t}(Bi.prototype=new at).isPureReactComponent=!0,Bi.prototype.shouldComponentUpdate=function(e,t){return Ki(this.props,e)||Ki(this.state,t)};var Yi=K.__b;K.__b=function(e){e.type&&e.type.__f&&e.ref&&(e.props.ref=e.ref,e.ref=null),Yi&&Yi(e)};var Yx=typeof Symbol<"u"&&Symbol.for&&Symbol.for("react.forward_ref")||3911,kl=K.__e;K.__e=function(e,t,r,n){if(e.then){for(var o,i=t;i=i.__;)if((o=i.__c)&&o.__c)return t.__e==null&&(t.__e=r.__e,t.__k=r.__k),o.__c(e,t)}kl(e,t,r,n)};var Gi=K.unmount;function Sa(e,t,r){return e&&(e.__c&&e.__c.__H&&(e.__c.__H.__.forEach(function(n){typeof n.__c=="function"&&n.__c()}),e.__c.__H=null),(e=Ml({},e)).__c!=null&&(e.__c.__P===r&&(e.__c.__P=t),e.__c.__e=!0,e.__c=null),e.__k=e.__k&&e.__k.map(function(n){return Sa(n,t,r)})),e}function Oa(e,t,r){return e&&r&&(e.__v=null,e.__k=e.__k&&e.__k.map(function(n){return Oa(n,t,r)}),e.__c&&e.__c.__P===t&&(e.__e&&r.appendChild(e.__e),e.__c.__e=!0,e.__c.__P=r)),e}function Qn(){this.__u=0,this.o=null,this.__b=null}function La(e){var t=e.__.__c;return t&&t.__a&&t.__a(e)}function pn(){this.i=null,this.l=null}K.unmount=function(e){var t=e.__c;t&&t.__R&&t.__R(),t&&32&e.__u&&(e.type=null),Gi&&Gi(e)},(Qn.prototype=new at).__c=function(e,t){var r=t.__c,n=this;n.o==null&&(n.o=[]),n.o.push(r);var o=La(n.__v),i=!1,a=function(){i||(i=!0,r.__R=null,o?o(s):s())};r.__R=a;var s=function(){if(!--n.__u){if(n.state.__a){var c=n.state.__a;n.__v.__k[0]=Oa(c,c.__c.__P,c.__c.__O)}var l;for(n.setState({__a:n.__b=null});l=n.o.pop();)l.forceUpdate()}};n.__u++||32&t.__u||n.setState({__a:n.__b=n.__v.__k[0]}),e.then(a,a)},Qn.prototype.componentWillUnmount=function(){this.o=[]},Qn.prototype.render=function(e,t){if(this.__b){if(this.__v.__k){var r=document.createElement("div"),n=this.__v.__k[0].__c;this.__v.__k[0]=Sa(this.__b,r,n.__O=n.__P)}this.__b=null}var o=t.__a&&Wt(ft,null,e.fallback);return o&&(o.__u&=-33),[Wt(ft,null,t.__a?null:e.children),o]};var Ji=function(e,t,r){if(++r[1]===r[0]&&e.l.delete(t),e.props.revealOrder&&(e.props.revealOrder[0]!=="t"||!e.l.size))for(r=e.i;r;){for(;r.length>3;)r.pop()();if(r[1]Object.freeze({get current(){return t.current}}),[])}var Nl=typeof globalThis<"u"&&typeof navigator<"u"&&typeof document<"u";function Dl(e,...t){var r;(r=e==null?void 0:e.addEventListener)==null||r.call(e,...t)}function Wl(e,...t){var r;(r=e==null?void 0:e.removeEventListener)==null||r.call(e,...t)}var Vl=(e,t)=>Object.hasOwn(e,t),zl=()=>!0,ql=()=>!1;function Kl(e=!1){let t=Vt(e),r=Sl(()=>t.current,[]);return mt(()=>(t.current=!0,()=>{t.current=!1}),[]),r}function Bl(e,...t){let r=Kl(),n=ka(t[1]),o=ur(()=>function(...i){r()&&(typeof n.current=="function"?n.current.apply(this,i):typeof n.current.handleEvent=="function"&&n.current.handleEvent.apply(this,i))},[]);mt(()=>{let i=Yl(e)?e.current:e;if(!i)return;let a=t.slice(2);return Dl(i,t[0],o,...a),()=>{Wl(i,t[0],o,...a)}},[e,t[0]])}function Yl(e){return e!==null&&typeof e=="object"&&Vl(e,"current")}var Gl=e=>typeof e=="function"?e:typeof e=="string"?t=>t.key===e:e?zl:ql,Jl=Nl?globalThis:null;function Aa(e,t,r=[],n={}){let{event:o="keydown",target:i=Jl,eventOptions:a}=n,s=ka(t),c=ur(()=>{let l=Gl(e);return function(u){l(u)&&s.current.call(this,u)}},r);Bl(i,o,c,a)}function Ca(e){var t,r,n="";if(typeof e=="string"||typeof e=="number")n+=e;else if(typeof e=="object")if(Array.isArray(e)){var o=e.length;for(t=0;t1)St--;else{for(var e,t=!1;kr!==void 0;){var r=kr;for(kr=void 0,io++;r!==void 0;){var n=r.o;if(r.o=void 0,r.f&=-3,!(8&r.f)&&Pa(r))try{r.c()}catch(o){t||(e=o,t=!0)}r=n}}if(io=0,St--,t)throw e}}function Ql(e){if(St>0)return e();St++;try{return e()}finally{xn()}}var ae=void 0;function Ha(e){var t=ae;ae=void 0;try{return e()}finally{ae=t}}var kr=void 0,St=0,io=0,gn=0;function $a(e){if(ae!==void 0){var t=e.n;if(t===void 0||t.t!==ae)return t={i:0,S:e,p:ae.s,n:void 0,t:ae,e:void 0,x:void 0,r:t},ae.s!==void 0&&(ae.s.n=t),ae.s=t,e.n=t,32&ae.f&&e.S(t),t;if(t.i===-1)return t.i=0,t.n!==void 0&&(t.n.p=t.p,t.p!==void 0&&(t.p.n=t.n),t.p=ae.s,t.n=void 0,ae.s.n=t,ae.s=t),t}}function Ce(e,t){this.v=e,this.i=0,this.n=void 0,this.t=void 0,this.W=t==null?void 0:t.watched,this.Z=t==null?void 0:t.unwatched,this.name=t==null?void 0:t.name}Ce.prototype.brand=Zl;Ce.prototype.h=function(){return!0};Ce.prototype.S=function(e){var t=this,r=this.t;r!==e&&e.e===void 0&&(e.x=r,this.t=e,r!==void 0?r.e=e:Ha(function(){var n;(n=t.W)==null||n.call(t)}))};Ce.prototype.U=function(e){var t=this;if(this.t!==void 0){var r=e.e,n=e.x;r!==void 0&&(r.x=n,e.e=void 0),n!==void 0&&(n.e=r,e.x=void 0),e===this.t&&(this.t=n,n===void 0&&Ha(function(){var o;(o=t.Z)==null||o.call(t)}))}};Ce.prototype.subscribe=function(e){var t=this;return qt(function(){var r=t.value,n=ae;ae=void 0;try{e(r)}finally{ae=n}},{name:"sub"})};Ce.prototype.valueOf=function(){return this.value};Ce.prototype.toString=function(){return this.value+""};Ce.prototype.toJSON=function(){return this.value};Ce.prototype.peek=function(){var e=ae;ae=void 0;try{return this.value}finally{ae=e}};Object.defineProperty(Ce.prototype,"value",{get:function(){var e=$a(this);return e!==void 0&&(e.i=this.i),this.v},set:function(e){if(e!==this.v){if(io>100)throw new Error("Cycle detected");this.v=e,this.i++,gn++,St++;try{for(var t=this.t;t!==void 0;t=t.x)t.t.N()}finally{xn()}}}});function Ot(e,t){return new Ce(e,t)}function Pa(e){for(var t=e.s;t!==void 0;t=t.n)if(t.S.i!==t.i||!t.S.h()||t.S.i!==t.i)return!0;return!1}function Ia(e){for(var t=e.s;t!==void 0;t=t.n){var r=t.S.n;if(r!==void 0&&(t.r=r),t.S.n=t,t.i=-1,t.n===void 0){e.s=t;break}}}function Ra(e){for(var t=e.s,r=void 0;t!==void 0;){var n=t.p;t.i===-1?(t.S.U(t),n!==void 0&&(n.n=t.n),t.n!==void 0&&(t.n.p=n)):r=t,t.S.n=t.r,t.r!==void 0&&(t.r=void 0),t=n}e.s=r}function Kt(e,t){Ce.call(this,void 0),this.x=e,this.s=void 0,this.g=gn-1,this.f=4,this.W=t==null?void 0:t.watched,this.Z=t==null?void 0:t.unwatched,this.name=t==null?void 0:t.name}Kt.prototype=new Ce;Kt.prototype.h=function(){if(this.f&=-3,1&this.f)return!1;if((36&this.f)==32||(this.f&=-5,this.g===gn))return!0;if(this.g=gn,this.f|=1,this.i>0&&!Pa(this))return this.f&=-2,!0;var e=ae;try{Ia(this),ae=this;var t=this.x();(16&this.f||this.v!==t||this.i===0)&&(this.v=t,this.f&=-17,this.i++)}catch(r){this.v=r,this.f|=16,this.i++}return ae=e,Ra(this),this.f&=-2,!0};Kt.prototype.S=function(e){if(this.t===void 0){this.f|=36;for(var t=this.s;t!==void 0;t=t.n)t.S.S(t)}Ce.prototype.S.call(this,e)};Kt.prototype.U=function(e){if(this.t!==void 0&&(Ce.prototype.U.call(this,e),this.t===void 0)){this.f&=-33;for(var t=this.s;t!==void 0;t=t.n)t.S.U(t)}};Kt.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var e=this.t;e!==void 0;e=e.x)e.t.N()}};Object.defineProperty(Kt.prototype,"value",{get:function(){if(1&this.f)throw new Error("Cycle detected");var e=$a(this);if(this.h(),e!==void 0&&(e.i=this.i),16&this.f)throw this.v;return this.v}});function ta(e,t){return new Kt(e,t)}function ja(e){var t=e.u;if(e.u=void 0,typeof t=="function"){St++;var r=ae;ae=void 0;try{t()}catch(n){throw e.f&=-2,e.f|=8,ho(e),n}finally{ae=r,xn()}}}function ho(e){for(var t=e.s;t!==void 0;t=t.n)t.S.U(t);e.x=void 0,e.s=void 0,ja(e)}function eu(e){if(ae!==this)throw new Error("Out-of-order effect");Ra(this),ae=e,this.f&=-2,8&this.f&&ho(this),xn()}function pr(e,t){this.x=e,this.u=void 0,this.s=void 0,this.o=void 0,this.f=32,this.name=t==null?void 0:t.name}pr.prototype.c=function(){var e=this.S();try{if(8&this.f||this.x===void 0)return;var t=this.x();typeof t=="function"&&(this.u=t)}finally{e()}};pr.prototype.S=function(){if(1&this.f)throw new Error("Cycle detected");this.f|=1,this.f&=-9,ja(this),Ia(this),St++;var e=ae;return ae=this,eu.bind(this,e)};pr.prototype.N=function(){2&this.f||(this.f|=2,this.o=kr,kr=this)};pr.prototype.d=function(){this.f|=8,1&this.f||ho(this)};pr.prototype.dispose=function(){this.d()};function qt(e,t){var r=new pr(e,t);try{r.c()}catch(o){throw r.d(),o}var n=r.d.bind(r);return n[Symbol.dispose]=n,n}var Fa,vo,eo,Ua=[];qt(function(){Fa=this.N})();function fr(e,t){K[e]=t.bind(null,K[e]||function(){})}function _n(e){eo&&eo(),eo=e&&e.S()}function Na(e){var t=this,r=e.data,n=ru(r);n.value=r;var o=ur(function(){for(var s=t,c=t.__v;c=c.__;)if(c.__c){c.__c.__$f|=4;break}var l=ta(function(){var m=n.value.value;return m===0?0:m===!0?"":m||""}),u=ta(function(){return!Array.isArray(l.value)&&!pa(l.value)}),p=qt(function(){if(this.N=Da,u.value){var m=l.value;s.__v&&s.__v.__e&&s.__v.__e.nodeType===3&&(s.__v.__e.data=m)}}),d=t.__$u.d;return t.__$u.d=function(){p(),d.call(this)},[u,l]},[]),i=o[0],a=o[1];return i.value?a.peek():a.value}Na.displayName="ReactiveTextNode";Object.defineProperties(Ce.prototype,{constructor:{configurable:!0,value:void 0},type:{configurable:!0,value:Na},props:{configurable:!0,get:function(){return{data:this}}},__b:{configurable:!0,value:1}});fr("__b",function(e,t){if(typeof t.type=="function"&&typeof window<"u"&&window.__PREACT_SIGNALS_DEVTOOLS__&&window.__PREACT_SIGNALS_DEVTOOLS__.exitComponent(),typeof t.type=="string"){var r,n=t.props;for(var o in n)if(o!=="children"){var i=n[o];i instanceof Ce&&(r||(t.__np=r={}),r[o]=i,n[o]=i.peek())}}e(t)});fr("__r",function(e,t){if(typeof t.type=="function"&&typeof window<"u"&&window.__PREACT_SIGNALS_DEVTOOLS__&&window.__PREACT_SIGNALS_DEVTOOLS__.enterComponent(t),t.type!==ft){_n();var r,n=t.__c;n&&(n.__$f&=-2,(r=n.__$u)===void 0&&(n.__$u=r=(function(o){var i;return qt(function(){i=this}),i.c=function(){n.__$f|=1,n.setState({})},i})())),vo=n,_n(r)}e(t)});fr("__e",function(e,t,r,n){typeof window<"u"&&window.__PREACT_SIGNALS_DEVTOOLS__&&window.__PREACT_SIGNALS_DEVTOOLS__.exitComponent(),_n(),vo=void 0,e(t,r,n)});fr("diffed",function(e,t){typeof t.type=="function"&&typeof window<"u"&&window.__PREACT_SIGNALS_DEVTOOLS__&&window.__PREACT_SIGNALS_DEVTOOLS__.exitComponent(),_n(),vo=void 0;var r;if(typeof t.type=="string"&&(r=t.__e)){var n=t.__np,o=t.props;if(n){var i=r.U;if(i)for(var a in i){var s=i[a];s!==void 0&&!(a in n)&&(s.d(),i[a]=void 0)}else i={},r.U=i;for(var c in n){var l=i[c],u=n[c];l===void 0?(l=tu(r,c,u,o),i[c]=l):l.o(u,o)}}}e(t)});function tu(e,t,r,n){var o=t in e&&e.ownerSVGElement===void 0,i=Ot(r);return{o:function(a,s){i.value=a,n=s},d:qt(function(){this.N=Da;var a=i.value.value;n[t]!==a&&(n[t]=a,o?e[t]=a:a?e.setAttribute(t,a):e.removeAttribute(t))})}}fr("unmount",function(e,t){if(typeof t.type=="string"){var r=t.__e;if(r){var n=r.U;if(n){r.U=void 0;for(var o in n){var i=n[o];i&&i.d()}}}}else{var a=t.__c;if(a){var s=a.__$u;s&&(a.__$u=void 0,s.d())}}e(t)});fr("__h",function(e,t,r,n){(n<3||n===9)&&(t.__$f|=2),e(t,r,n)});at.prototype.shouldComponentUpdate=function(e,t){var r=this.__$u,n=r&&r.s!==void 0;for(var o in t)return!0;if(this.__f||typeof this.u=="boolean"&&this.u===!0){var i=2&this.__$f;if(!(n||i||4&this.__$f)||1&this.__$f)return!0}else if(!(n||4&this.__$f)||3&this.__$f)return!0;for(var a in e)if(a!=="__source"&&e[a]!==this.props[a])return!0;for(var s in this.props)if(!(s in e))return!0;return!1};function ru(e,t){return bn(function(){return Ot(e,t)})[0]}var nu=function(e){queueMicrotask(function(){queueMicrotask(e)})};function ou(){Ql(function(){for(var e;e=Ua.shift();)Fa.call(e)})}function Da(){Ua.push(this)===1&&(K.requestAnimationFrame||nu)(ou)}var ao=[0];for(let e=0;e<32;e++)ao.push(ao[e]|1<>>5]>>>e&1}set(e){this.data[e>>>5]|=1<<(e&31)}forEach(e){let t=this.size&31;for(let r=0;r{var r;return(r=t.tags)==null?void 0:r.length})&&(matchMedia("(max-width: 768px)").matches||Wa())}function Dt(){Qe.value=He(H({},Qe.value),{hideSearch:!Qe.value.hideSearch})}function Wa(){Qe.value=He(H({},Qe.value),{hideFilters:!Qe.value.hideFilters})}function dn(){return Qe.value.selectedItem}function so(e){Qe.value=He(H({},Qe.value),{selectedItem:e})}function su(){var e,t;return(t=(e=lr.value)==null?void 0:e.items)!=null?t:[]}function wn(){return typeof Oe.value.input=="string"?Oe.value.input:""}function Va(e){let t=za();e.length&&!t.length?Oe.value=He(H({},Oe.value),{page:void 0,input:e}):!e.length&&t.length?Oe.value=He(H({},Oe.value),{page:void 0,input:{type:"operator",data:{operator:"not",operands:[]}}}):Oe.value=He(H({},Oe.value),{page:void 0,input:e})}function cu(){typeof it.value.pagination.next<"u"&&(Oe.value=He(H({},Oe.value),{page:it.value.pagination.next}))}function lu(e){let t=Oe.value.filter.input;if("type"in t&&t.type==="operator"){for(let r of t.data.operands)if("type"in r&&r.type==="value"&&typeof r.data.value=="string"&&r.data.value===e)return!0}return!1}function za(){let e=Oe.value.filter.input,t=[];if("type"in e&&e.type==="operator")for(let r of e.data.operands)"type"in r&&r.type==="value"&&typeof r.data.value=="string"&&t.push(r.data.value);return t}function uu(e){let t=Oe.value.filter.input,r=[];if("type"in t&&t.type==="operator")for(let n of t.data.operands)"type"in n&&n.type==="value"&&typeof n.data.value=="string"&&r.push(n.data.value);if(r.includes(e)){let n=r.indexOf(e);n>-1&&r.splice(n,1)}else r.push(e);Oe.value=He(H({},Oe.value),{page:void 0,filter:He(H({},Oe.value.filter),{input:{type:"operator",data:{operator:"and",operands:r.map(n=>({type:"value",data:{field:"tags",value:n}}))}}})}),Va(wn())}function pu(){return it.value.items}function fu(){return it.value.total}function mu(){var e;for(let t of(e=it.value.aggregations)!=null?e:[])if(t.type==="term")return t.data.value;return[]}function sr(){return Qe.value.hideSearch}function du(){return Qe.value.hideFilters}function qa(){var e;return(e=Ka.value.highlight)!=null?e:!1}var Qe=Ot({hideSearch:!0,hideFilters:!0,selectedItem:0}),Ka=Ot({}),lr=Ot(),na=Ot(),Oe=Ot({input:"",filter:{input:{type:"operator",data:{operator:"and",operands:[]}},aggregation:{input:[{type:"term",data:{field:"tags"}}]}}}),it=Ot({items:[],query:{select:{documents:new ra(0),terms:new ra(0)},values:[]},pagination:{total:0}});function hu(e,t,r){for(let n=0;tr&&t(0,o,r,r=i);continue;case 62:e.charCodeAt(r+1)===47?t(2,--o,r,r=i+1):hu(e,r,n)?t(3,o,r,r=i+1):t(1,o++,r,r=i+1)}i>r&&t(0,o,r,i)}function bu(e,t=0,r=e.length){let n=++t;e:for(let l=0;n{let i=[],a=[],{onElement:s,onText:c=gu}=typeof r=="function"?{onElement:r}:r,l=0,u=0;return e(t,(p,d,m,h)=>{if(p===0)i[l++]=c(t,m,h),a[u++]={value:null,depth:d};else if(p&1&&(a[u++]={value:bu(t,m,h),depth:d}),p&2)for(let v=0;u>=0;v++){let{value:x,depth:w}=a[--u];if(w>d)continue;let E=i.slice(l-=v,l+v);i[l++]=s(x,E),u++;break}},n,o),i.slice(0,l)}}function yu(e){return e.replace(/[&<>]/g,t=>{switch(t.charCodeAt(0)){case 38:return"&";case 60:return"<";case 62:return">"}})}function hn(e){return e.replace(/&(amp|[lg]t);/g,t=>{switch(t.charCodeAt(1)){case 97:return"&";case 108:return"<";case 103:return">"}})}function xu(e,t){return{start:e.start+t,end:e.end+t,value:e.value}}function wu(e,t,r){return e.slice(t,r)}function Eu(e){let{onHighlight:t,onText:r=wu}=typeof e=="function"?{onHighlight:e}:e;return(n,o,i=0,a=n.length)=>{var l;let s=[],c=(l=o==null?void 0:o.ranges)!=null?l:[];for(let u=0,p=i;ua)break;let m=c[u].end;if(mi&&s.push(r(n,i,d));let{value:h}=c[u];s.push(t(n,{start:d,end:i=m,value:h}))}return i{let o=n.data;switch(o.type){case 1:na.value=!0;break;case 3:typeof o.data.pagination.prev<"u"?it.value=He(H({},it.value),{pagination:o.data.pagination,items:[...it.value.items,...o.data.items]}):(it.value=o.data,so(0));break}},qt(()=>{lr.value&&r.postMessage({type:0,data:lr.value})}),qt(()=>{na.value&&r.postMessage({type:2,data:Oe.value})})}var oa={container:"p",hidden:"m"};function ku(e){return z("div",{class:zt(oa.container,{[oa.hidden]:e.hidden}),onClick:()=>Dt()})}var ia={container:"r",disabled:"c"};function co(e){return z("button",{class:zt(ia.container,{[ia.disabled]:!e.onClick}),onClick:e.onClick,children:e.children})}var aa=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),Au=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(t,r,n)=>n?n.toUpperCase():r.toLowerCase()),sa=e=>{let t=Au(e);return t.charAt(0).toUpperCase()+t.slice(1)},Cu=(...e)=>e.filter((t,r,n)=>!!t&&t.trim()!==""&&n.indexOf(t)===r).join(" ").trim(),Hu={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},$u=c=>{var l=c,{color:e="currentColor",size:t=24,strokeWidth:r=2,absoluteStrokeWidth:n,children:o,iconNode:i,class:a=""}=l,s=gr(l,["color","size","strokeWidth","absoluteStrokeWidth","children","iconNode","class"]);return Wt("svg",H(He(H({},Hu),{width:String(t),height:t,stroke:e,"stroke-width":n?Number(r)*24/Number(t):r,class:["lucide",a].join(" ")}),s),[...i.map(([u,p])=>Wt(u,p)),...Cr(o)])},bo=(e,t)=>{let r=a=>{var s=a,{class:n="",children:o}=s,i=gr(s,["class","children"]);return Wt($u,He(H({},i),{iconNode:t,class:Cu(`lucide-${aa(sa(e))}`,`lucide-${aa(e)}`,n)}),o)};return r.displayName=sa(e),r},Pu=bo("corner-down-left",[["path",{d:"M20 4v7a4 4 0 0 1-4 4H4",key:"6o5b7l"}],["path",{d:"m9 10-5 5 5 5",key:"1kshq7"}]]),Iu=bo("list-filter",[["path",{d:"M2 5h20",key:"1fs1ex"}],["path",{d:"M6 12h12",key:"8npq4p"}],["path",{d:"M9 19h6",key:"456am0"}]]),Ru=bo("search",[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]]),Gx=hl(vl(),1);function ju({threshold:e=0,root:t=null,rootMargin:r="0%",freezeOnceVisible:n=!1,initialIsIntersecting:o=!1,onChange:i}={}){var a;let[s,c]=bn(null),[l,u]=bn(()=>({isIntersecting:o,entry:void 0})),p=Vt();p.current=i;let d=((a=l.entry)==null?void 0:a.isIntersecting)&&n;mt(()=>{if(!s||!("IntersectionObserver"in window)||d)return;let v,x=new IntersectionObserver(w=>{let E=Array.isArray(x.thresholds)?x.thresholds:[x.thresholds];w.forEach(_=>{let de=_.isIntersecting&&E.some(be=>_.intersectionRatio>=be);u({isIntersecting:de,entry:_}),p.current&&p.current(de,_),de&&n&&v&&(v(),v=void 0)})},{threshold:e,root:t,rootMargin:r});return x.observe(s),()=>{x.disconnect()}},[s,JSON.stringify(e),t,r,d,n]);let m=Vt(null);mt(()=>{var v;!s&&(v=l.entry)!=null&&v.target&&!n&&!d&&m.current!==l.entry.target&&(m.current=l.entry.target,u({isIntersecting:o,entry:void 0}))},[s,l.entry,n,d,o]);let h=[c,!!l.isIntersecting,l.entry];return h.ref=h[0],h.isIntersecting=h[1],h.entry=h[2],h}var lt={container:"n",hidden:"l",content:"u",pop:"d",badge:"y",sidebar:"i",controls:"w",results:"k",loadmore:"z"};function Fu(e){let{isIntersecting:t,ref:r}=ju({threshold:0});mt(()=>{t&&cu()},[t]);let n=Vt(null);mt(()=>{n.current&&typeof Oe.value.page>"u"&&n.current.scrollTo({top:0,behavior:"smooth"})},[Oe.value]);let o=za();return z("div",{class:zt(lt.container,{[lt.hidden]:e.hidden}),children:[z("div",{class:lt.content,children:[z("div",{class:lt.controls,children:[z(co,{onClick:Dt,children:z(Ru,{})}),z(Nu,{focus:!e.hidden}),z(co,{onClick:Wa,children:[z(Iu,{}),o.length>0&&z("span",{class:lt.badge,children:o.length})]})]}),z("div",{class:lt.results,ref:n,children:[z(Du,{keyboard:!e.hidden}),z("div",{class:lt.loadmore,ref:r})]})]}),z("div",{class:zt(lt.sidebar,{[lt.hidden]:du()}),children:z(Uu,{})})]})}var Tt={container:"X",list:"j",heading:"F",title:"I",item:"o",active:"g",value:"R",count:"q"};function Uu(e){let t=mu();return t.sort((r,n)=>n.node.count-r.node.count),z("div",{class:Tt.container,children:[z("h3",{class:Tt.heading,children:"Filters"}),z("h4",{class:Tt.title,children:"Tags"}),z("ol",{class:Tt.list,children:t.map(r=>z("li",{class:zt(Tt.item,{[Tt.active]:lu(r.node.value)}),onClick:()=>uu(r.node.value),children:[z("span",{class:Tt.value,children:r.node.value}),z("span",{class:Tt.count,children:r.node.count})]}))})]})}var ca={container:"f"};function Nu(e){let t=Vt(null);return mt(()=>{var r,n;e.focus?(r=t.current)==null||r.focus():(n=t.current)==null||n.blur()},[e.focus]),z("div",{class:ca.container,children:z("input",{ref:t,type:"text",class:ca.content,value:hn(wn()),onInput:r=>Va(yu(r.currentTarget.value)),autocapitalize:"off",autocomplete:"off",autocorrect:"off",placeholder:"Search",spellcheck:!1,role:"combobox"})})}var ut={container:"b",heading:"A",item:"a",active:"h",wrapper:"B",actions:"s",title:"x",path:"t"};function Ga(){let[e,t]=bn(!1);return mt(()=>{let r=()=>t(!0),n=()=>t(!1);return document.addEventListener("compositionstart",r),document.addEventListener("compositionend",n),()=>{document.removeEventListener("compositionstart",r),document.removeEventListener("compositionend",n)}},[]),e}function Du(e){var s;let t=su(),r=pu(),n=dn(),o=Vt([]),i=Ga();mt(()=>{let c=o.current[n];c&&c.scrollIntoView({block:"center",behavior:"smooth"})},[n]),Aa(e.keyboard,c=>{if(i)return;let l=dn();c.key==="ArrowDown"?(c.preventDefault(),so(Math.min(l+1,r.length-1))):c.key==="ArrowUp"&&(c.preventDefault(),so(Math.max(l-1,0)))},[e.keyboard,i]);let a=(s=fu())!=null?s:0;return z(ft,{children:[r.length>0&&z("h3",{class:ut.heading,children:[z("span",{class:ut.bubble,children:new Intl.NumberFormat("en-US").format(a)})," ","results"]}),z("ol",{class:ut.container,children:r.map((c,l)=>{var m;let u=Ba(t[c.id].title,c.matches.find(({field:h})=>h==="title")),p=Mu((m=t[c.id].path)!=null?m:[],c.matches.find(({field:h})=>h==="path")),d=t[c.id].location;if(qa()){let h=encodeURIComponent(wn()),[v,x]=d.split("#",2);d=`${v}?h=${h.replace(/%20/g,"+")}`,typeof x<"u"&&(d+=`#${x}`)}return z("li",{children:z("a",{ref:h=>{o.current[l]=h},href:d,onClick:()=>Dt(),class:zt(ut.item,{[ut.active]:l===dn()}),children:[z("div",{class:ut.wrapper,children:[z("h2",{class:ut.title,children:u}),z("menu",{class:ut.path,children:p.map(h=>z("li",{children:h}))})]}),z("nav",{class:ut.actions,children:z(co,{children:z(Pu,{})})})]})})})})]})}var Wu={container:"e"};function Vu(e){let t=Ga();return Aa(!0,r=>{var n,o,i,a,s;if(!t)if((r.metaKey||r.ctrlKey)&&r.key==="k")r.preventDefault(),Dt();else if((r.metaKey||r.ctrlKey)&&r.key==="j")document.body.classList.toggle("dark");else if(r.key==="Enter"&&!sr()){r.preventDefault();let c=dn(),l=(o=(n=it.value)==null?void 0:n.items[c])==null?void 0:o.id;if((a=(i=lr.value)==null?void 0:i.items[l])!=null&&a.location){Dt();let u=(s=lr.value)==null?void 0:s.items[l].location;if(qa()){let p=encodeURIComponent(wn()),[d,m]=u.split("#",2);u=`${d}?h=${p.replace(/%20/g,"+")}`,typeof m<"u"&&(u+=`#${m}`)}window.location.href=u}}else r.key==="Escape"&&!sr()&&(r.preventDefault(),Dt())},[t]),z("div",{class:Wu.container,children:[z(ku,{hidden:sr()}),z(Fu,{hidden:sr()})]})}function Ja(e,t){au(e),El(z(Vu,{}),t)}function go(){Dt()}function zu(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function qu(){return R(b(window,"compositionstart").pipe(f(()=>!0)),b(window,"compositionend").pipe(f(()=>!1))).pipe(J(!1))}function Xa(){let e=b(window,"keydown").pipe(f(t=>({mode:sr()?"global":"search",type:t.key,meta:t.ctrlKey||t.metaKey,claim(){t.preventDefault(),t.stopPropagation()}})),L(({mode:t,type:r})=>{if(t==="global"){let n=xt();if(typeof n!="undefined")return!zu(n,r)}return!0}),xe());return qu().pipe(g(t=>t?y:e))}function Ye(){return new URL(location.href)}function dt(e,t=!1){if(X("navigation.instant")&&!t){let r=A("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function Za(){return new I}function Qa(){return location.hash.slice(1)}function es(e){let t=A("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function _o(e){return R(b(window,"hashchange"),e).pipe(f(Qa),J(Qa()),L(t=>t.length>0),f(decodeURIComponent),se(1))}function ts(e){return _o(e).pipe(f(t=>we(`[id="${t}"]`)),L(t=>typeof t!="undefined"))}function Ir(e){let t=matchMedia(e);return an(r=>t.addListener(()=>r(t.matches))).pipe(J(t.matches))}function rs(){let e=matchMedia("print");return R(b(window,"beforeprint").pipe(f(()=>!0)),b(window,"afterprint").pipe(f(()=>!1))).pipe(J(e.matches))}function yo(e,t){return e.pipe(g(r=>r?t():y))}function xo(e,t){return new U(r=>{let n=new XMLHttpRequest;return n.open("GET",`${e}`),n.responseType="blob",n.addEventListener("load",()=>{n.status>=200&&n.status<300?(r.next(n.response),r.complete()):r.error(new Error(n.statusText))}),n.addEventListener("error",()=>{r.error(new Error("Network error"))}),n.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(n.addEventListener("progress",o=>{var i;if(o.lengthComputable)t.progress$.next(o.loaded/o.total*100);else{let a=(i=n.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(o.loaded/+a*100)}}),t.progress$.next(5)),n.send(),()=>n.abort()})}function et(e,t){return xo(e,t).pipe(g(r=>r.text()),f(r=>JSON.parse(r)),se(1))}function En(e,t){let r=new DOMParser;return xo(e,t).pipe(g(n=>n.text()),f(n=>r.parseFromString(n,"text/html")),se(1))}function ns(e,t){let r=new DOMParser;return xo(e,t).pipe(g(n=>n.text()),f(n=>r.parseFromString(n,"text/xml")),se(1))}var wo={drawer:G("[data-md-toggle=drawer]"),search:G("[data-md-toggle=search]")};function Eo(e,t){wo[e].checked!==t&&wo[e].click()}function Tn(e){let t=wo[e];return b(t,"change").pipe(f(()=>t.checked),J(t.checked))}function os(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function is(){return R(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(f(os),J(os()))}function as(){return{width:innerWidth,height:innerHeight}}function ss(){return b(window,"resize",{passive:!0}).pipe(f(as),J(as()))}function cs(){return re([is(),ss()]).pipe(f(([e,t])=>({offset:e,size:t})),se(1))}function Sn(e,{viewport$:t,header$:r}){let n=t.pipe(fe("size")),o=re([n,r]).pipe(f(()=>wt(e)));return re([r,t,o]).pipe(f(([{height:i},{offset:a,size:s},{x:c,y:l}])=>({offset:{x:a.x-c,y:a.y-l+i},size:s})))}var Ku=G("#__config"),mr=JSON.parse(Ku.textContent);mr.base=`${new URL(mr.base,Ye())}`;function Ue(){return mr}function X(e){return mr.features.includes(e)}function Bt(e,t){return typeof t!="undefined"?mr.translations[e].replace("#",t.toString()):mr.translations[e]}function ht(e,t=document){return G(`[data-md-component=${e}]`,t)}function Te(e,t=document){return P(`[data-md-component=${e}]`,t)}function Bu(e){let t=G(".md-typeset > :first-child",e);return b(t,"click",{once:!0}).pipe(f(()=>G(".md-typeset",e)),f(r=>({hash:__md_hash(r.innerHTML)})))}function ls(e){if(!X("announce.dismiss")||!e.childElementCount)return y;if(!e.hidden){let t=G(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return j(()=>{let t=new I;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),Bu(e).pipe($(r=>t.next(r)),V(()=>t.complete()),f(r=>H({ref:e},r)))})}function Yu(e,{target$:t}){return t.pipe(f(r=>({hidden:r!==e})))}function us(e,t){let r=new I;return r.subscribe(({hidden:n})=>{e.hidden=n}),Yu(e,t).pipe($(n=>r.next(n)),V(()=>r.complete()),f(n=>H({ref:e},n)))}function To(e,t){return t==="inline"?A("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},A("div",{class:"md-tooltip__inner md-typeset"})):A("div",{class:"md-tooltip",id:e,role:"tooltip"},A("div",{class:"md-tooltip__inner md-typeset"}))}function On(...e){return A("div",{class:"md-tooltip2",role:"dialog"},A("div",{class:"md-tooltip2__inner md-typeset"},e))}function ps(...e){return A("div",{class:"md-tooltip2",role:"tooltip"},A("div",{class:"md-tooltip2__inner md-typeset"},e))}function fs(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return A("aside",{class:"md-annotation",tabIndex:0},To(t),A("a",{href:r,class:"md-annotation__index",tabIndex:-1},A("span",{"data-md-annotation-id":e})))}else return A("aside",{class:"md-annotation",tabIndex:0},To(t),A("span",{class:"md-annotation__index",tabIndex:-1},A("span",{"data-md-annotation-id":e})))}function ms(e){return A("button",{class:"md-code__button",title:Bt("clipboard.copy"),"data-clipboard-target":`#${e} > code`,"data-md-type":"copy"})}function ds(){return A("button",{class:"md-code__button",title:"Toggle line selection","data-md-type":"select"})}function hs(){return A("nav",{class:"md-code__nav"})}var Xu=_r(So());function bs(e){return A("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>A("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?Li(r):r)))}function Oo(e){let t=`tabbed-control tabbed-control--${e}`;return A("div",{class:t,hidden:!0},A("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function gs(e){return A("div",{class:"md-typeset__scrollwrap"},A("div",{class:"md-typeset__table"},e))}function Zu(e){var n;let t=Ue(),r=new URL(`../${e.version}/`,t.base);return A("li",{class:"md-version__item"},A("a",{href:`${r}`,class:"md-version__link"},e.title,((n=t.version)==null?void 0:n.alias)&&e.aliases.length>0&&A("span",{class:"md-version__alias"},e.aliases[0])))}function _s(e,t){var n;let r=Ue();return e=e.filter(o=>{var i;return!((i=o.properties)!=null&&i.hidden)}),A("div",{class:"md-version"},A("button",{class:"md-version__current","aria-label":Bt("select.version")},t.title,((n=r.version)==null?void 0:n.alias)&&t.aliases.length>0&&A("span",{class:"md-version__alias"},t.aliases[0])),A("ul",{class:"md-version__list"},e.map(Zu)))}var Qu=0;function ep(e,t=250){let r=re([ir(e),Ft(e,t)]).pipe(f(([o,i])=>o||i),ie()),n=j(()=>Ai(e)).pipe(oe(Ut),Lr(1),Ze(r),f(()=>Ci(e)));return r.pipe(Sr(o=>o),g(()=>re([r,n])),f(([o,i])=>({active:o,offset:i})),xe())}function Rr(e,t,r=250){let{content$:n,viewport$:o}=t,i=`__tooltip2_${Qu++}`;return j(()=>{let a=new I,s=new Un(!1);a.pipe(he(),ye(!1)).subscribe(s);let c=s.pipe(Tr(u=>Ve(+!u*250,Wn)),ie(),g(u=>u?n:y),$(u=>u.id=i),xe());re([a.pipe(f(({active:u})=>u)),c.pipe(g(u=>Ft(u,250)),J(!1))]).pipe(f(u=>u.some(p=>p))).subscribe(s);let l=s.pipe(L(u=>u),pe(c,o),f(([u,p,{size:d}])=>{let m=e.getBoundingClientRect(),h=m.width/2;if(p.role==="tooltip")return{x:h,y:8+m.height};if(m.y>=d.height/2){let{height:v}=Ae(p);return{x:h,y:-16-v}}else return{x:h,y:16+m.height}}));return re([c,a,l]).subscribe(([u,{offset:p},d])=>{u.style.setProperty("--md-tooltip-host-x",`${p.x}px`),u.style.setProperty("--md-tooltip-host-y",`${p.y}px`),u.style.setProperty("--md-tooltip-x",`${d.x}px`),u.style.setProperty("--md-tooltip-y",`${d.y}px`),u.classList.toggle("md-tooltip2--top",d.y<0),u.classList.toggle("md-tooltip2--bottom",d.y>=0)}),s.pipe(L(u=>u),pe(c,(u,p)=>p),L(u=>u.role==="tooltip")).subscribe(u=>{let p=Ae(G(":scope > *",u));u.style.setProperty("--md-tooltip-width",`${p.width}px`),u.style.setProperty("--md-tooltip-tail","0px")}),s.pipe(ie(),Ie(je),pe(c)).subscribe(([u,p])=>{p.classList.toggle("md-tooltip2--active",u)}),re([s.pipe(L(u=>u)),c]).subscribe(([u,p])=>{p.role==="dialog"?(e.setAttribute("aria-controls",i),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",i)}),s.pipe(L(u=>!u)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),ep(e,r).pipe($(u=>a.next(u)),V(()=>a.complete()),f(u=>H({ref:e},u)))})}function Ge(e,{viewport$:t},r=document.body){return Rr(e,{content$:new U(n=>{let o=e.title,i=ps(o);return n.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",o)}}),viewport$:t},0)}function tp(e,t){let r=j(()=>re([Hi(e),Ut(t)])).pipe(f(([{x:n,y:o},i])=>{let{width:a,height:s}=Ae(e);return{x:n-i.x+a/2,y:o-i.y+s/2}}));return ir(e).pipe(g(n=>r.pipe(f(o=>({active:n,offset:o})),Me(+!n||1/0))))}function ys(e,t,{target$:r}){let[n,o]=Array.from(e.children);return j(()=>{let i=new I,a=i.pipe(he(),ye(!0));return i.subscribe({next({offset:s}){e.style.setProperty("--md-tooltip-x",`${s.x}px`),e.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),Et(e).pipe(Q(a)).subscribe(s=>{e.toggleAttribute("data-md-visible",s)}),R(i.pipe(L(({active:s})=>s)),i.pipe(Be(250),L(({active:s})=>!s))).subscribe({next({active:s}){s?e.prepend(n):n.remove()},complete(){e.prepend(n)}}),i.pipe(Xe(16,je)).subscribe(({active:s})=>{n.classList.toggle("md-tooltip--active",s)}),i.pipe(Lr(125,je),L(()=>!!e.offsetParent),f(()=>e.offsetParent.getBoundingClientRect()),f(({x:s})=>s)).subscribe({next(s){s?e.style.setProperty("--md-tooltip-0",`${-s}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),b(o,"click").pipe(Q(a),L(s=>!(s.metaKey||s.ctrlKey))).subscribe(s=>{s.stopPropagation(),s.preventDefault()}),b(o,"mousedown").pipe(Q(a),pe(i)).subscribe(([s,{active:c}])=>{var l;if(s.button!==0||s.metaKey||s.ctrlKey)s.preventDefault();else if(c){s.preventDefault();let u=e.parentElement.closest(".md-annotation");u instanceof HTMLElement?u.focus():(l=xt())==null||l.blur()}}),r.pipe(Q(a),L(s=>s===n),It(125)).subscribe(()=>e.focus()),tp(e,t).pipe($(s=>i.next(s)),V(()=>i.complete()),f(s=>H({ref:e},s)))})}function rp(e){let t=Ue();if(e.tagName!=="CODE")return[e];let r=[".c",".c1",".cm"];if(t.annotate){let n=e.closest("[class|=language]");if(n)for(let o of Array.from(n.classList)){if(!o.startsWith("language-"))continue;let[,i]=o.split("-");i in t.annotate&&r.push(...t.annotate[i])}}return P(r.join(", "),e)}function np(e){let t=[];for(let r of rp(e)){let n=[],o=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=o.nextNode();i;i=o.nextNode())n.push(i);for(let i of n){let a;for(;a=/(\(\d+\))(!)?/.exec(i.textContent);){let[,s,c]=a;if(typeof c=="undefined"){let l=i.splitText(a.index);i=l.splitText(s.length),t.push(l)}else{i.textContent=s,t.push(i);break}}}}return t}function xs(e,t){t.append(...Array.from(e.childNodes))}function Ln(e,t,{target$:r,print$:n}){let o=t.closest("[id]"),i=o==null?void 0:o.id,a=new Map;for(let s of np(t)){let[,c]=s.textContent.match(/\((\d+)\)/);we(`:scope > li:nth-child(${c})`,e)&&(a.set(c,fs(c,i)),s.replaceWith(a.get(c)))}return a.size===0?y:j(()=>{let s=new I,c=s.pipe(he(),ye(!0)),l=[];for(let[u,p]of a)l.push([G(".md-typeset",p),G(`:scope > li:nth-child(${u})`,e)]);return n.pipe(Q(c)).subscribe(u=>{e.hidden=!u,e.classList.toggle("md-annotation-list",u);for(let[p,d]of l)u?xs(p,d):xs(d,p)}),R(...[...a].map(([,u])=>ys(u,t,{target$:r}))).pipe(V(()=>s.complete()),xe())})}function ws(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return ws(t)}}function Es(e,t){return j(()=>{let r=ws(e);return typeof r!="undefined"?Ln(r,e,t):y})}var Ss=_r(Mo());var op=0,Ts=R(b(window,"keydown").pipe(f(()=>!0)),R(b(window,"keyup"),b(window,"contextmenu")).pipe(f(()=>!1))).pipe(J(!1),se(1));function Os(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Os(t)}}function ip(e){return Re(e).pipe(f(({width:t})=>({scrollable:Mr(e).width>t})),fe("scrollable"))}function Ls(e,t){let{matches:r}=matchMedia("(hover)"),n=j(()=>{let o=new I,i=o.pipe(Gn(1));o.subscribe(({scrollable:m})=>{m&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let a=[],s=e.closest("pre"),c=s.closest("[id]"),l=c?c.id:op++;s.id=`__code_${l}`;let u=[],p=e.closest(".highlight");if(p instanceof HTMLElement){let m=Os(p);if(typeof m!="undefined"&&(p.classList.contains("annotate")||X("content.code.annotate"))){let h=Ln(m,e,t);u.push(Re(p).pipe(Q(i),f(({width:v,height:x})=>v&&x),ie(),g(v=>v?h:y)))}}let d=P(":scope > span[id]",e);if(d.length&&(e.classList.add("md-code__content"),e.closest(".select")||X("content.code.select")&&!e.closest(".no-select"))){let m=+d[0].id.split("-").pop(),h=ds();a.push(h),X("content.tooltips")&&u.push(Ge(h,{viewport$}));let v=b(h,"click").pipe(Or(M=>!M,!1),$(()=>h.blur()),xe());v.subscribe(M=>{h.classList.toggle("md-code__button--active",M)});let x=me(d).pipe(oe(M=>Ft(M).pipe(f(O=>[M,O]))));v.pipe(g(M=>M?x:y)).subscribe(([M,O])=>{let N=we(".hll.select",M);if(N&&!O)N.replaceWith(...Array.from(N.childNodes));else if(!N&&O){let ee=document.createElement("span");ee.className="hll select",ee.append(...Array.from(M.childNodes).slice(1)),M.append(ee)}});let w=me(d).pipe(oe(M=>b(M,"mousedown").pipe($(O=>O.preventDefault()),f(()=>M)))),E=v.pipe(g(M=>M?w:y),pe(Ts),f(([M,O])=>{var ee;let N=d.indexOf(M)+m;if(O===!1)return[N,N];{let le=P(".hll",e).map(ce=>d.indexOf(ce.parentElement)+m);return(ee=window.getSelection())==null||ee.removeAllRanges(),[Math.min(N,...le),Math.max(N,...le)]}})),_=_o(y).pipe(L(M=>M.startsWith(`__codelineno-${l}-`)));_.subscribe(M=>{let[,,O]=M.split("-"),N=O.split(":").map(le=>+le-m+1);N.length===1&&N.push(N[0]);for(let le of P(".hll:not(.select)",e))le.replaceWith(...Array.from(le.childNodes));let ee=d.slice(N[0]-1,N[1]);for(let le of ee){let ce=document.createElement("span");ce.className="hll",ce.append(...Array.from(le.childNodes).slice(1)),le.append(ce)}}),_.pipe(Me(1),Ie(ge)).subscribe(M=>{if(M.includes(":")){let O=document.getElementById(M.split(":")[0]);O&&setTimeout(()=>{let N=O,ee=-64;for(;N!==document.body;)ee+=N.offsetTop,N=N.offsetParent;window.scrollTo({top:ee})},1)}});let be=me(P('a[href^="#__codelineno"]',p)).pipe(oe(M=>b(M,"click").pipe($(O=>O.preventDefault()),f(()=>M)))).pipe(Q(i),pe(Ts),f(([M,O])=>{let ee=+G(`[id="${M.hash.slice(1)}"]`).parentElement.id.split("-").pop();if(O===!1)return[ee,ee];{let le=P(".hll",e).map(ce=>+ce.parentElement.id.split("-").pop());return[Math.min(ee,...le),Math.max(ee,...le)]}}));R(E,be).subscribe(M=>{let O=`#__codelineno-${l}-`;M[0]===M[1]?O+=M[0]:O+=`${M[0]}:${M[1]}`,history.replaceState({},"",O),window.dispatchEvent(new HashChangeEvent("hashchange",{newURL:window.location.origin+window.location.pathname+O,oldURL:window.location.href}))})}if(Ss.default.isSupported()&&(e.closest(".copy")||X("content.code.copy")&&!e.closest(".no-copy"))){let m=ms(s.id);a.push(m),X("content.tooltips")&&u.push(Ge(m,{viewport$}))}if(a.length){let m=hs();m.append(...a),s.insertBefore(m,e)}return ip(e).pipe($(m=>o.next(m)),V(()=>o.complete()),f(m=>H({ref:e},m)),Rt(R(...u).pipe(Q(i))))});return X("content.lazy")?Et(e).pipe(L(o=>o),Me(1),g(()=>n)):n}function ap(e,{target$:t,print$:r}){let n=!0;return R(t.pipe(f(o=>o.closest("details:not([open])")),L(o=>e===o),f(()=>({action:"open",reveal:!0}))),r.pipe(L(o=>o||!n),$(()=>n=e.open),f(o=>({action:o?"open":"close"}))))}function Ms(e,t){return j(()=>{let r=new I;return r.subscribe(({action:n,reveal:o})=>{e.toggleAttribute("open",n==="open"),o&&e.scrollIntoView()}),ap(e,t).pipe($(n=>r.next(n)),V(()=>r.complete()),f(n=>H({ref:e},n)))})}var ks=0,As=new Map;function sp(e){let t=document.createElement("h3");t.innerHTML=e.innerHTML;let r=[t],n=e.nextElementSibling;for(;n&&!(n instanceof HTMLHeadingElement);)r.push(n.cloneNode(!0)),n=n.nextElementSibling;return r}function cp(e,t){for(let r of P("[href], [src]",e))for(let n of["href","src"]){let o=r.getAttribute(n);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){r[n]=new URL(r.getAttribute(n),t).toString();break}}for(let r of P("[name^=__], [for]",e))for(let n of["id","for","name"]){let o=r.getAttribute(n);o&&r.setAttribute(n,`${o}$preview_${ks}`)}return ks++,Y(e)}function lp(e){let t=As.get(e.toString());return t?Y(t):En(e).pipe(g(r=>cp(r,e)),f(r=>(As.set(e.toString(),r),r)))}function Cs(e,t){let{sitemap$:r}=t;if(!(e instanceof HTMLAnchorElement))return y;if(!(X("navigation.instant.preview")||e.hasAttribute("data-preview")))return y;e.removeAttribute("title");let n=re([ir(e),Ft(e).pipe(ke(1))]).pipe(f(([i,a])=>i||a),ie(),L(i=>i));return $t([r,n]).pipe(g(([i])=>{let a=new URL(e.href);return a.search=a.hash="",i.has(`${a}`)?Y(a):y}),g(i=>lp(i)),g(i=>{let a=e.hash?`article [id="${decodeURIComponent(e.hash.slice(1))}"]`:"article h1",s=we(a,i);return typeof s=="undefined"?y:Y(sp(s))})).pipe(g(i=>{let a=new U(s=>{let c=On(...i);return s.next(c),document.body.append(c),()=>c.remove()});return Rr(e,H({content$:a},t))}))}var Hs=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.flowchartTitleText{fill:var(--md-mermaid-label-fg-color)}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel p,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel p{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color)}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}.classDiagramTitleText{fill:var(--md-mermaid-label-fg-color)}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs marker.marker.composition.class path,defs marker.marker.dependency.class path,defs marker.marker.extension.class path{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs marker.marker.aggregation.class path{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}.statediagramTitleText{fill:var(--md-mermaid-label-fg-color)}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}a .nodeLabel{text-decoration:underline}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}[id^=entity] path,[id^=entity] rect{fill:var(--md-default-bg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs .marker.oneOrMore.er *,defs .marker.onlyOne.er *,defs .marker.zeroOrMore.er *,defs .marker.zeroOrOne.er *{stroke:var(--md-mermaid-edge-color)!important}text:not([class]):last-child{fill:var(--md-mermaid-label-fg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var ko,pp=0;function fp(){return typeof mermaid=="undefined"||mermaid instanceof Element?ar("https://unpkg.com/mermaid@11/dist/mermaid.min.js"):Y(void 0)}function $s(e){return e.classList.remove("mermaid"),ko||(ko=fp().pipe($(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Hs,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),f(()=>{}),se(1))),ko.subscribe(()=>Uo(null,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${pp++}`,r=A("div",{class:"mermaid"}),n=e.textContent,{svg:o,fn:i}=yield mermaid.render(t,n),a=r.attachShadow({mode:"closed"});a.innerHTML=o,e.replaceWith(r),i==null||i(a)})),ko.pipe(f(()=>({ref:e})))}var Ps=A("table");function Is(e){return e.replaceWith(Ps),Ps.replaceWith(gs(e)),Y({ref:e})}function mp(e){let t=e.find(r=>r.checked)||e[0];return R(...e.map(r=>b(r,"change").pipe(f(()=>G(`label[for="${r.id}"]`))))).pipe(J(G(`label[for="${t.id}"]`)),f(r=>({active:r})))}function Rs(e,{viewport$:t,target$:r}){let n=G(".tabbed-labels",e),o=P(":scope > input",e),i=Oo("prev");e.append(i);let a=Oo("next");return e.append(a),j(()=>{let s=new I,c=s.pipe(he(),ye(!0));re([s,Re(e),Et(e)]).pipe(Q(c),Xe(1,je)).subscribe({next([{active:l},u]){let p=wt(l),{width:d}=Ae(l);e.style.setProperty("--md-indicator-x",`${p.x}px`),e.style.setProperty("--md-indicator-width",`${d}px`);let m=ln(n);(p.xm.x+u.width)&&n.scrollTo({left:Math.max(0,p.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),re([Ut(n),Re(n)]).pipe(Q(c)).subscribe(([l,u])=>{let p=Mr(n);i.hidden=l.x<16,a.hidden=l.x>p.width-u.width-16}),R(b(i,"click").pipe(f(()=>-1)),b(a,"click").pipe(f(()=>1))).pipe(Q(c)).subscribe(l=>{let{width:u}=Ae(n);n.scrollBy({left:u*l,behavior:"smooth"})}),r.pipe(Q(c),L(l=>o.includes(l))).subscribe(l=>l.click()),n.classList.add("tabbed-labels--linked");for(let l of o){let u=G(`label[for="${l.id}"]`);u.replaceChildren(A("a",{href:`#${u.htmlFor}`,tabIndex:-1},...Array.from(u.childNodes))),b(u.firstElementChild,"click").pipe(Q(c),L(p=>!(p.metaKey||p.ctrlKey)),$(p=>{p.preventDefault(),p.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${u.htmlFor}`),u.click()})}return X("content.tabs.link")&&s.pipe(ke(1),pe(t)).subscribe(([{active:l},{offset:u}])=>{let p=l.innerText.trim();if(l.hasAttribute("data-md-switching"))l.removeAttribute("data-md-switching");else{let d=e.offsetTop-u.y;for(let h of P("[data-tabs]"))for(let v of P(":scope > input",h)){let x=G(`label[for="${v.id}"]`);if(x!==l&&x.innerText.trim()===p){x.setAttribute("data-md-switching",""),v.click();break}}window.scrollTo({top:e.offsetTop-d});let m=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([p,...m])])}}),s.pipe(Q(c)).subscribe(()=>{for(let l of P("audio, video",e))l.offsetWidth&&l.autoplay?l.play().catch(()=>{}):l.pause()}),mp(o).pipe($(l=>s.next(l)),V(()=>s.complete()),f(l=>H({ref:e},l)))}).pipe(Ht(ge))}function js(e,t){let{viewport$:r,target$:n,print$:o}=t;return R(...P(".annotate:not(.highlight)",e).map(i=>Es(i,{target$:n,print$:o})),...P("pre:not(.mermaid) > code",e).map(i=>Ls(i,{target$:n,print$:o})),...P("a",e).map(i=>Cs(i,t)),...P("pre.mermaid",e).map(i=>$s(i)),...P("table:not([class])",e).map(i=>Is(i)),...P("details",e).map(i=>Ms(i,{target$:n,print$:o})),...P("[data-tabs]",e).map(i=>Rs(i,{viewport$:r,target$:n})),...P("[title]:not([data-preview])",e).filter(()=>X("content.tooltips")).map(i=>Ge(i,{viewport$:r})),...P(".footnote-ref",e).filter(()=>X("content.footnote.tooltips")).map(i=>Rr(i,{content$:new U(a=>{let s=new URL(i.href).hash.slice(1),c=Array.from(document.getElementById(s).cloneNode(!0).children),l=On(...c);return a.next(l),document.body.append(l),()=>l.remove()}),viewport$:r})))}function dp(e,{alert$:t}){return t.pipe(g(r=>R(Y(!0),Y(!1).pipe(It(2e3))).pipe(f(n=>({message:r,active:n})))))}function Fs(e,t){let r=G(".md-typeset",e);return j(()=>{let n=new I;return n.subscribe(({message:o,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=o}),dp(e,t).pipe($(o=>n.next(o)),V(()=>n.complete()),f(o=>H({ref:e},o)))})}function hp({viewport$:e}){if(!X("header.autohide"))return Y(!1);let t=e.pipe(f(({offset:{y:o}})=>o),Pt(2,1),f(([o,i])=>[oMath.abs(i-o.y)>100),f(([,[o]])=>o),ie()),n=Tn("search");return re([e,n]).pipe(f(([{offset:o},i])=>o.y>400&&!i),ie(),g(o=>o?r:Y(!1)),J(!1))}function Us(e,t){return j(()=>re([Re(e),hp(t)])).pipe(f(([{height:r},n])=>({height:r,hidden:n})),ie((r,n)=>r.height===n.height&&r.hidden===n.hidden),se(1))}function Ns(e,{viewport$:t,header$:r,main$:n}){return j(()=>{let o=new I,i=o.pipe(he(),ye(!0));o.pipe(fe("active"),Ze(r)).subscribe(([{active:s},{hidden:c}])=>{e.classList.toggle("md-header--shadow",s&&!c),e.hidden=c});let a=me(P("[title]",e)).pipe(L(()=>X("content.tooltips")),oe(s=>Ge(s,{viewport$:t})));return n.subscribe(o),r.pipe(Q(i),f(s=>H({ref:e},s)),Rt(a.pipe(Q(i))))})}function vp(e,{viewport$:t,header$:r}){return Sn(e,{viewport$:t,header$:r}).pipe(f(({offset:{y:n}})=>{let{height:o}=Ae(e);return{active:o>0&&n>=o}}),fe("active"))}function Ds(e,t){return j(()=>{let r=new I;r.subscribe({next({active:o}){e.classList.toggle("md-header__title--active",o)},complete(){e.classList.remove("md-header__title--active")}});let n=we(".md-content h1");return typeof n=="undefined"?y:vp(n,t).pipe($(o=>r.next(o)),V(()=>r.complete()),f(o=>H({ref:e},o)))})}function Ws(e,{viewport$:t,header$:r}){let n=r.pipe(f(({height:i})=>i),ie()),o=n.pipe(g(()=>Re(e).pipe(f(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),fe("bottom"))));return re([n,o,t]).pipe(f(([i,{top:a,bottom:s},{offset:{y:c},size:{height:l}}])=>(l=Math.max(0,l-Math.max(0,a-c,i)-Math.max(0,l+c-s)),{offset:a-i,height:l,active:a-i<=c})),ie((i,a)=>i.offset===a.offset&&i.height===a.height&&i.active===a.active))}function bp(e){let t=__md_get("__palette")||{index:e.findIndex(n=>matchMedia(n.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return Y(...e).pipe(oe(n=>b(n,"change").pipe(f(()=>n))),J(e[r]),f(n=>({index:e.indexOf(n),color:{media:n.getAttribute("data-md-color-media"),scheme:n.getAttribute("data-md-color-scheme"),primary:n.getAttribute("data-md-color-primary"),accent:n.getAttribute("data-md-color-accent")}})),se(1))}function Vs(e){let t=P("input",e),r=A("meta",{name:"theme-color"});document.head.appendChild(r);let n=A("meta",{name:"color-scheme"});document.head.appendChild(n);let o=Ir("(prefers-color-scheme: light)");return j(()=>{let i=new I;return i.subscribe(a=>{if(document.body.setAttribute("data-md-color-switching",""),a.color.media==="(prefers-color-scheme)"){let s=matchMedia("(prefers-color-scheme: light)"),c=document.querySelector(s.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");a.color.scheme=c.getAttribute("data-md-color-scheme"),a.color.primary=c.getAttribute("data-md-color-primary"),a.color.accent=c.getAttribute("data-md-color-accent")}for(let[s,c]of Object.entries(a.color))document.body.setAttribute(`data-md-color-${s}`,c);for(let s=0;sa.key==="Enter"),pe(i,(a,s)=>s)).subscribe(({index:a})=>{a=(a+1)%t.length,t[a].click(),t[a].focus()}),i.pipe(f(()=>{let a=ht("header"),s=window.getComputedStyle(a);return n.content=s.colorScheme,s.backgroundColor.match(/\d+/g).map(c=>(+c).toString(16).padStart(2,"0")).join("")})).subscribe(a=>r.content=`#${a}`),i.pipe(Ie(ge)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),bp(t).pipe(Q(o.pipe(ke(1))),jt(),$(a=>i.next(a)),V(()=>i.complete()),f(a=>H({ref:e},a)))})}function zs(e,{progress$:t}){return j(()=>{let r=new I;return r.subscribe(({value:n})=>{e.style.setProperty("--md-progress-value",`${n}`)}),t.pipe($(n=>r.next({value:n})),V(()=>r.complete()),f(n=>({ref:e,value:n})))})}var qs='.v u{text-decoration:underline!important;text-decoration-style:wavy!important;text-decoration-thickness:1px!important}.p{-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);background-color:rgba(var(--color-backdrop)/var(--alpha-lighter));cursor:pointer;height:100%;pointer-events:auto;position:absolute;transition:opacity .25s;width:100%}.p.m{opacity:0;pointer-events:none;transition:opacity .35s}.r{align-items:center;background-color:initial;border:none;border-radius:var(--space-2);cursor:pointer;display:flex;flex-shrink:0;font-family:var(--font-family);height:36px;justify-content:center;outline:none;padding:0;position:relative;transition:background-color .25s,color .25s;width:36px;z-index:1}.r svg{stroke:rgb(var(--color-foreground));height:18px;opacity:.5;width:18px}.r:before{background-color:rgb(var(--color-background-subtle));border-radius:var(--border-radius-2);content:"";inset:0;opacity:0;position:absolute;transform:scale(.75);transition:transform 125ms,opacity 125ms;z-index:0}.r:hover:before{opacity:1;transform:scale(1)}.r.c{cursor:auto}.r.c:before{display:none}.n{-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);background-color:rgba(var(--color-background)/var(--alpha-light));border-radius:var(--space-3);box-shadow:0 0 60px #0000000d;display:flex;height:480px;overflow:hidden;pointer-events:auto;position:absolute;transition:transform .25s cubic-bezier(.16,1,.3,1),opacity .25s;width:640px}.n.l{opacity:0;pointer-events:none;transform:scale(1.1);transition:transform .25s .15s,opacity .15s}@media (max-width:680px){.n{border-radius:0;height:100%;width:100%}}.u{display:flex;flex-basis:min-content;flex-direction:column;flex-grow:1;flex-shrink:0}@keyframes d{0%{transform:scale(0)}50%{transform:scale(1.2)}to{transform:scale(1)}}.y{animation:d .25s ease-in-out;background:var(--color-highlight);border-radius:100%;color:#fff;font-size:8px;font-weight:700;height:12px;padding-top:1px;position:absolute;right:4px;top:4px;width:12px}.i{background-color:rgb(var(--color-background-subtle)/var(--alpha-lighter));flex-shrink:0;overflow:scroll;position:relative;transition:width .35s cubic-bezier(.16,1,.3,1),opacity .25s;width:200px}.i>*{transform:translate(0);transition:transform .25s cubic-bezier(.16,1,.3,1)}.i.l{opacity:0;width:0}.i.l>*{transform:translate(-48px)}@media (max-width:680px){.i{-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);background-color:rgba(var(--color-background-subtle)/var(--alpha-light));box-shadow:0 0 60px #00000026;height:100%;position:absolute;right:0;top:0}}.w{border-bottom:1px solid rgb(var(--color-foreground)/var(--alpha-lightest));display:flex;gap:var(--space-1);padding:var(--space-2)}.k{-webkit-overflow-scrolling:touch;overflow:auto;overscroll-behavior:contain}.z{padding:8px 10px}.X{color:rgb(var(--color-foreground)/var(--alpha-light));padding:var(--space-2);position:absolute;width:200px}.X,.j{display:flex;flex-direction:column}.j{gap:2px;list-style:none;padding:0}.F,.j{margin:0}.F{font-size:16px;font-weight:400}.F,.I{padding:8px}.I{font-size:14px;margin:4px 0 0;opacity:.5}.I,.o{font-size:12px}.o{cursor:pointer;display:flex;padding:4px 8px;position:relative}.o:before{background-color:var(--color-highlight-transparent);border-radius:var(--space-1);content:"";inset:0;opacity:0;position:absolute;transform:scale(.75);transition:transform 125ms,opacity 125ms;z-index:0}.o.g:before,.o:hover:before{opacity:1;transform:scale(1)}.o.g,.o:hover{color:var(--color-highlight)}.R{flex-grow:1}.R,.q{position:relative}.q{font-weight:700}.f{flex-grow:1}.f input{background:#0000;border:none;color:rgb(var(--color-foreground));font-family:var(--font-family);font-size:16px;height:100%;letter-spacing:-.25px;outline:none;width:100%}.b{color:rgb(var(--color-foreground)/var(--alpha-light));display:flex;flex-direction:column;gap:2px;line-height:1.3;list-style:none;margin:var(--space-2);margin-top:0;padding:0}.A,.b li{margin:0}.A{color:rgb(var(--color-foreground)/var(--alpha-lighter));font-size:12px;margin-top:var(--space-2);padding:0 18px}.a{border-radius:var(--space-2);color:inherit;cursor:pointer;display:flex;flex-direction:row;flex-grow:1;padding:8px 10px;position:relative;text-decoration:none}.a:before{background-color:rgb(var(--color-background-subtle));border-radius:var(--border-radius-2);content:"";display:block;inset:0;opacity:0;position:absolute;transform:scale(.9);transition:transform 125ms,opacity 125ms;z-index:0}@media (pointer:fine){.a.h:before,.a:hover:before{opacity:1;transform:scale(1)}}.a mark{background:#0000;color:var(--color-highlight)}.a u{background-color:var(--color-highlight-transparent);border-radius:2px;box-shadow:0 0 0 1px var(--color-highlight-transparent);text-decoration:none}.B{flex-grow:1}.s{margin-right:-8px;opacity:0;position:relative;transform:translate(-2px);transition:transform 125ms,opacity 125ms;z-index:0}@media (pointer:fine){.h>.s,:hover>.s{opacity:1;transform:none}}.x{font-size:14px;margin:0;position:relative}.x code{background:rgb(var(--color-background-subtle));border-radius:var(--space-1);font-size:13px;padding:2px 4px}.t{color:rgb(var(--color-foreground)/var(--alpha-lighter));display:inline-flex;flex-wrap:wrap;font-size:12px;gap:var(--space-1);list-style:none;margin:0;padding:0;position:relative}.t li{white-space:nowrap}.t li:after{content:"/";display:inline;margin-left:var(--space-1)}.t li:last-child:after{content:"";display:none}.e{--space-1:4px;--space-2:calc(var(--space-1)*2);--space-3:calc(var(--space-2)*2);--space-4:calc(var(--space-3)*2);--space-5:calc(var(--space-4)*2);--alpha-light:.7;--alpha-lighter:.54;--alpha-lightest:.1;--color-highlight:var(--md-accent-fg-color,#526cfe);--color-highlight-transparent:var(--md-accent-fg-color--transparent,#526cfe1a);--border-radius-1:var(--space-1);--border-radius-2:var(--space-2);--border-radius-3:calc(var(--space-1) + var(--space-2));--font-family:var(--md-text-font-family,Inter,Roboto Flex,system-ui,sans-serif);--font-size:16px;--line-height:1.5;--letter-spacing:-.5px;-webkit-font-smoothing:antialiased;align-items:center;display:flex;font-family:var(--font-family);font-size:var(--font-size);height:100vh;justify-content:center;letter-spacing:var(--letter-spacing);line-height:var(--line-height);pointer-events:none;position:absolute;width:100vw}@media (pointer:coarse){.e{height:-webkit-fill-available}}.e *,.e :after,.e :before{box-sizing:border-box}';function Ks(e,{index$:t}){let r=Ue(),n=document.createElement("div");document.body.appendChild(n),n.style.position="fixed",n.style.height="100%",n.style.top="0",n.style.zIndex="4";let o=n.attachShadow({mode:"open"});o.appendChild(A("style",{},qs.toString()));try{Ya(r.search,{highlight:r.features.includes("search.highlight")}),me(t).subscribe(i=>{for(let a of i.items)a.location=new URL(a.location,r.base).toString();Ja(i,o)}),b(e,"click").subscribe(()=>{go()}),Tn("search").pipe(ke(1)).subscribe(()=>go())}catch(i){e.hidden=!0;let a=G("label[for=__search]");a.hidden=!0}return Ke}var Bs=_r(So());function Ys(e,{index$:t,location$:r}){return re([t,r.pipe(J(Ye()),L(n=>!!n.searchParams.get("h")))]).pipe(f(([n,o])=>_p(n.config)(o.searchParams.get("h"))),f(n=>{var a;let o=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let s=i.nextNode();s;s=i.nextNode())if((a=s.parentElement)!=null&&a.offsetHeight){let c=s.textContent,l=n(c);l.length>c.length&&o.set(s,l)}for(let[s,c]of o){let{childNodes:l}=A("span",null,c);s.replaceWith(...Array.from(l))}return{ref:e,nodes:o}}))}function _p(e){let t=e.separator.split("|").map(o=>o.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":o).join("|"),r=new RegExp(t,"img"),n=(o,i,a)=>`${i}${a}`;return o=>{o=o.replace(/\s+/g," ").replace(/&/g,"&").trim();let i=new RegExp(`(^|${e.separator}|)(${o.split(r).map(a=>a.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&")).filter(a=>a.length>0).join("|")})`,"img");return a=>(0,Bs.default)(a).replace(i,n).replace(/<\/mark>(\s+)]*>/img,"$1")}}function yp(e,{viewport$:t,main$:r}){let n=e.closest(".md-grid"),o=n.offsetTop-n.parentElement.offsetTop;return re([r,t]).pipe(f(([{offset:i,height:a},{offset:{y:s}}])=>(a=a+Math.min(o,Math.max(0,s-i))-o,{height:a,locked:s>=i+o})),ie((i,a)=>i.height===a.height&&i.locked===a.locked))}function Ao(e,n){var o=n,{header$:t}=o,r=gr(o,["header$"]);let i=G(".md-sidebar__scrollwrap",e),{y:a}=wt(i);return j(()=>{let s=new I,c=s.pipe(he(),ye(!0)),l=s.pipe(Xe(0,je));return l.pipe(pe(t)).subscribe({next([{height:u},{height:p}]){i.style.height=`${u-2*a}px`,e.style.top=`${p}px`},complete(){i.style.height="",e.style.top=""}}),l.pipe(Sr()).subscribe(()=>{for(let u of P(".md-nav__link--active[href]",e)){if(!u.clientHeight)continue;let p=u.closest(".md-sidebar__scrollwrap");if(typeof p!="undefined"){let d=u.offsetTop-p.offsetTop,{height:m}=Ae(p);p.scrollTo({top:d-m/2})}}}),me(P("label[tabindex]",e)).pipe(oe(u=>b(u,"click").pipe(Ie(ge),f(()=>u),Q(c)))).subscribe(u=>{let p=G(`[id="${u.htmlFor}"]`);G(`[aria-labelledby="${u.id}"]`).setAttribute("aria-expanded",`${p.checked}`)}),X("content.tooltips")&&me(P("abbr[title]",e)).pipe(oe(u=>Ge(u,{viewport$})),Q(c)).subscribe(),yp(e,r).pipe($(u=>s.next(u)),V(()=>s.complete()),f(u=>H({ref:e},u)))})}function Gs(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return $t(et(`${r}/releases/latest`).pipe(_e(()=>y),f(n=>({version:n.tag_name})),ot({})),et(r).pipe(_e(()=>y),f(n=>({stars:n.stargazers_count,forks:n.forks_count})),ot({}))).pipe(f(([n,o])=>H(H({},n),o)))}else{let r=`https://api.github.com/users/${e}`;return et(r).pipe(f(n=>({repositories:n.public_repos})),ot({}))}}function Js(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return $t(et(`${r}/releases/permalink/latest`).pipe(_e(()=>y),f(({tag_name:n})=>({version:n})),ot({})),et(r).pipe(_e(()=>y),f(({star_count:n,forks_count:o})=>({stars:n,forks:o})),ot({}))).pipe(f(([n,o])=>H(H({},n),o)))}function Xs(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,n]=t;return Gs(r,n)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,n]=t;return Js(r,n)}return y}var xp;function wp(e){return xp||(xp=j(()=>{let t=__md_get("__source",sessionStorage);if(t)return Y(t);if(Te("consent").length){let n=__md_get("__consent");if(!(n&&n.github))return y}return Xs(e.href).pipe($(n=>__md_set("__source",n,sessionStorage)))}).pipe(_e(()=>y),L(t=>Object.keys(t).length>0),f(t=>({facts:t})),se(1)))}function Zs(e){let t=G(":scope > :last-child",e);return j(()=>{let r=new I;return r.subscribe(({facts:n})=>{t.appendChild(bs(n)),t.classList.add("md-source__repository--active")}),wp(e).pipe($(n=>r.next(n)),V(()=>r.complete()),f(n=>H({ref:e},n)))})}function Ep(e,{viewport$:t,header$:r}){return Re(document.body).pipe(g(()=>Sn(e,{header$:r,viewport$:t})),f(({offset:{y:n}})=>({hidden:n>=10})),fe("hidden"))}function Qs(e,t){return j(()=>{let r=new I;return r.subscribe({next({hidden:n}){e.hidden=n},complete(){e.hidden=!1}}),(X("navigation.tabs.sticky")?Y({hidden:!1}):Ep(e,t)).pipe($(n=>r.next(n)),V(()=>r.complete()),f(n=>H({ref:e},n)))})}function Tp(e,{viewport$:t,header$:r}){let n=new Map,o=P(".md-nav__link",e);for(let s of o){let c=decodeURIComponent(s.hash.substring(1)),l=we(`[id="${c}"]`);typeof l!="undefined"&&n.set(s,l)}let i=r.pipe(fe("height"),f(({height:s})=>{let c=ht("main"),l=G(":scope > :first-child",c);return s+.9*(l.offsetTop-c.offsetTop)}),xe());return Re(document.body).pipe(fe("height"),g(s=>j(()=>{let c=[];return Y([...n].reduce((l,[u,p])=>{for(;c.length&&n.get(c[c.length-1]).tagName>=p.tagName;)c.pop();let d=p.offsetTop;for(;!d&&p.parentElement;)p=p.parentElement,d=p.offsetTop;let m=p.offsetParent;for(;m;m=m.offsetParent)d+=m.offsetTop;return l.set([...c=[...c,u]].reverse(),d)},new Map))}).pipe(f(c=>new Map([...c].sort(([,l],[,u])=>l-u))),Ze(i),g(([c,l])=>t.pipe(Or(([u,p],{offset:{y:d},size:m})=>{let h=d+m.height>=Math.floor(s.height);for(;p.length;){let[,v]=p[0];if(v-l=d&&!h)p=[u.pop(),...p];else break}return[u,p]},[[],[...c]]),ie((u,p)=>u[0]===p[0]&&u[1]===p[1])))))).pipe(f(([s,c])=>({prev:s.map(([l])=>l),next:c.map(([l])=>l)})),J({prev:[],next:[]}),Pt(2,1),f(([s,c])=>s.prev.length{let i=new I,a=i.pipe(he(),ye(!0));i.subscribe(({prev:c,next:l})=>{for(let[u]of l)u.classList.remove("md-nav__link--passed"),u.classList.remove("md-nav__link--active");for(let[u,[p]]of c.entries())p.classList.add("md-nav__link--passed"),p.classList.toggle("md-nav__link--active",u===c.length-1)});let s=we(".md-sidebar--secondary");if(typeof s!="undefined"&&b(document.body,"click").subscribe(c=>{let l=c.target;if(!s.contains(l)){let u=we(".md-nav__toggle",s);typeof u!="undefined"&&(u.checked=!1)}}),X("toc.follow")){let c=R(t.pipe(Be(1),f(()=>{})),t.pipe(Be(250),f(()=>"smooth")));i.pipe(L(({prev:l})=>l.length>0),Ze(n.pipe(Ie(ge))),pe(c)).subscribe(([[{prev:l}],u])=>{let[p]=l[l.length-1];if(p.offsetHeight){let d=ki(p);if(typeof d!="undefined"){let m=p.offsetTop-d.offsetTop,{height:h}=Ae(d);d.scrollTo({top:m-h/2,behavior:u})}}})}return X("navigation.tracking")&&t.pipe(Q(a),fe("offset"),Be(250),ke(1),Q(o.pipe(ke(1))),jt({delay:250}),pe(i)).subscribe(([,{prev:c}])=>{let l=Ye(),u=c[c.length-1];if(u&&u.length){let[p]=u,{hash:d}=new URL(p.href);l.hash!==d&&(l.hash=d,history.replaceState({},"",`${l}`))}else l.hash="",history.replaceState({},"",`${l}`)}),Tp(e,{viewport$:t,header$:r}).pipe($(c=>i.next(c)),V(()=>i.complete()),f(c=>H({ref:e},c)))})}function Sp(e,{viewport$:t,main$:r,target$:n}){let o=t.pipe(f(({offset:{y:a}})=>a),Pt(2,1),f(([a,s])=>a>s&&s>0),ie()),i=r.pipe(f(({active:a})=>a));return re([i,o]).pipe(f(([a,s])=>!(a&&s)),ie(),Q(n.pipe(ke(1))),ye(!0),jt({delay:250}),f(a=>({hidden:a})))}function tc(e,{viewport$:t,header$:r,main$:n,target$:o}){let i=new I,a=i.pipe(he(),ye(!0));return i.subscribe({next({hidden:s}){e.hidden=s,s?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(Q(a),fe("height")).subscribe(({height:s})=>{e.style.top=`${s+16}px`}),b(e,"click").subscribe(s=>{s.preventDefault(),window.scrollTo({top:0})}),Sp(e,{viewport$:t,main$:n,target$:o}).pipe($(s=>i.next(s)),V(()=>i.complete()),f(s=>H({ref:e},s)))}function rc(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,t.port&&(e.port=t.port),e}function Op(e,t){let r=new Map;for(let n of P("url",e)){let o=G("loc",n),i=[rc(new URL(o.textContent),t)];r.set(`${i[0]}`,i);for(let a of P("[rel=alternate]",n)){let s=a.getAttribute("href");s!=null&&i.push(rc(new URL(s),t))}}return r}function dr(e){return ns(new URL("sitemap.xml",e)).pipe(f(t=>Op(t,new URL(e))),_e(()=>Y(new Map)),xe())}function nc({document$:e}){let t=new Map;e.pipe(g(()=>P("link[rel=alternate]")),f(r=>new URL(r.href)),L(r=>!t.has(r.toString())),oe(r=>dr(r).pipe(f(n=>[r,n]),_e(()=>y)))).subscribe(([r,n])=>{t.set(r.toString().replace(/\/$/,""),n)}),b(document.body,"click").pipe(L(r=>!r.metaKey&&!r.ctrlKey),g(r=>{if(r.target instanceof Element){let n=r.target.closest("a");if(n&&!n.target){let o=[...t].find(([p])=>n.href.startsWith(`${p}/`));if(typeof o=="undefined")return y;let[i,a]=o,s=Ye();if(s.href.startsWith(i))return y;let c=Ue(),l=s.href.replace(c.base,"");l=`${i}/${l}`;let u=a.has(l.split("#")[0])?new URL(l,c.base):new URL(i);return r.preventDefault(),Y(u)}}return y})).subscribe(r=>dt(r,!0))}var Co=_r(Mo());function Lp(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function oc({alert$:e}){Co.default.isSupported()&&new U(t=>{new Co.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||Lp(G(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe($(t=>{t.trigger.focus()}),f(()=>Bt("clipboard.copied"))).subscribe(e)}function ic(e,t){if(!(e.target instanceof Element))return y;let r=e.target.closest("a");if(r===null)return y;if(r.target||e.metaKey||e.ctrlKey)return y;let n=new URL(r.href);return n.search=n.hash="",t.has(`${n}`)?(e.preventDefault(),Y(r)):y}function ac(e){let t=new Map;for(let r of P(":scope > *",e.head))t.set(r.outerHTML,r);return t}function sc(e){for(let t of P("[href], [src]",e))for(let r of["href","src"]){let n=t.getAttribute(r);if(n&&!/^(?:[a-z]+:)?\/\//i.test(n)){t[r]=t[r];break}}return Y(e)}function Mp(e){for(let n of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...X("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let o=we(n),i=we(n,e);typeof o!="undefined"&&typeof i!="undefined"&&o.replaceWith(i)}let t=ac(document);for(let[n,o]of ac(e))t.has(n)?t.delete(n):document.head.appendChild(o);for(let n of t.values()){let o=n.getAttribute("name");o!=="theme-color"&&o!=="color-scheme"&&n.remove()}let r=ht("container");return nt(P("script",r)).pipe(g(n=>{let o=e.createElement("script");if(n.src){for(let i of n.getAttributeNames())o.setAttribute(i,n.getAttribute(i));return n.replaceWith(o),new U(i=>{o.onload=()=>i.complete()})}else return o.textContent=n.textContent,n.replaceWith(o),y}),he(),ye(document))}function cc({sitemap$:e,location$:t,viewport$:r,progress$:n}){if(location.protocol==="file:")return Ke;Y(document).subscribe(sc);let o=b(document.body,"click").pipe(Ze(e),g(([s,c])=>ic(s,c)),f(({href:s})=>new URL(s)),xe()),i=b(window,"popstate").pipe(f(Ye),xe());o.pipe(pe(r)).subscribe(([s,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",s)}),R(o,i).subscribe(t);let a=t.pipe(fe("pathname"),g(s=>En(s,{progress$:n}).pipe(_e(()=>(dt(s,!0),y)))),g(sc),g(Mp),xe());return R(a.pipe(pe(t,(s,c)=>c)),a.pipe(g(()=>t),fe("hash")),t.pipe(ie((s,c)=>s.pathname===c.pathname&&s.hash===c.hash),g(()=>o),$(()=>history.back()))).subscribe(s=>{var c,l;history.state!==null||!s.hash?window.scrollTo(0,(l=(c=history.state)==null?void 0:c.y)!=null?l:0):(history.scrollRestoration="auto",es(s.hash),history.scrollRestoration="manual")}),t.subscribe(()=>{history.scrollRestoration="manual"}),b(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),r.pipe(fe("offset"),Be(100)).subscribe(({offset:s})=>{history.replaceState(s,"")}),X("navigation.instant.prefetch")&&R(b(document.body,"mousemove"),b(document.body,"focusin")).pipe(Ze(e),g(([s,c])=>ic(s,c)),Be(25),Yn(({href:s})=>s),cn(s=>{let c=document.createElement("link");return c.rel="prefetch",c.href=s.toString(),document.head.appendChild(c),b(c,"load").pipe(f(()=>c),Me(1))})).subscribe(s=>s.remove()),a}function lc(e){var u;let{selectedVersionSitemap:t,selectedVersionBaseURL:r,currentLocation:n,currentBaseURL:o}=e,i=(u=Ho(o))==null?void 0:u.pathname;if(i===void 0)return;let a=kp(n.pathname,i);if(a===void 0)return;let s=Cp(t.keys());if(!t.has(s))return;let c=Ho(a,s);if(!c||!t.has(c.href))return;let l=Ho(a,r);if(l)return l.hash=n.hash,l.search=n.search,l}function Ho(e,t){try{return new URL(e,t)}catch(r){return}}function kp(e,t){if(e.startsWith(t))return e.slice(t.length)}function Ap(e,t){let r=Math.min(e.length,t.length),n;for(n=0;ny)),n=r.pipe(f(o=>{let[,i]=t.base.match(/([^/]+)\/?$/);return o.find(({version:a,aliases:s})=>a===i||s.includes(i))||o[0]}));r.pipe(f(o=>new Map(o.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),g(o=>b(document.body,"click").pipe(L(i=>!i.metaKey&&!i.ctrlKey),pe(n),g(([i,a])=>{if(i.target instanceof Element){let s=i.target.closest("a");if(s&&!s.target&&o.has(s.href)){let c=s.href;return!i.target.closest(".md-version")&&o.get(c)===a?y:(i.preventDefault(),Y(new URL(c)))}}return y}),g(i=>dr(i).pipe(f(a=>{var s;return(s=lc({selectedVersionSitemap:a,selectedVersionBaseURL:i,currentLocation:Ye(),currentBaseURL:t.base}))!=null?s:i})))))).subscribe(o=>dt(o,!0)),re([r,n]).subscribe(([o,i])=>{G(".md-header__topic").appendChild(_s(o,i))}),e.pipe(g(()=>n)).subscribe(o=>{var s;let i=new URL(t.base),a=__md_get("__outdated",sessionStorage,i);if(a===null){a=!0;let c=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(c)||(c=[c]);e:for(let l of c)for(let u of o.aliases.concat(o.version))if(new RegExp(l,"i").test(u)){a=!1;break e}__md_set("__outdated",a,sessionStorage,i)}if(a)for(let c of Te("outdated"))c.hidden=!1})}function pc({document$:e,viewport$:t}){e.pipe(g(()=>P(".md-ellipsis")),oe(r=>Et(r).pipe(Q(e.pipe(ke(1))),L(n=>n),f(()=>r),Me(1))),L(r=>r.offsetWidth{let n=r.innerText,o=r.closest("a")||r;return o.title=n,X("content.tooltips")?Ge(o,{viewport$:t}).pipe(Q(e.pipe(ke(1))),V(()=>o.removeAttribute("title"))):y})).subscribe(),X("content.tooltips")&&e.pipe(g(()=>P(".md-status")),oe(r=>Ge(r,{viewport$:t}))).subscribe()}function fc({document$:e,tablet$:t}){e.pipe(g(()=>P(".md-toggle--indeterminate")),$(r=>{r.indeterminate=!0,r.checked=!1}),oe(r=>b(r,"change").pipe(Xn(()=>r.classList.contains("md-toggle--indeterminate")),f(()=>r))),pe(t)).subscribe(([r,n])=>{r.classList.remove("md-toggle--indeterminate"),n&&(r.checked=!1)})}function Hp(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function mc({document$:e}){e.pipe(g(()=>P("[data-md-scrollfix]")),$(t=>t.removeAttribute("data-md-scrollfix")),L(Hp),oe(t=>b(t,"touchstart").pipe(f(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let n=e[r];typeof n=="string"?n=document.createTextNode(n):n.parentNode&&n.parentNode.removeChild(n),r?t.insertBefore(this.previousSibling,n):t.replaceChild(n,this)}}}));function $p(){return location.protocol==="file:"?ar(`${new URL("search.js",Mn.base)}`).pipe(f(()=>__index),_e(()=>Ke),se(1)):et(new URL("search.json",Mn.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var vt=Si(),Ur=Za(),hr=ts(Ur),hc=Xa(),ze=cs(),$o=Ir("(min-width: 60em)"),vc=Ir("(min-width: 76.25em)"),bc=rs(),Mn=Ue(),gc=we(".md-search")?$p():Ke,Po=new I;oc({alert$:Po});nc({document$:vt});var Io=new I,_c=dr(Mn.base);X("navigation.instant")&&cc({sitemap$:_c,location$:Ur,viewport$:ze,progress$:Io}).subscribe(vt);var dc;((dc=Mn.version)==null?void 0:dc.provider)==="mike"&&uc({document$:vt});R(Ur,hr).pipe(It(125)).subscribe(()=>{Eo("drawer",!1),Eo("search",!1)});hc.pipe(L(({mode:e,meta:t})=>e==="global"&&!t)).subscribe(e=>{switch(e.type){case",":case"p":let t=document.querySelector("link[rel=prev]");t instanceof HTMLLinkElement&&dt(t);break;case".":case"n":let r=document.querySelector("link[rel=next]");r instanceof HTMLLinkElement&&dt(r);break;case"/":let n=document.querySelector("[data-md-component=search] button");n instanceof HTMLButtonElement&&n.click();break;case"Enter":let o=xt();o instanceof HTMLLabelElement&&o.click()}});pc({viewport$:ze,document$:vt});fc({document$:vt,tablet$:$o});mc({document$:vt});var Lt=Us(ht("header"),{viewport$:ze}),Fr=vt.pipe(f(()=>ht("main")),g(e=>Ws(e,{viewport$:ze,header$:Lt})),se(1)),Pp=R(...Te("consent").map(e=>us(e,{target$:hr})),...Te("dialog").map(e=>Fs(e,{alert$:Po})),...Te("palette").map(e=>Vs(e)),...Te("progress").map(e=>zs(e,{progress$:Io})),...Te("search").map(e=>Ks(e,{index$:gc})),...Te("source").map(e=>Zs(e))),Ip=j(()=>R(...Te("announce").map(e=>ls(e)),...Te("content").map(e=>js(e,{sitemap$:_c,viewport$:ze,target$:hr,print$:bc})),...Te("content").map(e=>X("search.highlight")?Ys(e,{index$:gc,location$:Ur}):y),...Te("header").map(e=>Ns(e,{viewport$:ze,header$:Lt,main$:Fr})),...Te("header-title").map(e=>Ds(e,{viewport$:ze,header$:Lt})),...Te("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?yo(vc,()=>Ao(e,{viewport$:ze,header$:Lt,main$:Fr})):yo($o,()=>Ao(e,{viewport$:ze,header$:Lt,main$:Fr}))),...Te("tabs").map(e=>Qs(e,{viewport$:ze,header$:Lt})),...Te("toc").map(e=>ec(e,{viewport$:ze,header$:Lt,main$:Fr,target$:hr})),...Te("top").map(e=>tc(e,{viewport$:ze,header$:Lt,main$:Fr,target$:hr})))),yc=vt.pipe(g(()=>Ip),Rt(Pp),se(1));yc.subscribe();window.document$=vt;window.location$=Ur;window.target$=hr;window.keyboard$=hc;window.viewport$=ze;window.tablet$=$o;window.screen$=vc;window.print$=bc;window.alert$=Po;window.progress$=Io;window.component$=yc;})(); diff --git a/site/assets/javascripts/bundle.ee611ef6.min.js b/site/assets/javascripts/bundle.ee611ef6.min.js deleted file mode 100644 index 00471bcbd..000000000 --- a/site/assets/javascripts/bundle.ee611ef6.min.js +++ /dev/null @@ -1,3 +0,0 @@ -"use strict";(()=>{var Lc=Object.create;var Cn=Object.defineProperty,Mc=Object.defineProperties,kc=Object.getOwnPropertyDescriptor,Ac=Object.getOwnPropertyDescriptors,Cc=Object.getOwnPropertyNames,Dr=Object.getOwnPropertySymbols,Hc=Object.getPrototypeOf,Hn=Object.prototype.hasOwnProperty,jo=Object.prototype.propertyIsEnumerable;var Ro=(e,t,r)=>t in e?Cn(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,k=(e,t)=>{for(var r in t||(t={}))Hn.call(t,r)&&Ro(e,r,t[r]);if(Dr)for(var r of Dr(t))jo.call(t,r)&&Ro(e,r,t[r]);return e},He=(e,t)=>Mc(e,Ac(t));var gr=(e,t)=>{var r={};for(var n in e)Hn.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&Dr)for(var n of Dr(e))t.indexOf(n)<0&&jo.call(e,n)&&(r[n]=e[n]);return r};var $n=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(r){throw t=0,r}};var $c=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Cc(t))!Hn.call(e,o)&&o!==r&&Cn(e,o,{get:()=>t[o],enumerable:!(n=kc(t,o))||n.enumerable});return e};var _r=(e,t,r)=>(r=e!=null?Lc(Hc(e)):{},$c(t||!e||!e.__esModule?Cn(r,"default",{value:e,enumerable:!0}):r,e));var Fo=(e,t,r)=>new Promise((n,o)=>{var i=c=>{try{s(r.next(c))}catch(l){o(l)}},a=c=>{try{s(r.throw(c))}catch(l){o(l)}},s=c=>c.done?n(c.value):Promise.resolve(c.value).then(i,a);s((r=r.apply(e,t)).next())});var No=$n((Pn,Uo)=>{(function(e,t){typeof Pn=="object"&&typeof Uo!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Pn,(function(){"use strict";function e(r){var n=!0,o=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(_){return!!(_&&_!==document&&_.nodeName!=="HTML"&&_.nodeName!=="BODY"&&"classList"in _&&"contains"in _.classList)}function c(_){var Z=_.type,ve=_.tagName;return!!(ve==="INPUT"&&a[Z]&&!_.readOnly||ve==="TEXTAREA"&&!_.readOnly||_.isContentEditable)}function l(_){_.classList.contains("focus-visible")||(_.classList.add("focus-visible"),_.setAttribute("data-focus-visible-added",""))}function u(_){_.hasAttribute("data-focus-visible-added")&&(_.classList.remove("focus-visible"),_.removeAttribute("data-focus-visible-added"))}function p(_){_.metaKey||_.altKey||_.ctrlKey||(s(r.activeElement)&&l(r.activeElement),n=!0)}function d(_){n=!1}function m(_){s(_.target)&&(n||c(_.target))&&l(_.target)}function h(_){s(_.target)&&(_.target.classList.contains("focus-visible")||_.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(_.target))}function v(_){document.visibilityState==="hidden"&&(o&&(n=!0),y())}function y(){document.addEventListener("mousemove",E),document.addEventListener("mousedown",E),document.addEventListener("mouseup",E),document.addEventListener("pointermove",E),document.addEventListener("pointerdown",E),document.addEventListener("pointerup",E),document.addEventListener("touchmove",E),document.addEventListener("touchstart",E),document.addEventListener("touchend",E)}function x(){document.removeEventListener("mousemove",E),document.removeEventListener("mousedown",E),document.removeEventListener("mouseup",E),document.removeEventListener("pointermove",E),document.removeEventListener("pointerdown",E),document.removeEventListener("pointerup",E),document.removeEventListener("touchmove",E),document.removeEventListener("touchstart",E),document.removeEventListener("touchend",E)}function E(_){_.target.nodeName&&_.target.nodeName.toLowerCase()==="html"||(n=!1,x())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",d,!0),document.addEventListener("pointerdown",d,!0),document.addEventListener("touchstart",d,!0),document.addEventListener("visibilitychange",v,!0),y(),r.addEventListener("focus",m,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)}))});var To=$n((D0,ys)=>{"use strict";var rp=/["'&<>]/;ys.exports=np;function np(e){var t=""+e,r=rp.exec(t);if(!r)return t;var n,o="",i=0,a=0;for(i=r.index;i{(function(t,r){typeof jr=="object"&&typeof Oo=="object"?Oo.exports=r():typeof define=="function"&&define.amd?define([],r):typeof jr=="object"?jr.ClipboardJS=r():t.ClipboardJS=r()})(jr,function(){return(function(){var e={686:(function(n,o,i){"use strict";i.d(o,{default:function(){return vr}});var a=i(279),s=i.n(a),c=i(370),l=i.n(c),u=i(817),p=i.n(u);function d(G){try{return document.execCommand(G)}catch(H){return!1}}var m=function(H){var C=p()(H);return d("cut"),C},h=m;function v(G){var H=document.documentElement.getAttribute("dir")==="rtl",C=document.createElement("textarea");C.style.fontSize="12pt",C.style.border="0",C.style.padding="0",C.style.margin="0",C.style.position="absolute",C.style[H?"right":"left"]="-9999px";var W=window.pageYOffset||document.documentElement.scrollTop;return C.style.top="".concat(W,"px"),C.setAttribute("readonly",""),C.value=G,C}var y=function(H,C){var W=v(H);C.container.appendChild(W);var V=p()(W);return d("copy"),W.remove(),V},x=function(H){var C=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},W="";return typeof H=="string"?W=y(H,C):H instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(H==null?void 0:H.type)?W=y(H.value,C):(W=p()(H),d("copy")),W},E=x;function _(G){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?_=function(C){return typeof C}:_=function(C){return C&&typeof Symbol=="function"&&C.constructor===Symbol&&C!==Symbol.prototype?"symbol":typeof C},_(G)}var Z=function(){var H=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},C=H.action,W=C===void 0?"copy":C,V=H.container,Q=H.target,Ve=H.text;if(W!=="copy"&&W!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(Q!==void 0)if(Q&&_(Q)==="object"&&Q.nodeType===1){if(W==="copy"&&Q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(W==="cut"&&(Q.hasAttribute("readonly")||Q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Ve)return E(Ve,{container:V});if(Q)return W==="cut"?h(Q):E(Q,{container:V})},ve=Z;function L(G){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?L=function(C){return typeof C}:L=function(C){return C&&typeof Symbol=="function"&&C.constructor===Symbol&&C!==Symbol.prototype?"symbol":typeof C},L(G)}function M(G,H){if(!(G instanceof H))throw new TypeError("Cannot call a class as a function")}function D(G,H){for(var C=0;C0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof V.action=="function"?V.action:this.defaultAction,this.target=typeof V.target=="function"?V.target:this.defaultTarget,this.text=typeof V.text=="function"?V.text:this.defaultText,this.container=L(V.container)==="object"?V.container:document.body}},{key:"listenClick",value:function(V){var Q=this;this.listener=l()(V,"click",function(Ve){return Q.onClick(Ve)})}},{key:"onClick",value:function(V){var Q=V.delegateTarget||V.currentTarget,Ve=this.action(Q)||"copy",Jt=ve({action:Ve,container:this.container,target:this.target(Q),text:this.text(Q)});this.emit(Jt?"success":"error",{action:Ve,text:Jt,trigger:Q,clearSelection:function(){Q&&Q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(V){return Yt("action",V)}},{key:"defaultTarget",value:function(V){var Q=Yt("target",V);if(Q)return document.querySelector(Q)}},{key:"defaultText",value:function(V){return Yt("text",V)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(V){var Q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return E(V,Q)}},{key:"cut",value:function(V){return h(V)}},{key:"isSupported",value:function(){var V=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Q=typeof V=="string"?[V]:V,Ve=!!document.queryCommandSupported;return Q.forEach(function(Jt){Ve=Ve&&!!document.queryCommandSupported(Jt)}),Ve}}]),C})(s()),vr=At}),828:(function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,c){for(;s&&s.nodeType!==o;){if(typeof s.matches=="function"&&s.matches(c))return s;s=s.parentNode}}n.exports=a}),438:(function(n,o,i){var a=i(828);function s(u,p,d,m,h){var v=l.apply(this,arguments);return u.addEventListener(d,v,h),{destroy:function(){u.removeEventListener(d,v,h)}}}function c(u,p,d,m,h){return typeof u.addEventListener=="function"?s.apply(null,arguments):typeof d=="function"?s.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return s(v,p,d,m,h)}))}function l(u,p,d,m){return function(h){h.delegateTarget=a(h.target,p),h.delegateTarget&&m.call(u,h)}}n.exports=c}),879:(function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}}),370:(function(n,o,i){var a=i(879),s=i(438);function c(d,m,h){if(!d&&!m&&!h)throw new Error("Missing required arguments");if(!a.string(m))throw new TypeError("Second argument must be a String");if(!a.fn(h))throw new TypeError("Third argument must be a Function");if(a.node(d))return l(d,m,h);if(a.nodeList(d))return u(d,m,h);if(a.string(d))return p(d,m,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function l(d,m,h){return d.addEventListener(m,h),{destroy:function(){d.removeEventListener(m,h)}}}function u(d,m,h){return Array.prototype.forEach.call(d,function(v){v.addEventListener(m,h)}),{destroy:function(){Array.prototype.forEach.call(d,function(v){v.removeEventListener(m,h)})}}}function p(d,m,h){return s(document.body,d,m,h)}n.exports=c}),817:(function(n){function o(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),l=document.createRange();l.selectNodeContents(i),c.removeAllRanges(),c.addRange(l),a=c.toString()}return a}n.exports=o}),279:(function(n){function o(){}o.prototype={on:function(i,a,s){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var c=this;function l(){c.off(i,l),a.apply(s,arguments)}return l._=a,this.on(i,l,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),c=0,l=s.length;for(c;c0&&i[i.length-1])&&(l[0]===6||l[0]===2)){r=0;continue}if(l[0]===3&&(!i||l[1]>i[0]&&l[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function re(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],a;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(s){a={error:s}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(a)throw a.error}}return i}function oe(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||c(m,v)})},h&&(o[m]=h(o[m])))}function c(m,h){try{l(n[m](h))}catch(v){d(i[0][3],v)}}function l(m){m.value instanceof Ct?Promise.resolve(m.value.v).then(u,p):d(i[0][2],m)}function u(m){c("next",m)}function p(m){c("throw",m)}function d(m,h){m(h),i.shift(),i.length&&c(i[0][0],i[0][1])}}function Vo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof $e=="function"?$e(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(a){return new Promise(function(s,c){a=e[i](a),o(s,c,a.done,a.value)})}}function o(i,a,s,c){Promise.resolve(c).then(function(l){i({value:l,done:s})},a)}}function F(e){return typeof e=="function"}function Xt(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var Vr=Xt(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: -`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` - `):"",this.name="UnsubscriptionError",this.errors=r}});function ut(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var nt=(function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a)if(this._parentage=null,Array.isArray(a))try{for(var s=$e(a),c=s.next();!c.done;c=s.next()){var l=c.value;l.remove(this)}}catch(v){t={error:v}}finally{try{c&&!c.done&&(r=s.return)&&r.call(s)}finally{if(t)throw t.error}}else a.remove(this);var u=this.initialTeardown;if(F(u))try{u()}catch(v){i=v instanceof Vr?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var d=$e(p),m=d.next();!m.done;m=d.next()){var h=m.value;try{zo(h)}catch(v){i=i!=null?i:[],v instanceof Vr?i=oe(oe([],re(i)),re(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{m&&!m.done&&(o=d.return)&&o.call(d)}finally{if(n)throw n.error}}}if(i)throw new Vr(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)zo(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&ut(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&ut(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=(function(){var t=new e;return t.closed=!0,t})(),e})();var Rn=nt.EMPTY;function zr(e){return e instanceof nt||e&&"closed"in e&&F(e.remove)&&F(e.add)&&F(e.unsubscribe)}function zo(e){F(e)?e():e.unsubscribe()}var Xe={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var Zt={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,a=o.isStopped,s=o.observers;return i||a?Rn:(this.currentObservers=null,s.push(r),new nt(function(){n.currentObservers=null,ut(s,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,a=n.isStopped;o?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new N;return r.source=this,r},t.create=function(r,n){return new Zo(r,n)},t})(N);var Zo=(function(e){pe(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Rn},t})(I);var Dn=(function(e){pe(t,e);function t(r){var n=e.call(this)||this;return n._value=r,n}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var n=e.prototype._subscribe.call(this,r);return!n.closed&&r.next(this._value),n},t.prototype.getValue=function(){var r=this,n=r.hasError,o=r.thrownError,i=r._value;if(n)throw o;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t})(I);var xr={now:function(){return(xr.delegate||Date).now()},delegate:void 0};var wr=(function(e){pe(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=xr);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,a=n._infiniteTimeWindow,s=n._timestampProvider,c=n._windowTime;o||(i.push(r),!a&&i.push(s.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,a=o._buffer,s=a.slice(),c=0;c0?e.prototype.schedule.call(this,r,n):(this.delay=n,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,n){return n>0||this.closed?e.prototype.execute.call(this,r,n):this._execute(r,n)},t.prototype.requestAsyncId=function(r,n,o){return o===void 0&&(o=0),o!=null&&o>0||o==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,n,o):(r.flush(this),0)},t})(rr);var ti=(function(e){pe(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t})(nr);var zn=new ti(ei);var ri=(function(e){pe(t,e);function t(r,n){var o=e.call(this,r,n)||this;return o.scheduler=r,o.work=n,o}return t.prototype.requestAsyncId=function(r,n,o){return o===void 0&&(o=0),o!==null&&o>0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=tr.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var a=r.actions;n!=null&&n===r._scheduled&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==n&&(tr.cancelAnimationFrame(n),r._scheduled=void 0)},t})(rr);var ni=(function(e){pe(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n;r?n=r.id:(n=this._scheduled,this._scheduled=void 0);var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t})(nr);var je=new ni(ri);var w=new N(function(e){return e.complete()});function Br(e){return e&&F(e.schedule)}function qn(e){return e[e.length-1]}function _t(e){return F(qn(e))?e.pop():void 0}function Be(e){return Br(qn(e))?e.pop():void 0}function Gr(e,t){return typeof qn(e)=="number"?e.pop():t}var or=(function(e){return e&&typeof e.length=="number"&&typeof e!="function"});function Yr(e){return F(e==null?void 0:e.then)}function Jr(e){return F(e[er])}function Xr(e){return Symbol.asyncIterator&&F(e==null?void 0:e[Symbol.asyncIterator])}function Zr(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Wc(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Qr=Wc();function en(e){return F(e==null?void 0:e[Qr])}function tn(e){return Wo(this,arguments,function(){var r,n,o,i;return Wr(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,Ct(r.read())];case 3:return n=a.sent(),o=n.value,i=n.done,i?[4,Ct(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,Ct(o)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function rn(e){return F(e==null?void 0:e.getReader)}function q(e){if(e instanceof N)return e;if(e!=null){if(Jr(e))return Vc(e);if(or(e))return zc(e);if(Yr(e))return qc(e);if(Xr(e))return oi(e);if(en(e))return Kc(e);if(rn(e))return Bc(e)}throw Zr(e)}function Vc(e){return new N(function(t){var r=e[er]();if(F(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function zc(e){return new N(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?O(function(o,i){return e(o,i,n)}):Le,Me(1),r?it(t):xi(function(){return new an}))}}function Jn(e){return e<=0?function(){return w}:S(function(t,r){var n=[];t.subscribe(T(r,function(o){n.push(o),e=2,!0))}function xe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new I}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,c=s===void 0?!0:s;return function(l){var u,p,d,m=0,h=!1,v=!1,y=function(){p==null||p.unsubscribe(),p=void 0},x=function(){y(),u=d=void 0,h=v=!1},E=function(){var _=u;x(),_==null||_.unsubscribe()};return S(function(_,Z){m++,!v&&!h&&y();var ve=d=d!=null?d:r();Z.add(function(){m--,m===0&&!v&&!h&&(p=Xn(E,c))}),ve.subscribe(Z),!u&&m>0&&(u=new $t({next:function(L){return ve.next(L)},error:function(L){v=!0,y(),p=Xn(x,o,L),ve.error(L)},complete:function(){h=!0,y(),p=Xn(x,a),ve.complete()}}),q(_).subscribe(u))})(l)}}function Xn(e,t){for(var r=[],n=2;ne.next(document)),e}function $(e,t=document){return Array.from(t.querySelectorAll(e))}function Y(e,t=document){let r=we(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function we(e,t=document){return t.querySelector(e)||void 0}function xt(){var e,t,r,n;return(n=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?n:void 0}var pl=R(b(document.body,"focusin"),b(document.body,"focusout")).pipe(Ye(1),J(void 0),f(()=>xt()||document.body),ae(1));function ar(e){return pl.pipe(f(t=>e.contains(t)),se())}function Nt(e,t){let{matches:r}=matchMedia("(hover)");return j(()=>(r?R(b(e,"mouseenter").pipe(f(()=>!0)),b(e,"mouseleave").pipe(f(()=>!1))):R(b(e,"touchstart").pipe(f(()=>!0)),b(e,"touchend").pipe(f(()=>!1)),b(e,"touchcancel").pipe(f(()=>!1)))).pipe(t?Tr(o=>ze(+!o*t)):Le,J(!0,e.matches(":hover"))))}function Si(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)Si(e,r)}function A(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)Si(n,o);return n}function Oi(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function wt(e){let t=A("script",{src:e});return j(()=>(document.head.appendChild(t),R(b(t,"load"),b(t,"error").pipe(g(()=>on(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(f(()=>{}),z(()=>document.head.removeChild(t)),Me(1))))}function Li(e){let t=A("link",{rel:"stylesheet",href:e});return document.head.appendChild(t),R(b(t,"load"),b(t,"error").pipe(g(()=>on(()=>new ReferenceError(`Invalid styles: ${e}`))))).pipe(f(()=>{}),Me(1))}var Mi=new I,fl=j(()=>typeof ResizeObserver=="undefined"?wt("https://unpkg.com/resize-observer-polyfill"):K(void 0)).pipe(f(()=>new ResizeObserver(e=>e.forEach(t=>Mi.next(t)))),g(e=>R(Ge,K(e)).pipe(z(()=>e.disconnect()))),ae(1));function Ae(e){return{width:e.offsetWidth,height:e.offsetHeight}}function Re(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return fl.pipe(P(r=>r.observe(t)),g(r=>Mi.pipe(O(n=>n.target===t),z(()=>r.unobserve(t)))),f(()=>Ae(e)),J(Ae(e)))}function Mr(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ki(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function Ai(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function Et(e){return{x:e.offsetLeft,y:e.offsetTop}}function Ci(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function Hi(e){return R(b(window,"load"),b(window,"resize")).pipe(Ze(0,je),f(()=>Et(e)),J(Et(e)))}function pn(e){return{x:e.scrollLeft,y:e.scrollTop}}function Dt(e){return R(b(e,"scroll"),b(window,"scroll"),b(window,"resize")).pipe(Ze(0,je),f(()=>pn(e)),J(pn(e)))}var $i=new I,ml=j(()=>K(new IntersectionObserver(e=>{for(let t of e)$i.next(t)},{threshold:0}))).pipe(g(e=>R(Ge,K(e)).pipe(z(()=>e.disconnect()))),ae(1));function Tt(e){return ml.pipe(P(t=>t.observe(e)),g(t=>$i.pipe(O(({target:r})=>r===e),z(()=>t.unobserve(e)),f(({isIntersecting:r})=>r))))}var dl=Object.create,ua=Object.defineProperty,hl=Object.getOwnPropertyDescriptor,vl=Object.getOwnPropertyNames,bl=Object.getPrototypeOf,gl=Object.prototype.hasOwnProperty,_l=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),yl=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of vl(t))!gl.call(e,o)&&o!==r&&ua(e,o,{get:()=>t[o],enumerable:!(n=hl(t,o))||n.enumerable});return e},xl=(e,t,r)=>(r=e!=null?dl(bl(e)):{},yl(t||!e||!e.__esModule?ua(r,"default",{value:e,enumerable:!0}):r,e)),wl=_l((e,t)=>{var r="Expected a function",n=NaN,o="[object Symbol]",i=/^\s+|\s+$/g,a=/^[-+]0x[0-9a-f]+$/i,s=/^0b[01]+$/i,c=/^0o[0-7]+$/i,l=parseInt,u=typeof global=="object"&&global&&global.Object===Object&&global,p=typeof self=="object"&&self&&self.Object===Object&&self,d=u||p||Function("return this")(),m=Object.prototype,h=m.toString,v=Math.max,y=Math.min,x=function(){return d.Date.now()};function E(M,D,te){var ue,le,De,bt,We,lt,rt=0,Yt=!1,At=!1,vr=!0;if(typeof M!="function")throw new TypeError(r);D=L(D)||0,_(te)&&(Yt=!!te.leading,At="maxWait"in te,De=At?v(L(te.maxWait)||0,D):De,vr="trailing"in te?!!te.trailing:vr);function G(Se){var gt=ue,br=le;return ue=le=void 0,rt=Se,bt=M.apply(br,gt),bt}function H(Se){return rt=Se,We=setTimeout(V,D),Yt?G(Se):bt}function C(Se){var gt=Se-lt,br=Se-rt,Io=D-gt;return At?y(Io,De-br):Io}function W(Se){var gt=Se-lt,br=Se-rt;return lt===void 0||gt>=D||gt<0||At&&br>=De}function V(){var Se=x();if(W(Se))return Q(Se);We=setTimeout(V,C(Se))}function Q(Se){return We=void 0,vr&&ue?G(Se):(ue=le=void 0,bt)}function Ve(){We!==void 0&&clearTimeout(We),rt=0,ue=lt=le=We=void 0}function Jt(){return We===void 0?bt:Q(x())}function Nr(){var Se=x(),gt=W(Se);if(ue=arguments,le=this,lt=Se,gt){if(We===void 0)return H(lt);if(At)return We=setTimeout(V,D),G(lt)}return We===void 0&&(We=setTimeout(V,D)),bt}return Nr.cancel=Ve,Nr.flush=Jt,Nr}function _(M){var D=typeof M;return!!M&&(D=="object"||D=="function")}function Z(M){return!!M&&typeof M=="object"}function ve(M){return typeof M=="symbol"||Z(M)&&h.call(M)==o}function L(M){if(typeof M=="number")return M;if(ve(M))return n;if(_(M)){var D=typeof M.valueOf=="function"?M.valueOf():M;M=_(D)?D+"":D}if(typeof M!="string")return M===0?M:+M;M=M.replace(i,"");var te=s.test(M);return te||c.test(M)?l(M.slice(2),te?2:8):a.test(M)?n:+M}t.exports=E}),wn,B,pa,fa,Wt,Pi,ma,da,ha,lo,ro,no,El,Ar={},va=[],Tl=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,Pr=Array.isArray;function ft(e,t){for(var r in t)e[r]=t[r];return e}function uo(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function Lt(e,t,r){var n,o,i,a={};for(i in t)i=="key"?n=t[i]:i=="ref"?o=t[i]:a[i]=t[i];if(arguments.length>2&&(a.children=arguments.length>3?wn.call(arguments,2):r),typeof e=="function"&&e.defaultProps!=null)for(i in e.defaultProps)a[i]===void 0&&(a[i]=e.defaultProps[i]);return dn(e,a,n,o,null)}function dn(e,t,r,n,o){var i={type:e,props:t,key:r,ref:n,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:o!=null?o:++pa,__i:-1,__u:0};return o==null&&B.vnode!=null&&B.vnode(i),i}function qe(e){return e.children}function ct(e,t){this.props=e,this.context=t}function cr(e,t){if(t==null)return e.__?cr(e.__,e.__i+1):null;for(var r;ts&&Wt.sort(da),e=Wt.shift(),s=Wt.length,e.__d&&(r=void 0,n=void 0,o=(n=(t=e).__v).__e,i=[],a=[],t.__P&&((r=ft({},n)).__v=n.__v+1,B.vnode&&B.vnode(r),po(t.__P,r,n,t.__n,t.__P.namespaceURI,32&n.__u?[o]:null,i,o!=null?o:cr(n),!!(32&n.__u),a),r.__v=n.__v,r.__.__k[r.__i]=r,ya(i,r,a),n.__e=n.__=null,r.__e!=o&&ba(r)));gn.__r=0}function ga(e,t,r,n,o,i,a,s,c,l,u){var p,d,m,h,v,y,x,E=n&&n.__k||va,_=t.length;for(c=Sl(r,t,E,c,_),p=0;p<_;p++)(m=r.__k[p])!=null&&(d=m.__i==-1?Ar:E[m.__i]||Ar,m.__i=p,y=po(e,m,d,o,i,a,s,c,l,u),h=m.__e,m.ref&&d.ref!=m.ref&&(d.ref&&fo(d.ref,null,m),u.push(m.ref,m.__c||h,m)),v==null&&h!=null&&(v=h),(x=!!(4&m.__u))||d.__k===m.__k?c=_a(m,c,e,x):typeof m.type=="function"&&y!==void 0?c=y:h&&(c=h.nextSibling),m.__u&=-7);return r.__e=v,c}function Sl(e,t,r,n,o){var i,a,s,c,l,u=r.length,p=u,d=0;for(e.__k=new Array(o),i=0;i0?dn(a.type,a.props,a.key,a.ref?a.ref:null,a.__v):a).__=e,a.__b=e.__b+1,s=null,(l=a.__i=Ol(a,r,c,p))!=-1&&(p--,(s=r[l])&&(s.__u|=2)),s==null||s.__v==null?(l==-1&&(o>u?d--:oc?d--:d++,a.__u|=4))):e.__k[i]=null;if(p)for(i=0;i(u?1:0)){for(o=r-1,i=r+1;o>=0||i=0?o--:i++])!=null&&!(2&l.__u)&&s==l.key&&c==l.type)return a}return-1}function Ri(e,t,r){t[0]=="-"?e.setProperty(t,r!=null?r:""):e[t]=r==null?"":typeof r!="number"||Tl.test(t)?r:r+"px"}function fn(e,t,r,n,o){var i,a;e:if(t=="style")if(typeof r=="string")e.style.cssText=r;else{if(typeof n=="string"&&(e.style.cssText=n=""),n)for(t in n)r&&t in r||Ri(e.style,t,"");if(r)for(t in r)n&&r[t]==n[t]||Ri(e.style,t,r[t])}else if(t[0]=="o"&&t[1]=="n")i=t!=(t=t.replace(ha,"$1")),a=t.toLowerCase(),t=a in e||t=="onFocusOut"||t=="onFocusIn"?a.slice(2):t.slice(2),e.l||(e.l={}),e.l[t+i]=r,r?n?r.u=n.u:(r.u=lo,e.addEventListener(t,i?no:ro,i)):e.removeEventListener(t,i?no:ro,i);else{if(o=="http://www.w3.org/2000/svg")t=t.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(t!="width"&&t!="height"&&t!="href"&&t!="list"&&t!="form"&&t!="tabIndex"&&t!="download"&&t!="rowSpan"&&t!="colSpan"&&t!="role"&&t!="popover"&&t in e)try{e[t]=r!=null?r:"";break e}catch(s){}typeof r=="function"||(r==null||r===!1&&t[4]!="-"?e.removeAttribute(t):e.setAttribute(t,t=="popover"&&r==1?"":r))}}function ji(e){return function(t){if(this.l){var r=this.l[t.type+e];if(t.t==null)t.t=lo++;else if(t.t0?e:Pr(e)?e.map(xa):ft({},e)}function Ll(e,t,r,n,o,i,a,s,c){var l,u,p,d,m,h,v,y=r.props,x=t.props,E=t.type;if(E=="svg"?o="http://www.w3.org/2000/svg":E=="math"?o="http://www.w3.org/1998/Math/MathML":o||(o="http://www.w3.org/1999/xhtml"),i!=null){for(l=0;l=r.__.length&&r.__.push({}),r.__[e]}function _n(e){return $r=1,Al(Sa,e)}function Al(e,t,r){var n=mo(Hr++,2);if(n.t=e,!n.__c&&(n.__=[r?r(t):Sa(void 0,t),function(s){var c=n.__N?n.__N[0]:n.__[0],l=n.t(c,s);c!==l&&(n.__N=[l,n.__[1]],n.__c.setState({}))}],n.__c=ge,!ge.__f)){var o=function(s,c,l){if(!n.__c.__H)return!0;var u=n.__c.__H.__.filter(function(d){return!!d.__c});if(u.every(function(d){return!d.__N}))return!i||i.call(this,s,c,l);var p=n.__c.props!==s;return u.forEach(function(d){if(d.__N){var m=d.__[0];d.__=d.__N,d.__N=void 0,m!==d.__[0]&&(p=!0)}}),i&&i.call(this,s,c,l)||p};ge.__f=!0;var i=ge.shouldComponentUpdate,a=ge.componentWillUpdate;ge.componentWillUpdate=function(s,c,l){if(this.__e){var u=i;i=void 0,o(s,c,l),i=u}a&&a.call(this,s,c,l)},ge.shouldComponentUpdate=o}return n.__N||n.__}function mt(e,t){var r=mo(Hr++,3);!Ee.__s&&Ta(r.__H,t)&&(r.__=e,r.u=t,ge.__H.__h.push(r))}function zt(e){return $r=5,ur(function(){return{current:e}},[])}function ur(e,t){var r=mo(Hr++,7);return Ta(r.__H,t)&&(r.__=e(),r.__H=t,r.__h=e),r.__}function Cl(e,t){return $r=8,ur(function(){return e},t)}function Hl(){for(var e;e=Ea.shift();)if(e.__P&&e.__H)try{e.__H.__h.forEach(hn),e.__H.__h.forEach(io),e.__H.__h=[]}catch(t){e.__H.__h=[],Ee.__e(t,e.__v)}}Ee.__b=function(e){ge=null,Ui&&Ui(e)},Ee.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),zi&&zi(e,t)},Ee.__r=function(e){Ni&&Ni(e),Hr=0;var t=(ge=e.__c).__H;t&&(Qn===ge?(t.__h=[],ge.__h=[],t.__.forEach(function(r){r.__N&&(r.__=r.__N),r.u=r.__N=void 0})):(t.__h.forEach(hn),t.__h.forEach(io),t.__h=[],Hr=0)),Qn=ge},Ee.diffed=function(e){Di&&Di(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(Ea.push(t)!==1&&Fi===Ee.requestAnimationFrame||((Fi=Ee.requestAnimationFrame)||$l)(Hl)),t.__H.__.forEach(function(r){r.u&&(r.__H=r.u),r.u=void 0})),Qn=ge=null},Ee.__c=function(e,t){t.some(function(r){try{r.__h.forEach(hn),r.__h=r.__h.filter(function(n){return!n.__||io(n)})}catch(n){t.some(function(o){o.__h&&(o.__h=[])}),t=[],Ee.__e(n,r.__v)}}),Wi&&Wi(e,t)},Ee.unmount=function(e){Vi&&Vi(e);var t,r=e.__c;r&&r.__H&&(r.__H.__.forEach(function(n){try{hn(n)}catch(o){t=o}}),r.__H=void 0,t&&Ee.__e(t,r.__v))};var qi=typeof requestAnimationFrame=="function";function $l(e){var t,r=function(){clearTimeout(n),qi&&cancelAnimationFrame(t),setTimeout(e)},n=setTimeout(r,35);qi&&(t=requestAnimationFrame(r))}function hn(e){var t=ge,r=e.__c;typeof r=="function"&&(e.__c=void 0,r()),ge=t}function io(e){var t=ge;e.__c=e.__(),ge=t}function Ta(e,t){return!e||e.length!==t.length||t.some(function(r,n){return r!==e[n]})}function Sa(e,t){return typeof t=="function"?t(e):t}function Pl(e,t){for(var r in t)e[r]=t[r];return e}function Ki(e,t){for(var r in e)if(r!=="__source"&&!(r in t))return!0;for(var n in t)if(n!=="__source"&&e[n]!==t[n])return!0;return!1}function Bi(e,t){this.props=e,this.context=t}(Bi.prototype=new ct).isPureReactComponent=!0,Bi.prototype.shouldComponentUpdate=function(e,t){return Ki(this.props,e)||Ki(this.state,t)};var Gi=B.__b;B.__b=function(e){e.type&&e.type.__f&&e.ref&&(e.props.ref=e.ref,e.ref=null),Gi&&Gi(e)};var sw=typeof Symbol<"u"&&Symbol.for&&Symbol.for("react.forward_ref")||3911,Il=B.__e;B.__e=function(e,t,r,n){if(e.then){for(var o,i=t;i=i.__;)if((o=i.__c)&&o.__c)return t.__e==null&&(t.__e=r.__e,t.__k=r.__k),o.__c(e,t)}Il(e,t,r,n)};var Yi=B.unmount;function Oa(e,t,r){return e&&(e.__c&&e.__c.__H&&(e.__c.__H.__.forEach(function(n){typeof n.__c=="function"&&n.__c()}),e.__c.__H=null),(e=Pl({},e)).__c!=null&&(e.__c.__P===r&&(e.__c.__P=t),e.__c.__e=!0,e.__c=null),e.__k=e.__k&&e.__k.map(function(n){return Oa(n,t,r)})),e}function La(e,t,r){return e&&r&&(e.__v=null,e.__k=e.__k&&e.__k.map(function(n){return La(n,t,r)}),e.__c&&e.__c.__P===t&&(e.__e&&r.appendChild(e.__e),e.__c.__e=!0,e.__c.__P=r)),e}function eo(){this.__u=0,this.o=null,this.__b=null}function Ma(e){var t=e.__.__c;return t&&t.__a&&t.__a(e)}function mn(){this.i=null,this.l=null}B.unmount=function(e){var t=e.__c;t&&t.__R&&t.__R(),t&&32&e.__u&&(e.type=null),Yi&&Yi(e)},(eo.prototype=new ct).__c=function(e,t){var r=t.__c,n=this;n.o==null&&(n.o=[]),n.o.push(r);var o=Ma(n.__v),i=!1,a=function(){i||(i=!0,r.__R=null,o?o(s):s())};r.__R=a;var s=function(){if(!--n.__u){if(n.state.__a){var c=n.state.__a;n.__v.__k[0]=La(c,c.__c.__P,c.__c.__O)}var l;for(n.setState({__a:n.__b=null});l=n.o.pop();)l.forceUpdate()}};n.__u++||32&t.__u||n.setState({__a:n.__b=n.__v.__k[0]}),e.then(a,a)},eo.prototype.componentWillUnmount=function(){this.o=[]},eo.prototype.render=function(e,t){if(this.__b){if(this.__v.__k){var r=document.createElement("div"),n=this.__v.__k[0].__c;this.__v.__k[0]=Oa(this.__b,r,n.__O=n.__P)}this.__b=null}var o=t.__a&&Lt(qe,null,e.fallback);return o&&(o.__u&=-33),[Lt(qe,null,t.__a?null:e.children),o]};var Ji=function(e,t,r){if(++r[1]===r[0]&&e.l.delete(t),e.props.revealOrder&&(e.props.revealOrder[0]!=="t"||!e.l.size))for(r=e.i;r;){for(;r.length>3;)r.pop()();if(r[1]Object.freeze({get current(){return t.current}}),[])}var Kl=typeof globalThis<"u"&&typeof navigator<"u"&&typeof document<"u";function Bl(e,...t){var r;(r=e==null?void 0:e.addEventListener)==null||r.call(e,...t)}function Gl(e,...t){var r;(r=e==null?void 0:e.removeEventListener)==null||r.call(e,...t)}var Yl=(e,t)=>Object.hasOwn(e,t),Jl=()=>!0,Xl=()=>!1;function Zl(e=!1){let t=zt(e),r=Cl(()=>t.current,[]);return mt(()=>(t.current=!0,()=>{t.current=!1}),[]),r}function Ql(e,...t){let r=Zl(),n=Aa(t[1]),o=ur(()=>function(...i){r()&&(typeof n.current=="function"?n.current.apply(this,i):typeof n.current.handleEvent=="function"&&n.current.handleEvent.apply(this,i))},[]);mt(()=>{let i=eu(e)?e.current:e;if(!i)return;let a=t.slice(2);return Bl(i,t[0],o,...a),()=>{Gl(i,t[0],o,...a)}},[e,t[0]])}function eu(e){return e!==null&&typeof e=="object"&&Yl(e,"current")}var tu=e=>typeof e=="function"?e:typeof e=="string"?t=>t.key===e:e?Jl:Xl,ru=Kl?globalThis:null;function Ca(e,t,r=[],n={}){let{event:o="keydown",target:i=ru,eventOptions:a}=n,s=Aa(t),c=ur(()=>{let l=tu(e);return function(u){l(u)&&s.current.call(this,u)}},r);Ql(i,o,c,a)}function Ha(e){var t,r,n="";if(typeof e=="string"||typeof e=="number")n+=e;else if(typeof e=="object")if(Array.isArray(e)){var o=e.length;for(t=0;t1)Ot--;else{for(var e,t=!1;kr!==void 0;){var r=kr;for(kr=void 0,ao++;r!==void 0;){var n=r.o;if(r.o=void 0,r.f&=-3,!(8&r.f)&&Ia(r))try{r.c()}catch(o){t||(e=o,t=!0)}r=n}}if(ao=0,Ot--,t)throw e}}function iu(e){if(Ot>0)return e();Ot++;try{return e()}finally{En()}}var ce=void 0;function $a(e){var t=ce;ce=void 0;try{return e()}finally{ce=t}}var kr=void 0,Ot=0,ao=0,yn=0;function Pa(e){if(ce!==void 0){var t=e.n;if(t===void 0||t.t!==ce)return t={i:0,S:e,p:ce.s,n:void 0,t:ce,e:void 0,x:void 0,r:t},ce.s!==void 0&&(ce.s.n=t),ce.s=t,e.n=t,32&ce.f&&e.S(t),t;if(t.i===-1)return t.i=0,t.n!==void 0&&(t.n.p=t.p,t.p!==void 0&&(t.p.n=t.n),t.p=ce.s,t.n=void 0,ce.s.n=t,ce.s=t),t}}function Ce(e,t){this.v=e,this.i=0,this.n=void 0,this.t=void 0,this.W=t==null?void 0:t.watched,this.Z=t==null?void 0:t.unwatched,this.name=t==null?void 0:t.name}Ce.prototype.brand=ou;Ce.prototype.h=function(){return!0};Ce.prototype.S=function(e){var t=this,r=this.t;r!==e&&e.e===void 0&&(e.x=r,this.t=e,r!==void 0?r.e=e:$a(function(){var n;(n=t.W)==null||n.call(t)}))};Ce.prototype.U=function(e){var t=this;if(this.t!==void 0){var r=e.e,n=e.x;r!==void 0&&(r.x=n,e.e=void 0),n!==void 0&&(n.e=r,e.x=void 0),e===this.t&&(this.t=n,n===void 0&&$a(function(){var o;(o=t.Z)==null||o.call(t)}))}};Ce.prototype.subscribe=function(e){var t=this;return Kt(function(){var r=t.value,n=ce;ce=void 0;try{e(r)}finally{ce=n}},{name:"sub"})};Ce.prototype.valueOf=function(){return this.value};Ce.prototype.toString=function(){return this.value+""};Ce.prototype.toJSON=function(){return this.value};Ce.prototype.peek=function(){var e=ce;ce=void 0;try{return this.value}finally{ce=e}};Object.defineProperty(Ce.prototype,"value",{get:function(){var e=Pa(this);return e!==void 0&&(e.i=this.i),this.v},set:function(e){if(e!==this.v){if(ao>100)throw new Error("Cycle detected");this.v=e,this.i++,yn++,Ot++;try{for(var t=this.t;t!==void 0;t=t.x)t.t.N()}finally{En()}}}});function Mt(e,t){return new Ce(e,t)}function Ia(e){for(var t=e.s;t!==void 0;t=t.n)if(t.S.i!==t.i||!t.S.h()||t.S.i!==t.i)return!0;return!1}function Ra(e){for(var t=e.s;t!==void 0;t=t.n){var r=t.S.n;if(r!==void 0&&(t.r=r),t.S.n=t,t.i=-1,t.n===void 0){e.s=t;break}}}function ja(e){for(var t=e.s,r=void 0;t!==void 0;){var n=t.p;t.i===-1?(t.S.U(t),n!==void 0&&(n.n=t.n),t.n!==void 0&&(t.n.p=n)):r=t,t.S.n=t.r,t.r!==void 0&&(t.r=void 0),t=n}e.s=r}function Bt(e,t){Ce.call(this,void 0),this.x=e,this.s=void 0,this.g=yn-1,this.f=4,this.W=t==null?void 0:t.watched,this.Z=t==null?void 0:t.unwatched,this.name=t==null?void 0:t.name}Bt.prototype=new Ce;Bt.prototype.h=function(){if(this.f&=-3,1&this.f)return!1;if((36&this.f)==32||(this.f&=-5,this.g===yn))return!0;if(this.g=yn,this.f|=1,this.i>0&&!Ia(this))return this.f&=-2,!0;var e=ce;try{Ra(this),ce=this;var t=this.x();(16&this.f||this.v!==t||this.i===0)&&(this.v=t,this.f&=-17,this.i++)}catch(r){this.v=r,this.f|=16,this.i++}return ce=e,ja(this),this.f&=-2,!0};Bt.prototype.S=function(e){if(this.t===void 0){this.f|=36;for(var t=this.s;t!==void 0;t=t.n)t.S.S(t)}Ce.prototype.S.call(this,e)};Bt.prototype.U=function(e){if(this.t!==void 0&&(Ce.prototype.U.call(this,e),this.t===void 0)){this.f&=-33;for(var t=this.s;t!==void 0;t=t.n)t.S.U(t)}};Bt.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var e=this.t;e!==void 0;e=e.x)e.t.N()}};Object.defineProperty(Bt.prototype,"value",{get:function(){if(1&this.f)throw new Error("Cycle detected");var e=Pa(this);if(this.h(),e!==void 0&&(e.i=this.i),16&this.f)throw this.v;return this.v}});function ta(e,t){return new Bt(e,t)}function Fa(e){var t=e.u;if(e.u=void 0,typeof t=="function"){Ot++;var r=ce;ce=void 0;try{t()}catch(n){throw e.f&=-2,e.f|=8,ho(e),n}finally{ce=r,En()}}}function ho(e){for(var t=e.s;t!==void 0;t=t.n)t.S.U(t);e.x=void 0,e.s=void 0,Fa(e)}function au(e){if(ce!==this)throw new Error("Out-of-order effect");ja(this),ce=e,this.f&=-2,8&this.f&&ho(this),En()}function pr(e,t){this.x=e,this.u=void 0,this.s=void 0,this.o=void 0,this.f=32,this.name=t==null?void 0:t.name}pr.prototype.c=function(){var e=this.S();try{if(8&this.f||this.x===void 0)return;var t=this.x();typeof t=="function"&&(this.u=t)}finally{e()}};pr.prototype.S=function(){if(1&this.f)throw new Error("Cycle detected");this.f|=1,this.f&=-9,Fa(this),Ra(this),Ot++;var e=ce;return ce=this,au.bind(this,e)};pr.prototype.N=function(){2&this.f||(this.f|=2,this.o=kr,kr=this)};pr.prototype.d=function(){this.f|=8,1&this.f||ho(this)};pr.prototype.dispose=function(){this.d()};function Kt(e,t){var r=new pr(e,t);try{r.c()}catch(o){throw r.d(),o}var n=r.d.bind(r);return n[Symbol.dispose]=n,n}var Ua,vo,to,Na=[];Kt(function(){Ua=this.N})();function fr(e,t){B[e]=t.bind(null,B[e]||function(){})}function xn(e){to&&to(),to=e&&e.S()}function Da(e){var t=this,r=e.data,n=cu(r);n.value=r;var o=ur(function(){for(var s=t,c=t.__v;c=c.__;)if(c.__c){c.__c.__$f|=4;break}var l=ta(function(){var m=n.value.value;return m===0?0:m===!0?"":m||""}),u=ta(function(){return!Array.isArray(l.value)&&!fa(l.value)}),p=Kt(function(){if(this.N=Wa,u.value){var m=l.value;s.__v&&s.__v.__e&&s.__v.__e.nodeType===3&&(s.__v.__e.data=m)}}),d=t.__$u.d;return t.__$u.d=function(){p(),d.call(this)},[u,l]},[]),i=o[0],a=o[1];return i.value?a.peek():a.value}Da.displayName="ReactiveTextNode";Object.defineProperties(Ce.prototype,{constructor:{configurable:!0,value:void 0},type:{configurable:!0,value:Da},props:{configurable:!0,get:function(){return{data:this}}},__b:{configurable:!0,value:1}});fr("__b",function(e,t){if(typeof t.type=="function"&&typeof window<"u"&&window.__PREACT_SIGNALS_DEVTOOLS__&&window.__PREACT_SIGNALS_DEVTOOLS__.exitComponent(),typeof t.type=="string"){var r,n=t.props;for(var o in n)if(o!=="children"){var i=n[o];i instanceof Ce&&(r||(t.__np=r={}),r[o]=i,n[o]=i.peek())}}e(t)});fr("__r",function(e,t){if(typeof t.type=="function"&&typeof window<"u"&&window.__PREACT_SIGNALS_DEVTOOLS__&&window.__PREACT_SIGNALS_DEVTOOLS__.enterComponent(t),t.type!==qe){xn();var r,n=t.__c;n&&(n.__$f&=-2,(r=n.__$u)===void 0&&(n.__$u=r=(function(o){var i;return Kt(function(){i=this}),i.c=function(){n.__$f|=1,n.setState({})},i})())),vo=n,xn(r)}e(t)});fr("__e",function(e,t,r,n){typeof window<"u"&&window.__PREACT_SIGNALS_DEVTOOLS__&&window.__PREACT_SIGNALS_DEVTOOLS__.exitComponent(),xn(),vo=void 0,e(t,r,n)});fr("diffed",function(e,t){typeof t.type=="function"&&typeof window<"u"&&window.__PREACT_SIGNALS_DEVTOOLS__&&window.__PREACT_SIGNALS_DEVTOOLS__.exitComponent(),xn(),vo=void 0;var r;if(typeof t.type=="string"&&(r=t.__e)){var n=t.__np,o=t.props;if(n){var i=r.U;if(i)for(var a in i){var s=i[a];s!==void 0&&!(a in n)&&(s.d(),i[a]=void 0)}else i={},r.U=i;for(var c in n){var l=i[c],u=n[c];l===void 0?(l=su(r,c,u,o),i[c]=l):l.o(u,o)}}}e(t)});function su(e,t,r,n){var o=t in e&&e.ownerSVGElement===void 0,i=Mt(r);return{o:function(a,s){i.value=a,n=s},d:Kt(function(){this.N=Wa;var a=i.value.value;n[t]!==a&&(n[t]=a,o?e[t]=a:a?e.setAttribute(t,a):e.removeAttribute(t))})}}fr("unmount",function(e,t){if(typeof t.type=="string"){var r=t.__e;if(r){var n=r.U;if(n){r.U=void 0;for(var o in n){var i=n[o];i&&i.d()}}}}else{var a=t.__c;if(a){var s=a.__$u;s&&(a.__$u=void 0,s.d())}}e(t)});fr("__h",function(e,t,r,n){(n<3||n===9)&&(t.__$f|=2),e(t,r,n)});ct.prototype.shouldComponentUpdate=function(e,t){var r=this.__$u,n=r&&r.s!==void 0;for(var o in t)return!0;if(this.__f||typeof this.u=="boolean"&&this.u===!0){var i=2&this.__$f;if(!(n||i||4&this.__$f)||1&this.__$f)return!0}else if(!(n||4&this.__$f)||3&this.__$f)return!0;for(var a in e)if(a!=="__source"&&e[a]!==this.props[a])return!0;for(var s in this.props)if(!(s in e))return!0;return!1};function cu(e,t){return _n(function(){return Mt(e,t)})[0]}var lu=function(e){queueMicrotask(function(){queueMicrotask(e)})};function uu(){iu(function(){for(var e;e=Na.shift();)Ua.call(e)})}function Wa(){Na.push(this)===1&&(B.requestAnimationFrame||lu)(uu)}var so=[0];for(let e=0;e<32;e++)so.push(so[e]|1<>>5]>>>e&1}set(e){this.data[e>>>5]|=1<<(e&31)}forEach(e){let t=this.size&31;for(let r=0;r{var r;return(r=t.tags)==null?void 0:r.length})&&(matchMedia("(max-width: 768px)").matches||Va())}function Vt(){et.value=He(k({},et.value),{hideSearch:!et.value.hideSearch})}function Va(){et.value=He(k({},et.value),{hideFilters:!et.value.hideFilters})}function vn(){return et.value.selectedItem}function co(e){et.value=He(k({},et.value),{selectedItem:e})}function mu(){var e,t;return(t=(e=lr.value)==null?void 0:e.items)!=null?t:[]}function Tn(){return typeof Oe.value.input=="string"?Oe.value.input:""}function za(e){let t=qa();e.length&&!t.length?Oe.value=He(k({},Oe.value),{page:void 0,input:e}):!e.length&&t.length?Oe.value=He(k({},Oe.value),{page:void 0,input:{type:"operator",data:{operator:"not",operands:[]}}}):Oe.value=He(k({},Oe.value),{page:void 0,input:e})}function du(){typeof st.value.pagination.next<"u"&&(Oe.value=He(k({},Oe.value),{page:st.value.pagination.next}))}function hu(e){let t=Oe.value.filter.input;if("type"in t&&t.type==="operator"){for(let r of t.data.operands)if("type"in r&&r.type==="value"&&typeof r.data.value=="string"&&r.data.value===e)return!0}return!1}function qa(){let e=Oe.value.filter.input,t=[];if("type"in e&&e.type==="operator")for(let r of e.data.operands)"type"in r&&r.type==="value"&&typeof r.data.value=="string"&&t.push(r.data.value);return t}function vu(e){let t=Oe.value.filter.input,r=[];if("type"in t&&t.type==="operator")for(let n of t.data.operands)"type"in n&&n.type==="value"&&typeof n.data.value=="string"&&r.push(n.data.value);if(r.includes(e)){let n=r.indexOf(e);n>-1&&r.splice(n,1)}else r.push(e);Oe.value=He(k({},Oe.value),{page:void 0,filter:He(k({},Oe.value.filter),{input:{type:"operator",data:{operator:"and",operands:r.map(n=>({type:"value",data:{field:"tags",value:n}}))}}})}),za(Tn())}function bu(){return st.value.items}function gu(){return st.value.total}function _u(){var e;for(let t of(e=st.value.aggregations)!=null?e:[])if(t.type==="term")return t.data.value;return[]}function sr(){return et.value.hideSearch}function yu(){return et.value.hideFilters}function Ka(){var e;return(e=Ba.value.highlight)!=null?e:!1}var et=Mt({hideSearch:!0,hideFilters:!0,selectedItem:0}),Ba=Mt({}),lr=Mt(),na=Mt(),Oe=Mt({input:"",filter:{input:{type:"operator",data:{operator:"and",operands:[]}},aggregation:{input:[{type:"term",data:{field:"tags"}}]}}}),st=Mt({items:[],query:{select:{documents:new ra(0),terms:new ra(0)},values:[]},pagination:{total:0}});function xu(e,t,r){for(let n=0;tr&&t(0,o,r,r=i);continue;case 62:e.charCodeAt(r+1)===47?t(2,--o,r,r=i+1):xu(e,r,n)?t(3,o,r,r=i+1):t(1,o++,r,r=i+1)}i>r&&t(0,o,r,i)}function Eu(e,t=0,r=e.length){let n=++t;e:for(let l=0;n{let i=[],a=[],{onElement:s,onText:c=Tu}=typeof r=="function"?{onElement:r}:r,l=0,u=0;return e(t,(p,d,m,h)=>{if(p===0)i[l++]=c(t,m,h),a[u++]={value:null,depth:d};else if(p&1&&(a[u++]={value:Eu(t,m,h),depth:d}),p&2)for(let v=0;u>=0;v++){let{value:y,depth:x}=a[--u];if(x>d)continue;let E=i.slice(l-=v,l+v);i[l++]=s(y,E),u++;break}},n,o),i.slice(0,l)}}function Ou(e){return e.replace(/[&<>]/g,t=>{switch(t.charCodeAt(0)){case 38:return"&";case 60:return"<";case 62:return">"}})}function bn(e){return e.replace(/&(amp|[lg]t);/g,t=>{switch(t.charCodeAt(1)){case 97:return"&";case 108:return"<";case 103:return">"}})}function Lu(e,t){return{start:e.start+t,end:e.end+t,value:e.value}}function Mu(e,t,r){return e.slice(t,r)}function ku(e){let{onHighlight:t,onText:r=Mu}=typeof e=="function"?{onHighlight:e}:e;return(n,o,i=0,a=n.length)=>{var l;let s=[],c=(l=o==null?void 0:o.ranges)!=null?l:[];for(let u=0,p=i;ua)break;let m=c[u].end;if(mi&&s.push(r(n,i,d));let{value:h}=c[u];s.push(t(n,{start:d,end:i=m,value:h}))}return it!==null&&typeof t<"u"&&t!==!1&&!(typeof t=="string"&&t.trim().length===0))}function Ja(e,t){let r=Ga(e,{onElement(n,o){return Lt(n.tag,n.attrs,...o)},onText(n,o,i){return Ya(n,t==null?void 0:t.value.highlight,o,i)}});return U(qe,{children:r})}function Iu(e,t){var n;let r=[];for(let o=0,i=0;om.start=s||c.push(He(k({},m),{start:Math.max(m.start,a),end:Math.min(m.end,s)}));let l=Ga(e,{onElement(m,h){var y;let v=Pu(h);if(v.length!==0)return $u.has(m.tag)?Lt(m.tag,(y=m.attrs)!=null?y:{},...v):m.tag==="li"?U(qe,{children:["\u2013 ",v," "]}):Hu.has(m.tag)?U(qe,{children:[" ",v," "]}):U(qe,{children:v})},onText(m,h,v){let y=Math.max(h,a),x=Math.min(v,s);if(!(y>=x))return Ya(m,{ranges:c},y,x)}});return U(qe,{children:[a>0&&"...",l]})}function Xa(e,t={highlight:!0}){Ba.value=t;let r=new Worker(e);r.onmessage=n=>{let o=n.data;switch(o.type){case 1:na.value=!0;break;case 3:typeof o.data.pagination.prev<"u"?st.value=He(k({},st.value),{pagination:o.data.pagination,items:[...st.value.items,...o.data.items]}):(st.value=o.data,co(0));break}},Kt(()=>{lr.value&&r.postMessage({type:0,data:lr.value})}),Kt(()=>{na.value&&r.postMessage({type:2,data:Oe.value})})}var oa={container:"p",hidden:"v"};function ju(e){return U("div",{class:qt(oa.container,{[oa.hidden]:e.hidden}),onClick:()=>Vt()})}var ia={container:"r",disabled:"c"};function aa(e){return U("button",{class:qt(ia.container,{[ia.disabled]:!e.onClick}),onClick:e.onClick,children:e.children})}var sa=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),Fu=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(t,r,n)=>n?n.toUpperCase():r.toLowerCase()),ca=e=>{let t=Fu(e);return t.charAt(0).toUpperCase()+t.slice(1)},Uu=(...e)=>e.filter((t,r,n)=>!!t&&t.trim()!==""&&n.indexOf(t)===r).join(" ").trim(),Nu={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},Du=c=>{var l=c,{color:e="currentColor",size:t=24,strokeWidth:r=2,absoluteStrokeWidth:n,children:o,iconNode:i,class:a=""}=l,s=gr(l,["color","size","strokeWidth","absoluteStrokeWidth","children","iconNode","class"]);return Lt("svg",k(He(k({},Nu),{width:String(t),height:t,stroke:e,"stroke-width":n?Number(r)*24/Number(t):r,class:["lucide",a].join(" ")}),s),[...i.map(([u,p])=>Lt(u,p)),...Cr(o)])},Za=(e,t)=>{let r=a=>{var s=a,{class:n="",children:o}=s,i=gr(s,["class","children"]);return Lt(Du,He(k({},i),{iconNode:t,class:Uu(`lucide-${sa(ca(e))}`,`lucide-${sa(e)}`,n)}),o)};return r.displayName=ca(e),r},Wu=Za("list-filter",[["path",{d:"M2 5h20",key:"1fs1ex"}],["path",{d:"M6 12h12",key:"8npq4p"}],["path",{d:"M9 19h6",key:"456am0"}]]),Vu=Za("search",[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]]),cw=xl(wl(),1);function zu({threshold:e=0,root:t=null,rootMargin:r="0%",freezeOnceVisible:n=!1,initialIsIntersecting:o=!1,onChange:i}={}){var a;let[s,c]=_n(null),[l,u]=_n(()=>({isIntersecting:o,entry:void 0})),p=zt();p.current=i;let d=((a=l.entry)==null?void 0:a.isIntersecting)&&n;mt(()=>{if(!s||!("IntersectionObserver"in window)||d)return;let v,y=new IntersectionObserver(x=>{let E=Array.isArray(y.thresholds)?y.thresholds:[y.thresholds];x.forEach(_=>{let Z=_.isIntersecting&&E.some(ve=>_.intersectionRatio>=ve);u({isIntersecting:Z,entry:_}),p.current&&p.current(Z,_),Z&&n&&v&&(v(),v=void 0)})},{threshold:e,root:t,rootMargin:r});return y.observe(s),()=>{y.disconnect()}},[s,JSON.stringify(e),t,r,d,n]);let m=zt(null);mt(()=>{var v;!s&&(v=l.entry)!=null&&v.target&&!n&&!d&&m.current!==l.entry.target&&(m.current=l.entry.target,u({isIntersecting:o,entry:void 0}))},[s,l.entry,n,d,o]);let h=[c,!!l.isIntersecting,l.entry];return h.ref=h[0],h.isIntersecting=h[1],h.entry=h[2],h}var pt={container:"n",hidden:"l",content:"y",pop:"d",badge:"w",sidebar:"e",controls:"k",results:"z",loadmore:"j"};function qu(e){let{isIntersecting:t,ref:r}=zu({threshold:0});mt(()=>{t&&du()},[t]);let n=zt(null);mt(()=>{n.current&&typeof Oe.value.page>"u"&&n.current.scrollTo({top:0,behavior:"smooth"})},[Oe.value]);let o=qa();return U("div",{class:qt(pt.container,{[pt.hidden]:e.hidden}),children:[U("div",{class:pt.content,children:[U("div",{class:pt.controls,children:[U(aa,{onClick:Vt,children:U(Vu,{})}),U(Bu,{focus:!e.hidden}),U(aa,{onClick:Va,children:[U(Wu,{}),o.length>0&&U("span",{class:pt.badge,children:o.length})]})]}),U("div",{class:pt.results,ref:n,children:[U(Gu,{keyboard:!e.hidden}),U("div",{class:pt.loadmore,ref:r})]})]}),U("div",{class:qt(pt.sidebar,{[pt.hidden]:yu()}),children:U(Ku,{})})]})}var St={container:"X",list:"F",heading:"I",title:"R",item:"o",active:"g",value:"q",count:"A"};function Ku(e){let t=_u();return t.sort((r,n)=>n.node.count-r.node.count),U("div",{class:St.container,children:[U("h3",{class:St.heading,children:"Filters"}),U("h4",{class:St.title,children:"Tags"}),U("ol",{class:St.list,children:t.map(r=>U("li",{class:qt(St.item,{[St.active]:hu(r.node.value)}),onClick:()=>vu(r.node.value),children:[U("span",{class:St.value,children:r.node.value}),U("span",{class:St.count,children:r.node.count})]}))})]})}var la={container:"f"};function Bu(e){let t=zt(null);return mt(()=>{var r,n;e.focus?(r=t.current)==null||r.focus():(n=t.current)==null||n.blur()},[e.focus]),U("div",{class:la.container,children:U("input",{ref:t,type:"text",class:la.content,value:bn(Tn()),onInput:r=>za(Ou(r.currentTarget.value)),autocapitalize:"off",autocomplete:"off",autocorrect:"off",placeholder:"Search",spellcheck:!1,role:"combobox"})})}var at={container:"b",heading:"B",item:"i",active:"h",wrapper:"C",meta:"D",actions:"s",title:"x",path:"t",excerpt:"u",more:"E"};function Qa(){let[e,t]=_n(!1);return mt(()=>{let r=()=>t(!0),n=()=>t(!1);return document.addEventListener("compositionstart",r),document.addEventListener("compositionend",n),()=>{document.removeEventListener("compositionstart",r),document.removeEventListener("compositionend",n)}},[]),e}function Gu(e){var s;let t=mu(),r=bu(),n=vn(),o=zt([]),i=Qa();mt(()=>{let c=o.current[n];c&&c.scrollIntoView({block:"center",behavior:"smooth"})},[n]),Ca(e.keyboard,c=>{if(i)return;let l=vn();c.key==="ArrowDown"?(c.preventDefault(),co(Math.min(l+1,r.length-1))):c.key==="ArrowUp"&&(c.preventDefault(),co(Math.max(l-1,0)))},[e.keyboard,i]);let a=(s=gu())!=null?s:0;return U(qe,{children:[r.length>0&&U("h3",{class:at.heading,children:[U("span",{class:at.bubble,children:new Intl.NumberFormat("en-US").format(a)})," ","results"]}),U("ol",{class:at.container,children:r.map((c,l)=>{var y,x,E,_;let u=c.matches.find(({field:Z})=>Z==="text"),p=Ja(t[c.id].title,c.matches.find(({field:Z})=>Z==="title")),d=Iu((y=t[c.id].path)!=null?y:[],c.matches.find(({field:Z})=>Z==="path")),m=Ru(t[c.id].text,u),h=Math.max(0,((_=(E=(x=u==null?void 0:u.value.highlight)==null?void 0:x.ranges)==null?void 0:E.filter(Z=>Z.start{o.current[l]=Z},href:v,onClick:()=>Vt(),class:qt(at.item,{[at.active]:l===vn()}),children:U("div",{class:at.wrapper,children:[U("div",{class:at.meta,children:U("menu",{class:at.path,children:d.map(Z=>U("li",{children:Z}))})}),U("h2",{class:at.title,children:p}),m&&U("div",{class:at.excerpt,children:m})]})})})})})]})}var Yu={container:"a"};function Ju(e){let t=Qa();return Ca(!0,r=>{var n,o,i,a,s;if(!t)if((r.metaKey||r.ctrlKey)&&r.key==="k")r.preventDefault(),Vt();else if((r.metaKey||r.ctrlKey)&&r.key==="j")document.body.classList.toggle("dark");else if(r.key==="Enter"&&!sr()){r.preventDefault();let c=vn(),l=(o=(n=st.value)==null?void 0:n.items[c])==null?void 0:o.id;if((a=(i=lr.value)==null?void 0:i.items[l])!=null&&a.location){Vt();let u=(s=lr.value)==null?void 0:s.items[l].location;if(Ka()){let p=encodeURIComponent(Tn()),[d,m]=u.split("#",2);u=`${d}?h=${p.replace(/%20/g,"+")}`,typeof m<"u"&&(u+=`#${m}`)}window.location.href=u}}else r.key==="Escape"&&!sr()&&(r.preventDefault(),Vt())},[t]),U("div",{class:Yu.container,children:[U(ju,{hidden:sr()}),U(qu,{hidden:sr()})]})}function es(e,t){fu(e),kl(U(Ju,{}),t)}function bo(){Vt()}function Xu(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Zu(){return R(b(window,"compositionstart").pipe(f(()=>!0)),b(window,"compositionend").pipe(f(()=>!1))).pipe(J(!1))}function ts(){let e=b(window,"keydown").pipe(f(t=>({mode:sr()?"global":"search",type:t.key,meta:t.ctrlKey||t.metaKey,claim(){t.preventDefault(),t.stopPropagation()}})),O(({mode:t,type:r})=>{if(t==="global"){let n=xt();if(typeof n!="undefined")return!Xu(n,r)}return!0}),xe());return Zu().pipe(g(t=>t?w:e))}function Ue(){return new URL(location.href)}function dt(e,t=!1){if(X("navigation.instant")&&!t){let r=A("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function rs(){return new I}function ns(){return location.hash.slice(1)}function os(e){let t=A("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function go(e){return R(b(window,"hashchange"),e).pipe(f(ns),J(ns()),O(t=>t.length>0),f(decodeURIComponent),ae(1))}function is(e){return go(e).pipe(f(t=>we(`[id="${t}"]`)),O(t=>typeof t!="undefined"))}function Ir(e){let t=matchMedia(e);return sn(r=>t.addListener(()=>r(t.matches))).pipe(J(t.matches))}function as(){let e=matchMedia("print");return R(b(window,"beforeprint").pipe(f(()=>!0)),b(window,"afterprint").pipe(f(()=>!1))).pipe(J(e.matches))}function _o(e,t){return e.pipe(g(r=>r?t():w))}function yo(e,t){return new N(r=>{let n=new XMLHttpRequest;return n.open("GET",`${e}`),n.responseType="blob",n.addEventListener("load",()=>{n.status>=200&&n.status<300?(r.next(n.response),r.complete()):r.error(new Error(n.statusText))}),n.addEventListener("error",()=>{r.error(new Error("Network error"))}),n.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(n.addEventListener("progress",o=>{var i;if(o.lengthComputable)t.progress$.next(o.loaded/o.total*100);else{let a=(i=n.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(o.loaded/+a*100)}}),t.progress$.next(5)),n.send(),()=>n.abort()})}function tt(e,t){return yo(e,t).pipe(g(r=>r.text()),f(r=>JSON.parse(r)),ae(1))}function Sn(e,t){let r=new DOMParser;return yo(e,t).pipe(g(n=>n.text()),f(n=>r.parseFromString(n,"text/html")),ae(1))}function ss(e,t){let r=new DOMParser;return yo(e,t).pipe(g(n=>n.text()),f(n=>r.parseFromString(n,"text/xml")),ae(1))}var xo={drawer:Y("[data-md-toggle=drawer]"),search:Y("[data-md-toggle=search]")};function wo(e,t){xo[e].checked!==t&&xo[e].click()}function On(e){let t=xo[e];return b(t,"change").pipe(f(()=>t.checked),J(t.checked))}function cs(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function ls(){return R(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(f(cs),J(cs()))}function us(){return{width:innerWidth,height:innerHeight}}function ps(){return b(window,"resize",{passive:!0}).pipe(f(us),J(us()))}function fs(){return ne([ls(),ps()]).pipe(f(([e,t])=>({offset:e,size:t})),ae(1))}function Ln(e,{viewport$:t,header$:r}){let n=t.pipe(he("size")),o=ne([n,r]).pipe(f(()=>Et(e)));return ne([r,t,o]).pipe(f(([{height:i},{offset:a,size:s},{x:c,y:l}])=>({offset:{x:a.x-c,y:a.y-l+i},size:s})))}var Qu=Y("#__config"),mr=JSON.parse(Qu.textContent);mr.base=`${new URL(mr.base,Ue())}`;function Ne(){return mr}function X(e){return mr.features.includes(e)}function Gt(e,t){return typeof t!="undefined"?mr.translations[e].replace("#",t.toString()):mr.translations[e]}function ht(e,t=document){return Y(`[data-md-component=${e}]`,t)}function Te(e,t=document){return $(`[data-md-component=${e}]`,t)}function ep(e){let t=Y(".md-typeset > :first-child",e);return b(t,"click",{once:!0}).pipe(f(()=>Y(".md-typeset",e)),f(r=>({hash:__md_hash(r.innerHTML)})))}function ms(e){if(!X("announce.dismiss")||!e.childElementCount)return w;if(!e.hidden){let t=Y(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return j(()=>{let t=new I;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),ep(e).pipe(P(r=>t.next(r)),z(()=>t.complete()),f(r=>k({ref:e},r)))})}function tp(e,{target$:t}){return t.pipe(f(r=>({hidden:r!==e})))}function ds(e,t){let r=new I;return r.subscribe(({hidden:n})=>{e.hidden=n}),tp(e,t).pipe(P(n=>r.next(n)),z(()=>r.complete()),f(n=>k({ref:e},n)))}function Eo(e,t){return t==="inline"?A("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},A("div",{class:"md-tooltip__inner md-typeset"})):A("div",{class:"md-tooltip",id:e,role:"tooltip"},A("div",{class:"md-tooltip__inner md-typeset"}))}function Mn(...e){return A("div",{class:"md-tooltip2",role:"dialog"},A("div",{class:"md-tooltip2__inner md-typeset"},e))}function hs(...e){return A("div",{class:"md-tooltip2",role:"tooltip"},A("div",{class:"md-tooltip2__inner md-typeset"},e))}function vs(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return A("aside",{class:"md-annotation",tabIndex:0},Eo(t),A("a",{href:r,class:"md-annotation__index",tabIndex:-1},A("span",{"data-md-annotation-id":e})))}else return A("aside",{class:"md-annotation",tabIndex:0},Eo(t),A("span",{class:"md-annotation__index",tabIndex:-1},A("span",{"data-md-annotation-id":e})))}function bs(e){return A("button",{class:"md-code__button",title:Gt("clipboard.copy"),"data-clipboard-target":`#${e} > code`,"data-md-type":"copy"})}function gs(){return A("button",{class:"md-code__button",title:"Toggle line selection","data-md-type":"select"})}function _s(){return A("nav",{class:"md-code__nav"})}var op=_r(To());function xs(e){return A("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>A("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?Oi(r):r)))}function So(e){let t=`tabbed-control tabbed-control--${e}`;return A("div",{class:t,hidden:!0},A("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function ws(e){return A("div",{class:"md-typeset__scrollwrap"},A("div",{class:"md-typeset__table"},e))}function ip(e){var n;let t=Ne(),r=new URL(`../${e.version}/`,t.base);return A("li",{class:"md-version__item"},A("a",{href:`${r}`,class:"md-version__link"},e.title,((n=t.version)==null?void 0:n.alias)&&e.aliases.length>0&&A("span",{class:"md-version__alias"},e.aliases[0])))}function Es(e,t){var n;let r=Ne();return e=e.filter(o=>{var i;return!((i=o.properties)!=null&&i.hidden)}),A("div",{class:"md-version"},A("button",{class:"md-version__current","aria-label":Gt("select.version")},t.title,((n=r.version)==null?void 0:n.alias)&&t.aliases.length>0&&A("span",{class:"md-version__alias"},t.aliases[0])),A("ul",{class:"md-version__list"},e.map(ip)))}var ap=0;function sp(e,t=250){let r=ne([ar(e),Nt(e,t)]).pipe(f(([o,i])=>o||i),se()),n=j(()=>Ai(e)).pipe(ie(Dt),Lr(1),Qe(r),f(()=>Ci(e)));return r.pipe(Sr(o=>o),g(()=>ne([r,n])),f(([o,i])=>({active:o,offset:i})),xe())}function Rr(e,t,r=250){let{content$:n,viewport$:o}=t,i=`__tooltip2_${ap++}`;return j(()=>{let a=new I,s=new Dn(!1);a.pipe(be(),ye(!1)).subscribe(s);let c=s.pipe(Tr(u=>ze(+!u*250,zn)),se(),g(u=>u?n:w),P(u=>u.id=i),xe());ne([a.pipe(f(({active:u})=>u)),c.pipe(g(u=>Nt(u,250)),J(!1))]).pipe(f(u=>u.some(p=>p))).subscribe(s);let l=s.pipe(O(u=>u),fe(c,o),f(([u,p,{size:d}])=>{let m=e.getBoundingClientRect(),h=m.width/2;if(p.role==="tooltip")return{x:h,y:8+m.height};if(m.y>=d.height/2){let{height:v}=Ae(p);return{x:h,y:-16-v}}else return{x:h,y:16+m.height}}));return ne([c,a,l]).subscribe(([u,{offset:p},d])=>{u.style.setProperty("--md-tooltip-host-x",`${p.x}px`),u.style.setProperty("--md-tooltip-host-y",`${p.y}px`),u.style.setProperty("--md-tooltip-x",`${d.x}px`),u.style.setProperty("--md-tooltip-y",`${d.y}px`),u.classList.toggle("md-tooltip2--top",d.y<0),u.classList.toggle("md-tooltip2--bottom",d.y>=0)}),s.pipe(O(u=>u),fe(c,(u,p)=>p),O(u=>u.role==="tooltip")).subscribe(u=>{let p=Ae(Y(":scope > *",u));u.style.setProperty("--md-tooltip-width",`${p.width}px`),u.style.setProperty("--md-tooltip-tail","0px")}),s.pipe(se(),Ie(je),fe(c)).subscribe(([u,p])=>{p.classList.toggle("md-tooltip2--active",u)}),ne([s.pipe(O(u=>u)),c]).subscribe(([u,p])=>{p.role==="dialog"?(e.setAttribute("aria-controls",i),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",i)}),s.pipe(O(u=>!u)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),sp(e,r).pipe(P(u=>a.next(u)),z(()=>a.complete()),f(u=>k({ref:e},u)))})}function Je(e,{viewport$:t},r=document.body){return Rr(e,{content$:new N(n=>{let o=e.title,i=hs(o);return n.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",o)}}),viewport$:t},0)}function cp(e,t){let r=j(()=>ne([Hi(e),Dt(t)])).pipe(f(([{x:n,y:o},i])=>{let{width:a,height:s}=Ae(e);return{x:n-i.x+a/2,y:o-i.y+s/2}}));return ar(e).pipe(g(n=>r.pipe(f(o=>({active:n,offset:o})),Me(+!n||1/0))))}function Ts(e,t,{target$:r}){let[n,o]=Array.from(e.children);return j(()=>{let i=new I,a=i.pipe(be(),ye(!0));return i.subscribe({next({offset:s}){e.style.setProperty("--md-tooltip-x",`${s.x}px`),e.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),Tt(e).pipe(ee(a)).subscribe(s=>{e.toggleAttribute("data-md-visible",s)}),R(i.pipe(O(({active:s})=>s)),i.pipe(Ye(250),O(({active:s})=>!s))).subscribe({next({active:s}){s?e.prepend(n):n.remove()},complete(){e.prepend(n)}}),i.pipe(Ze(16,je)).subscribe(({active:s})=>{n.classList.toggle("md-tooltip--active",s)}),i.pipe(Lr(125,je),O(()=>!!e.offsetParent),f(()=>e.offsetParent.getBoundingClientRect()),f(({x:s})=>s)).subscribe({next(s){s?e.style.setProperty("--md-tooltip-0",`${-s}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),b(o,"click").pipe(ee(a),O(s=>!(s.metaKey||s.ctrlKey))).subscribe(s=>{s.stopPropagation(),s.preventDefault()}),b(o,"mousedown").pipe(ee(a),fe(i)).subscribe(([s,{active:c}])=>{var l;if(s.button!==0||s.metaKey||s.ctrlKey)s.preventDefault();else if(c){s.preventDefault();let u=e.parentElement.closest(".md-annotation");u instanceof HTMLElement?u.focus():(l=xt())==null||l.blur()}}),r.pipe(ee(a),O(s=>s===n),jt(125)).subscribe(()=>e.focus()),cp(e,t).pipe(P(s=>i.next(s)),z(()=>i.complete()),f(s=>k({ref:e},s)))})}function lp(e){let t=Ne();if(e.tagName!=="CODE")return[e];let r=[".c",".c1",".cm"];if(t.annotate){let n=e.closest("[class|=language]");if(n)for(let o of Array.from(n.classList)){if(!o.startsWith("language-"))continue;let[,i]=o.split("-");i in t.annotate&&r.push(...t.annotate[i])}}return $(r.join(", "),e)}function up(e){let t=[];for(let r of lp(e)){let n=[],o=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=o.nextNode();i;i=o.nextNode())n.push(i);for(let i of n){let a;for(;a=/(\(\d+\))(!)?/.exec(i.textContent);){let[,s,c]=a;if(typeof c=="undefined"){let l=i.splitText(a.index);i=l.splitText(s.length),t.push(l)}else{i.textContent=s,t.push(i);break}}}}return t}function Ss(e,t){t.append(...Array.from(e.childNodes))}function kn(e,t,{target$:r,print$:n}){let o=t.closest("[id]"),i=o==null?void 0:o.id,a=new Map;for(let s of up(t)){let[,c]=s.textContent.match(/\((\d+)\)/);we(`:scope > li:nth-child(${c})`,e)&&(a.set(c,vs(c,i)),s.replaceWith(a.get(c)))}return a.size===0?w:j(()=>{let s=new I,c=s.pipe(be(),ye(!0)),l=[];for(let[u,p]of a)l.push([Y(".md-typeset",p),Y(`:scope > li:nth-child(${u})`,e)]);return n.pipe(ee(c)).subscribe(u=>{e.hidden=!u,e.classList.toggle("md-annotation-list",u);for(let[p,d]of l)u?Ss(p,d):Ss(d,p)}),R(...[...a].map(([,u])=>Ts(u,t,{target$:r}))).pipe(z(()=>s.complete()),xe())})}function Os(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Os(t)}}function Ls(e,t){return j(()=>{let r=Os(e);return typeof r!="undefined"?kn(r,e,t):w})}var ks=_r(Lo());var pp=0,Ms=R(b(window,"keydown").pipe(f(()=>!0)),R(b(window,"keyup"),b(window,"contextmenu")).pipe(f(()=>!1))).pipe(J(!1),ae(1));function As(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return As(t)}}function fp(e){return Re(e).pipe(f(({width:t})=>({scrollable:Mr(e).width>t})),he("scrollable"))}function Cs(e,t){let{matches:r}=matchMedia("(hover)"),n=j(()=>{let o=new I,i=o.pipe(Jn(1));o.subscribe(({scrollable:m})=>{m&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let a=[],s=e.closest("pre"),c=s.closest("[id]"),l=c?c.id:pp++;s.id=`__code_${l}`;let u=[],p=e.closest(".highlight");if(p instanceof HTMLElement){let m=As(p);if(typeof m!="undefined"&&(p.classList.contains("annotate")||X("content.code.annotate"))){let h=kn(m,e,t);u.push(Re(p).pipe(ee(i),f(({width:v,height:y})=>v&&y),se(),g(v=>v?h:w)))}}let d=$(":scope > span[id]",e);if(d.length&&(e.classList.add("md-code__content"),e.closest(".select")||X("content.code.select")&&!e.closest(".no-select"))){let m=+d[0].id.split("-").pop(),h=gs();a.push(h),X("content.tooltips")&&u.push(Je(h,{viewport$}));let v=b(h,"click").pipe(Or(L=>!L,!1),P(()=>h.blur()),xe());v.subscribe(L=>{h.classList.toggle("md-code__button--active",L)});let y=me(d).pipe(ie(L=>Nt(L).pipe(f(M=>[L,M]))));v.pipe(g(L=>L?y:w)).subscribe(([L,M])=>{let D=we(".hll.select",L);if(D&&!M)D.replaceWith(...Array.from(D.childNodes));else if(!D&&M){let te=document.createElement("span");te.className="hll select",te.append(...Array.from(L.childNodes).slice(1)),L.append(te)}});let x=me(d).pipe(ie(L=>b(L,"mousedown").pipe(P(M=>M.preventDefault()),f(()=>L)))),E=v.pipe(g(L=>L?x:w),fe(Ms),f(([L,M])=>{var te;let D=d.indexOf(L)+m;if(M===!1)return[D,D];{let ue=$(".hll",e).map(le=>d.indexOf(le.parentElement)+m);return(te=window.getSelection())==null||te.removeAllRanges(),[Math.min(D,...ue),Math.max(D,...ue)]}})),_=go(w).pipe(O(L=>L.startsWith(`__codelineno-${l}-`)));_.subscribe(L=>{let[,,M]=L.split("-"),D=M.split(":").map(ue=>+ue-m+1);D.length===1&&D.push(D[0]);for(let ue of $(".hll:not(.select)",e))ue.replaceWith(...Array.from(ue.childNodes));let te=d.slice(D[0]-1,D[1]);for(let ue of te){let le=document.createElement("span");le.className="hll",le.append(...Array.from(ue.childNodes).slice(1)),ue.append(le)}}),_.pipe(Me(1),Ie(_e)).subscribe(L=>{if(L.includes(":")){let M=document.getElementById(L.split(":")[0]);M&&setTimeout(()=>{let D=M,te=-64;for(;D!==document.body;)te+=D.offsetTop,D=D.offsetParent;window.scrollTo({top:te})},1)}});let ve=me($('a[href^="#__codelineno"]',p)).pipe(ie(L=>b(L,"click").pipe(P(M=>M.preventDefault()),f(()=>L)))).pipe(ee(i),fe(Ms),f(([L,M])=>{let te=+Y(`[id="${L.hash.slice(1)}"]`).parentElement.id.split("-").pop();if(M===!1)return[te,te];{let ue=$(".hll",e).map(le=>+le.parentElement.id.split("-").pop());return[Math.min(te,...ue),Math.max(te,...ue)]}}));R(E,ve).subscribe(L=>{let M=`#__codelineno-${l}-`;L[0]===L[1]?M+=L[0]:M+=`${L[0]}:${L[1]}`,history.replaceState({},"",M),window.dispatchEvent(new HashChangeEvent("hashchange",{newURL:window.location.origin+window.location.pathname+M,oldURL:window.location.href}))})}if(ks.default.isSupported()&&(e.closest(".copy")||X("content.code.copy")&&!e.closest(".no-copy"))){let m=bs(s.id);a.push(m),X("content.tooltips")&&u.push(Je(m,{viewport$}))}if(a.length){let m=_s();m.append(...a),s.insertBefore(m,e)}return fp(e).pipe(P(m=>o.next(m)),z(()=>o.complete()),f(m=>k({ref:e},m)),Ft(R(...u).pipe(ee(i))))});return X("content.lazy")?Tt(e).pipe(O(o=>o),Me(1),g(()=>n)):n}function mp(e,{target$:t,print$:r}){let n=!0;return R(t.pipe(f(o=>o.closest("details:not([open])")),O(o=>e===o),f(()=>({action:"open",reveal:!0}))),r.pipe(O(o=>o||!n),P(()=>n=e.open),f(o=>({action:o?"open":"close"}))))}function Hs(e,t){return j(()=>{let r=new I;return r.subscribe(({action:n,reveal:o})=>{e.toggleAttribute("open",n==="open"),o&&e.scrollIntoView()}),mp(e,t).pipe(P(n=>r.next(n)),z(()=>r.complete()),f(n=>k({ref:e},n)))})}var $s;function dp(){return typeof GLightbox=="undefined"||GLightbox instanceof Element?wt("https://unpkg.com/glightbox@3/dist/js/glightbox.min.js").pipe(de(()=>w),f(()=>{})):K(void 0)}function hp(){return Li("https://unpkg.com/glightbox@3/dist/css/glightbox.min.css").pipe(de(()=>w),f(()=>{}))}function Ps(e){return $s||($s=dp().pipe(f(()=>new GLightbox(k({touchNavigation:!0,loop:!1,zoomable:!0,draggable:!0,openEffect:"zoom",closeEffect:"zoom",slideEffect:"slide",onOpen:()=>{document.activeElement instanceof HTMLElement&&document.activeElement.blur()}},typeof GLightboxOptions!="undefined"?GLightboxOptions:{}))),ae(1))),hp().pipe(g(()=>$s)).pipe(g(t=>(t.setElements(e),e.map((r,n)=>(b(r,"click").subscribe(o=>{o.preventDefault(),t.openAt(n)}),{ref:r})))))}var Is=0,Rs=new Map;function vp(e){let t=document.createElement("h3");t.innerHTML=e.innerHTML;let r=[t],n=e.nextElementSibling;for(;n&&!(n instanceof HTMLHeadingElement);)r.push(n.cloneNode(!0)),n=n.nextElementSibling;return r}function bp(e,t){for(let r of $("[href], [src]",e))for(let n of["href","src"]){let o=r.getAttribute(n);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){r[n]=new URL(r.getAttribute(n),t).toString();break}}for(let r of $("[name^=__], [for]",e))for(let n of["id","for","name"]){let o=r.getAttribute(n);o&&r.setAttribute(n,`${o}$preview_${Is}`)}return Is++,K(e)}function gp(e){let t=Rs.get(e.toString());return t?K(t):Sn(e).pipe(g(r=>bp(r,e)),f(r=>(Rs.set(e.toString(),r),r)))}function js(e,t){let{sitemap$:r}=t;if(!(e instanceof HTMLAnchorElement))return w;if(!(X("navigation.instant.preview")||e.hasAttribute("data-preview")))return w;e.removeAttribute("title");let n=ne([ar(e),Nt(e).pipe(ke(1))]).pipe(f(([i,a])=>i||a),se(),O(i=>i));return It([r,n]).pipe(g(([i])=>{let a=new URL(e.href);return a.search=a.hash="",i.has(`${a}`)?K(a):w}),g(i=>gp(i)),g(i=>{let a=e.hash?`article [id="${decodeURIComponent(e.hash.slice(1))}"]`:"article h1",s=we(a,i);return typeof s=="undefined"?w:K(vp(s))})).pipe(g(i=>{let a=new N(s=>{let c=Mn(...i);return s.next(c),document.body.append(c),()=>c.remove()});return Rr(e,k({content$:a},t))}))}var Fs=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.flowchartTitleText{fill:var(--md-mermaid-label-fg-color)}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel p,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel p{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color)}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}.classDiagramTitleText{fill:var(--md-mermaid-label-fg-color)}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs marker.marker.composition.class path,defs marker.marker.dependency.class path,defs marker.marker.extension.class path{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs marker.marker.aggregation.class path{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}.statediagramTitleText{fill:var(--md-mermaid-label-fg-color)}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}a .nodeLabel{text-decoration:underline}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}[id^=entity] path,[id^=entity] rect{fill:var(--md-default-bg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs .marker.oneOrMore.er *,defs .marker.onlyOne.er *,defs .marker.zeroOrMore.er *,defs .marker.zeroOrOne.er *{stroke:var(--md-mermaid-edge-color)!important}text:not([class]):last-child{fill:var(--md-mermaid-label-fg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}.actor-line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}[id$=-arrowhead] path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var Mo,yp=0;function xp(){return typeof mermaid=="undefined"||mermaid instanceof Element?wt("https://unpkg.com/mermaid@11/dist/mermaid.min.js"):K(void 0)}function Us(e){return e.classList.remove("mermaid"),Mo||(Mo=xp().pipe(P(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Fs,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),f(()=>{}),ae(1))),Mo.subscribe(()=>Fo(null,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${yp++}`,r=A("div",{class:"mermaid"}),n=e.textContent,{svg:o,fn:i}=yield mermaid.render(t,n),a=r.attachShadow({mode:"closed"});a.innerHTML=o,e.replaceWith(r),i==null||i(a)})),Mo.pipe(f(()=>({ref:e})))}var Ns=A("table");function Ds(e){return e.replaceWith(Ns),Ns.replaceWith(ws(e)),K({ref:e})}function wp(e){let t=e.find(r=>r.checked)||e[0];return R(...e.map(r=>b(r,"change").pipe(f(()=>Y(`label[for="${r.id}"]`))))).pipe(J(Y(`label[for="${t.id}"]`)),f(r=>({active:r})))}function Ws(e,{viewport$:t,target$:r}){let n=Y(".tabbed-labels",e),o=$(":scope > input",e),i=So("prev");e.append(i);let a=So("next");return e.append(a),j(()=>{let s=new I,c=s.pipe(be(),ye(!0));ne([s,Re(e),Tt(e)]).pipe(ee(c),Ze(1,je)).subscribe({next([{active:l},u]){let p=Et(l),{width:d}=Ae(l);e.style.setProperty("--md-indicator-x",`${p.x}px`),e.style.setProperty("--md-indicator-width",`${d}px`);let m=pn(n);(p.xm.x+u.width)&&n.scrollTo({left:Math.max(0,p.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),ne([Dt(n),Re(n)]).pipe(ee(c)).subscribe(([l,u])=>{let p=Mr(n);i.hidden=l.x<16,a.hidden=l.x>p.width-u.width-16}),R(b(i,"click").pipe(f(()=>-1)),b(a,"click").pipe(f(()=>1))).pipe(ee(c)).subscribe(l=>{let{width:u}=Ae(n);n.scrollBy({left:u*l,behavior:"smooth"})}),r.pipe(ee(c),O(l=>o.includes(l))).subscribe(l=>l.click()),n.classList.add("tabbed-labels--linked");for(let l of o){let u=Y(`label[for="${l.id}"]`);u.replaceChildren(A("a",{href:`#${u.htmlFor}`,tabIndex:-1},...Array.from(u.childNodes))),b(u.firstElementChild,"click").pipe(ee(c),O(p=>!(p.metaKey||p.ctrlKey)),P(p=>{p.preventDefault(),p.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${u.htmlFor}`),u.click()})}return X("content.tabs.link")&&s.pipe(ke(1),fe(t)).subscribe(([{active:l},{offset:u}])=>{let p=l.innerText.trim();if(l.hasAttribute("data-md-switching"))l.removeAttribute("data-md-switching");else{let d=e.offsetTop-u.y;for(let h of $("[data-tabs]"))for(let v of $(":scope > input",h)){let y=Y(`label[for="${v.id}"]`);if(y!==l&&y.innerText.trim()===p){y.setAttribute("data-md-switching",""),v.click();break}}window.scrollTo({top:e.offsetTop-d});let m=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([p,...m])])}}),s.pipe(ee(c)).subscribe(()=>{for(let l of $("audio, video",e))l.offsetWidth&&l.autoplay?l.play().catch(()=>{}):l.pause()}),wp(o).pipe(P(l=>s.next(l)),z(()=>s.complete()),f(l=>k({ref:e},l)))}).pipe(Pt(_e))}function Vs(e,t){let{viewport$:r,target$:n,print$:o}=t;return R(...$(".annotate:not(.highlight)",e).map(i=>Ls(i,{target$:n,print$:o})),...$("pre:not(.mermaid) > code",e).map(i=>Cs(i,{target$:n,print$:o})),...$("a",e).map(i=>js(i,t)),...$("pre.mermaid",e).map(i=>Us(i)),...[$(".glightbox",e)].filter(i=>i.length>0).map(i=>Ps(i)),...$("table:not([class])",e).map(i=>Ds(i)),...$("details",e).map(i=>Hs(i,{target$:n,print$:o})),...$("[data-tabs]",e).map(i=>Ws(i,{viewport$:r,target$:n})),...$("[title]:not([data-preview])",e).filter(()=>X("content.tooltips")).map(i=>Je(i,{viewport$:r})),...$(".footnote-ref",e).filter(()=>X("content.footnote.tooltips")).map(i=>Rr(i,{content$:new N(a=>{let s=new URL(i.href).hash.slice(1),c=Array.from(document.getElementById(s).cloneNode(!0).children),l=Mn(...c);return a.next(l),document.body.append(l),()=>l.remove()}),viewport$:r})))}function Ep(e,{alert$:t}){return t.pipe(g(r=>R(K(!0),K(!1).pipe(jt(2e3))).pipe(f(n=>({message:r,active:n})))))}function zs(e,t){let r=Y(".md-typeset",e);return j(()=>{let n=new I;return n.subscribe(({message:o,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=o}),Ep(e,t).pipe(P(o=>n.next(o)),z(()=>n.complete()),f(o=>k({ref:e},o)))})}function Tp({viewport$:e}){if(!X("header.autohide"))return K(!1);let t=e.pipe(f(({offset:{y:o}})=>o),Rt(2,1),f(([o,i])=>[oMath.abs(i-o.y)>100),f(([,[o]])=>o),se()),n=On("search");return ne([e,n]).pipe(f(([{offset:o},i])=>o.y>400&&!i),se(),g(o=>o?r:K(!1)),J(!1))}function qs(e,t){return j(()=>ne([Re(e),Tp(t)])).pipe(f(([{height:r},n])=>({height:r,hidden:n})),se((r,n)=>r.height===n.height&&r.hidden===n.hidden),ae(1))}function Ks(e,{viewport$:t,header$:r,main$:n}){return j(()=>{let o=new I,i=o.pipe(be(),ye(!0));o.pipe(he("active"),Qe(r)).subscribe(([{active:s},{hidden:c}])=>{e.classList.toggle("md-header--shadow",s&&!c),e.hidden=c});let a=me($("[title]",e)).pipe(O(()=>X("content.tooltips")),ie(s=>Je(s,{viewport$:t})));return n.subscribe(o),r.pipe(ee(i),f(s=>k({ref:e},s)),Ft(a.pipe(ee(i))))})}function Sp(e,{viewport$:t,header$:r}){return Ln(e,{viewport$:t,header$:r}).pipe(f(({offset:{y:n}})=>{let{height:o}=Ae(e);return{active:o>0&&n>=o}}),he("active"))}function Bs(e,t){return j(()=>{let r=new I;r.subscribe({next({active:o}){e.classList.toggle("md-header__title--active",o)},complete(){e.classList.remove("md-header__title--active")}});let n=we(".md-content h1");return typeof n=="undefined"?w:Sp(n,t).pipe(P(o=>r.next(o)),z(()=>r.complete()),f(o=>k({ref:e},o)))})}function Gs(e,{viewport$:t,header$:r}){let n=r.pipe(f(({height:i})=>i),se()),o=n.pipe(g(()=>Re(e).pipe(f(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),he("bottom"))));return ne([n,o,t]).pipe(f(([i,{top:a,bottom:s},{offset:{y:c},size:{height:l}}])=>(l=Math.max(0,l-Math.max(0,a-c,i)-Math.max(0,l+c-s)),{offset:a-i,height:l,active:a-i<=c})),se((i,a)=>i.offset===a.offset&&i.height===a.height&&i.active===a.active))}function Op(e){let t=__md_get("__palette")||{index:e.findIndex(n=>matchMedia(n.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return K(...e).pipe(ie(n=>b(n,"change").pipe(f(()=>n))),J(e[r]),f(n=>({index:e.indexOf(n),color:{media:n.getAttribute("data-md-color-media"),scheme:n.getAttribute("data-md-color-scheme"),primary:n.getAttribute("data-md-color-primary"),accent:n.getAttribute("data-md-color-accent")}})),ae(1))}function Ys(e){let t=$("input",e),r=A("meta",{name:"theme-color"});document.head.appendChild(r);let n=A("meta",{name:"color-scheme"});document.head.appendChild(n);let o=Ir("(prefers-color-scheme: light)");return j(()=>{let i=new I;return i.subscribe(a=>{if(document.body.setAttribute("data-md-color-switching",""),a.color.media==="(prefers-color-scheme)"){let s=matchMedia("(prefers-color-scheme: light)"),c=document.querySelector(s.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");a.color.scheme=c.getAttribute("data-md-color-scheme"),a.color.primary=c.getAttribute("data-md-color-primary"),a.color.accent=c.getAttribute("data-md-color-accent")}for(let[s,c]of Object.entries(a.color))document.body.setAttribute(`data-md-color-${s}`,c);for(let s=0;sa.key==="Enter"),fe(i,(a,s)=>s)).subscribe(({index:a})=>{a=(a+1)%t.length,t[a].click(),t[a].focus()}),i.pipe(f(()=>{let a=ht("header"),s=window.getComputedStyle(a);return n.content=s.colorScheme,s.backgroundColor.match(/\d+/g).map(c=>(+c).toString(16).padStart(2,"0")).join("")})).subscribe(a=>r.content=`#${a}`),i.pipe(Ie(_e)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),Op(t).pipe(ee(o.pipe(ke(1))),Ut(),P(a=>i.next(a)),z(()=>i.complete()),f(a=>k({ref:e},a)))})}function Js(e,{progress$:t}){return j(()=>{let r=new I;return r.subscribe(({value:n})=>{e.style.setProperty("--md-progress-value",`${n}`)}),t.pipe(P(n=>r.next({value:n})),z(()=>r.complete()),f(n=>({ref:e,value:n})))})}var Xs='.m u{text-decoration:underline!important;text-decoration-style:wavy!important;text-decoration-thickness:1px!important}.p{-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);background-color:rgba(var(--color-backdrop)/var(--alpha-lighter));cursor:pointer;height:100%;pointer-events:auto;position:absolute;transition:opacity .25s;width:100%}.p.v{opacity:0;pointer-events:none;transition:opacity .35s}.r{align-items:center;background-color:initial;border:none;border-radius:var(--space-2);cursor:pointer;display:flex;flex-shrink:0;font-family:var(--font-family);height:36px;justify-content:center;outline:none;padding:0;position:relative;transition:background-color .25s,color .25s;width:36px;z-index:1}.r svg{stroke:rgb(var(--color-foreground));height:18px;opacity:.5;width:18px}.r:before{background-color:rgb(var(--color-background-subtle));border-radius:var(--border-radius-2);content:"";inset:0;opacity:0;position:absolute;transform:scale(.75);transition:transform 125ms,opacity 125ms;z-index:0}.r:hover:before{opacity:1;transform:scale(1)}.r.c{cursor:auto}.r.c:before{display:none}.n{-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);background-color:rgba(var(--color-background)/var(--alpha-light));border:1px solid rgb(var(--color-foreground)/var(--alpha-lightest));border-radius:var(--space-3);box-shadow:0 0 60px #0000000d;display:flex;height:480px;overflow:hidden;pointer-events:auto;position:absolute;transition:transform .25s cubic-bezier(.16,1,.3,1),opacity .25s;width:640px}.n.l{opacity:0;pointer-events:none;transform:scale(1.1);transition:transform .25s .15s,opacity .15s}@media (max-width:680px){.n{border-radius:0;height:100%;width:100%}}.y{display:flex;flex:1 1 auto;flex-direction:column;min-height:0;min-width:0}@keyframes d{0%{transform:scale(0)}50%{transform:scale(1.2)}to{transform:scale(1)}}.w{animation:d .25s ease-in-out;background:var(--color-highlight);border-radius:100%;color:#fff;font-size:8px;font-weight:700;height:12px;padding-top:1px;position:absolute;right:4px;top:4px;width:12px}.e{background-color:rgb(var(--color-background-subtle)/var(--alpha-lighter));border-left:1px solid rgb(var(--color-foreground)/var(--alpha-lightest));flex-shrink:0;overflow:scroll;position:relative;transition:width .35s cubic-bezier(.16,1,.3,1),opacity .25s;width:200px}.e>*{transform:translate(0);transition:transform .25s cubic-bezier(.16,1,.3,1)}.e.l{opacity:0;width:0}.e.l>*{transform:translate(-48px)}@media (max-width:680px){.e{-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);background-color:rgba(var(--color-background-subtle)/var(--alpha-light));box-shadow:0 0 60px #00000026;height:100%;position:absolute;right:0;top:0}}.k{border-bottom:1px solid rgb(var(--color-foreground)/var(--alpha-lightest));display:flex;gap:var(--space-1);padding:var(--space-2)}.z{-webkit-overflow-scrolling:touch;flex:1 1 auto;min-height:0;overflow:auto;overscroll-behavior:contain}.j{padding:8px 10px}.X{color:rgb(var(--color-foreground)/var(--alpha-light));padding:var(--space-2);position:absolute;width:200px}.F,.X{display:flex;flex-direction:column}.F{gap:2px;list-style:none;padding:0}.F,.I{margin:0}.I{font-size:16px;font-weight:400}.I,.R{padding:8px}.R{font-size:14px;margin:4px 0 0;opacity:.5}.R,.o{font-size:12px}.o{cursor:pointer;display:flex;padding:4px 8px;position:relative}.o:before{background-color:var(--color-highlight-transparent);border-radius:var(--space-1);content:"";inset:0;opacity:0;position:absolute;transform:scale(.75);transition:transform 125ms,opacity 125ms;z-index:0}.o.g:before,.o:hover:before{opacity:1;transform:scale(1)}.o.g,.o:hover{color:var(--color-highlight)}.q{flex-grow:1}.A,.q{position:relative}.A{font-weight:700}.f{flex-grow:1}.f input{background:#0000;border:none;color:rgb(var(--color-foreground));font-family:var(--font-family);font-size:16px;height:100%;letter-spacing:-.25px;outline:none;width:100%}.b{color:rgb(var(--color-foreground)/var(--alpha-light));display:flex;flex-direction:column;gap:2px;line-height:1.3;list-style:none;margin:var(--space-2);margin-top:0;padding:0}.B,.b li{margin:0}.B{color:rgb(var(--color-foreground)/var(--alpha-lighter));font-size:12px;margin-top:var(--space-2);padding:0 18px}.i{border-radius:var(--space-2);color:inherit;cursor:pointer;display:flex;flex-direction:row;flex-grow:1;padding:8px 10px;position:relative;text-decoration:none}.i:before{background-color:rgb(var(--color-background-subtle));border-radius:var(--border-radius-2);content:"";display:block;inset:0;opacity:0;position:absolute;transform:scale(.9);transition:transform 125ms,opacity 125ms;z-index:0}@media (pointer:fine){.i.h:before,.i:hover:before{opacity:1;transform:scale(1)}}.i mark{background:#0000;color:var(--color-highlight)}.i u{text-decoration:underline}.C{flex-direction:column;flex-grow:1;gap:5.5px}.C,.D{display:flex;min-width:0}.D{align-items:flex-start;gap:var(--space-2);justify-content:space-between}.s{align-items:flex-end;align-self:flex-end;display:flex;flex-direction:column;gap:6px;justify-content:flex-end;margin-right:-8px;margin-top:auto;opacity:0;position:relative;transform:translate(-2px);transition:transform 125ms,opacity 125ms;z-index:0}@media (pointer:fine){.h>.s,:hover>.s{opacity:1;transform:none}}.x{font-size:14px;margin:0;position:relative}.x code{background:rgb(var(--color-background-subtle));border-radius:var(--space-1);font-size:13px;padding:2px 4px}.t{color:rgb(var(--color-foreground)/.45);display:inline-flex;flex:1 1 auto;flex-wrap:wrap;font-size:12px;gap:var(--space-1);list-style:none;margin:0;min-width:0;padding:0;position:relative}.t li{white-space:nowrap}.t li:after{content:"/";display:inline;margin-left:var(--space-1)}.t li:last-child:after{content:"";display:none}.u{-webkit-box-orient:vertical;-webkit-line-clamp:2;color:rgb(var(--color-foreground));display:-webkit-box;font-size:12px;line-height:1.5;overflow:hidden;position:relative}.u code{background:rgb(var(--color-background-subtle));border-radius:var(--space-1);padding:2px 4px}.E,.u code{font-size:11px}.E{color:rgb(var(--color-foreground)/.45);line-height:1;white-space:nowrap;z-index:1}.a{--space-1:4px;--space-2:calc(var(--space-1)*2);--space-3:calc(var(--space-2)*2);--space-4:calc(var(--space-3)*2);--space-5:calc(var(--space-4)*2);--alpha-light:.7;--alpha-lighter:.54;--alpha-lightest:.07;--color-highlight:var(--md-accent-fg-color,#526cfe);--color-highlight-transparent:var( --md-accent-fg-color--transparent,#526cfe1a );--border-radius-1:var(--space-1);--border-radius-2:var(--space-2);--border-radius-3:calc(var(--space-1) + var(--space-2));--font-family:var( --md-text-font-family,Inter,Roboto Flex,system-ui,sans-serif );--font-size:16px;--line-height:1.5;--letter-spacing:-.5px;-webkit-font-smoothing:antialiased;align-items:center;display:flex;font-family:var(--font-family);font-size:var(--font-size);height:100vh;justify-content:center;letter-spacing:var(--letter-spacing);line-height:var(--line-height);pointer-events:none;position:absolute;width:100vw}@media (pointer:coarse){.a{height:-webkit-fill-available}}.a *,.a :after,.a :before{box-sizing:border-box}';function Zs(e,{index$:t}){let r=Ne(),n=document.createElement("div");document.body.appendChild(n),n.style.position="fixed",n.style.height="100%",n.style.top="0",n.style.zIndex="4";let o=n.attachShadow({mode:"open"});o.appendChild(A("style",{},Xs.toString()));try{Xa(r.search,{highlight:r.features.includes("search.highlight")}),me(t).subscribe(i=>{for(let a of i.items)a.location=new URL(`./${a.location}`,r.base).toString();es(i,o)}),b(e,"click").subscribe(()=>{bo()}),On("search").pipe(ke(1)).subscribe(()=>bo())}catch(i){e.hidden=!0;let a=Y("label[for=__search]");a.hidden=!0}return Ge}var Qs=_r(To());function ec(e,{index$:t,location$:r}){return ne([t,r.pipe(J(Ue()),O(n=>!!n.searchParams.get("h")))]).pipe(f(([n,o])=>Mp(n.config)(o.searchParams.get("h"))),f(n=>{var a;let o=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let s=i.nextNode();s;s=i.nextNode())if((a=s.parentElement)!=null&&a.offsetHeight){let c=s.textContent,l=n(c);l.length>c.length&&o.set(s,l)}for(let[s,c]of o){let{childNodes:l}=A("span",null,c);s.replaceWith(...Array.from(l))}return{ref:e,nodes:o}}))}function Mp(e){let t=e.separator.split("|").map(o=>o.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":o).join("|"),r=new RegExp(t,"img"),n=(o,i,a)=>`${i}${a}`;return o=>{o=o.replace(/\s+/g," ").replace(/&/g,"&").trim();let i=new RegExp(`(^|${e.separator}|)(${o.split(r).map(a=>a.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&")).filter(a=>a.length>=2).join("|")})`,"img");return a=>(0,Qs.default)(a).replace(i,n).replace(/<\/mark>(\s+)]*>/img,"$1")}}function kp(e,{viewport$:t,main$:r}){let n=e.closest(".md-grid"),o=n.offsetTop-n.parentElement.offsetTop;return ne([r,t]).pipe(f(([{offset:i,height:a},{offset:{y:s}}])=>(a=a+Math.min(o,Math.max(0,s-i))-o,{height:a,locked:s>=i+o})),se((i,a)=>i.height===a.height&&i.locked===a.locked))}function ko(e,n){var o=n,{header$:t}=o,r=gr(o,["header$"]);let i=Y(".md-sidebar__scrollwrap",e),{y:a}=Et(i);return j(()=>{let s=new I,c=s.pipe(be(),ye(!0)),l=s.pipe(Ze(0,je));return l.pipe(fe(t)).subscribe({next([{height:u},{height:p}]){i.style.height=`${u-2*a}px`,e.style.top=`${p}px`},complete(){i.style.height="",e.style.top=""}}),l.pipe(Sr()).subscribe(()=>{for(let u of $(".md-nav__link--active[href]",e)){if(!u.clientHeight)continue;let p=u.closest(".md-sidebar__scrollwrap");if(typeof p!="undefined"){let d=u.offsetTop-p.offsetTop,{height:m}=Ae(p);p.scrollTo({top:d-m/2})}}}),me($("label[tabindex]",e)).pipe(ie(u=>b(u,"click").pipe(Ie(_e),f(()=>u),ee(c)))).subscribe(u=>{let p=Y(`[id="${u.htmlFor}"]`);Y(`[aria-labelledby="${u.id}"]`).setAttribute("aria-expanded",`${p.checked}`)}),X("content.tooltips")&&me($("abbr[title]",e)).pipe(ie(u=>Je(u,{viewport$})),ee(c)).subscribe(),kp(e,r).pipe(P(u=>s.next(u)),z(()=>s.complete()),f(u=>k({ref:e},u)))})}function tc(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return It(tt(`${r}/releases/latest`).pipe(de(()=>w),f(n=>({version:n.tag_name})),it({})),tt(r).pipe(de(()=>w),f(n=>({stars:n.stargazers_count,forks:n.forks_count})),it({}))).pipe(f(([n,o])=>k(k({},n),o)))}else{let r=`https://api.github.com/users/${e}`;return tt(r).pipe(f(n=>({repositories:n.public_repos})),it({}))}}function rc(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return It(tt(`${r}/releases/permalink/latest`).pipe(de(()=>w),f(({tag_name:n})=>({version:n})),it({})),tt(r).pipe(de(()=>w),f(({star_count:n,forks_count:o})=>({stars:n,forks:o})),it({}))).pipe(f(([n,o])=>k(k({},n),o)))}function nc(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,n]=t;return tc(r,n)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,n]=t;return rc(r,n)}return w}var Ap;function Cp(e){return Ap||(Ap=j(()=>{let t=__md_get("__source",sessionStorage);if(t)return K(t);if(Te("consent").length){let n=__md_get("__consent");if(!(n&&n.github))return w}return nc(e.href).pipe(P(n=>__md_set("__source",n,sessionStorage)))}).pipe(de(()=>w),O(t=>Object.keys(t).length>0),f(t=>({facts:t})),ae(1)))}function oc(e){let t=Y(":scope > :last-child",e);return j(()=>{let r=new I;return r.subscribe(({facts:n})=>{t.appendChild(xs(n)),t.classList.add("md-source__repository--active")}),Cp(e).pipe(P(n=>r.next(n)),z(()=>r.complete()),f(n=>k({ref:e},n)))})}function Hp(e,{viewport$:t,header$:r}){return Re(document.body).pipe(g(()=>Ln(e,{header$:r,viewport$:t})),f(({offset:{y:n}})=>({hidden:n>=10})),he("hidden"))}function ic(e,t){return j(()=>{let r=new I;return r.subscribe({next({hidden:n}){e.hidden=n},complete(){e.hidden=!1}}),(X("navigation.tabs.sticky")?K({hidden:!1}):Hp(e,t)).pipe(P(n=>r.next(n)),z(()=>r.complete()),f(n=>k({ref:e},n)))})}function $p(e,{viewport$:t,header$:r}){let n=new Map,o=$(".md-nav__link",e);for(let s of o){let c=decodeURIComponent(s.hash.substring(1)),l=we(`[id="${c}"]`);typeof l!="undefined"&&n.set(s,l)}let i=r.pipe(he("height"),f(({height:s})=>{let c=ht("main"),l=Y(":scope > :first-child",c);return s+.9*(l.offsetTop-c.offsetTop)}),xe());return Re(document.body).pipe(he("height"),g(s=>j(()=>{let c=[];return K([...n].reduce((l,[u,p])=>{for(;c.length&&n.get(c[c.length-1]).tagName>=p.tagName;)c.pop();let d=p.offsetTop;for(;!d&&p.parentElement;)p=p.parentElement,d=p.offsetTop;let m=p.offsetParent;for(;m;m=m.offsetParent)d+=m.offsetTop;return l.set([...c=[...c,u]].reverse(),d)},new Map))}).pipe(f(c=>new Map([...c].sort(([,l],[,u])=>l-u))),Qe(i),g(([c,l])=>t.pipe(Or(([u,p],{offset:{y:d},size:m})=>{let h=d+m.height>=Math.floor(s.height);for(;p.length;){let[,v]=p[0];if(v-l=d&&!h)p=[u.pop(),...p];else break}return[u,p]},[[],[...c]]),se((u,p)=>u[0]===p[0]&&u[1]===p[1])))))).pipe(f(([s,c])=>({prev:s.map(([l])=>l),next:c.map(([l])=>l)})),J({prev:[],next:[]}),Rt(2,1),f(([s,c])=>s.prev.length{let i=new I,a=i.pipe(be(),ye(!0));i.subscribe(({prev:c,next:l})=>{for(let[u]of l)u.classList.remove("md-nav__link--passed"),u.classList.remove("md-nav__link--active");for(let[u,[p]]of c.entries())p.classList.add("md-nav__link--passed"),p.classList.toggle("md-nav__link--active",u===c.length-1)});let s=we(".md-sidebar--secondary");if(typeof s!="undefined"&&b(document.body,"click").subscribe(c=>{let l=c.target;if(!s.contains(l)){let u=we(".md-nav__toggle",s);typeof u!="undefined"&&(u.checked=!1)}}),X("toc.follow")){let c=R(t.pipe(Ye(1),f(()=>{})),t.pipe(Ye(250),f(()=>"smooth")));i.pipe(O(({prev:l})=>l.length>0),Qe(n.pipe(Ie(_e))),fe(c)).subscribe(([[{prev:l}],u])=>{let[p]=l[l.length-1];if(p.offsetHeight){let d=ki(p);if(typeof d!="undefined"){let m=p.offsetTop-d.offsetTop,{height:h}=Ae(d);d.scrollTo({top:m-h/2,behavior:u})}}})}return X("navigation.tracking")&&t.pipe(ee(a),he("offset"),Ye(250),ke(1),ee(o.pipe(ke(1))),Ut({delay:250}),fe(i)).subscribe(([,{prev:c}])=>{let l=Ue(),u=c[c.length-1];if(u&&u.length){let[p]=u,{hash:d}=new URL(p.href);l.hash!==d&&(l.hash=d,history.replaceState({},"",`${l}`))}else l.hash="",history.replaceState({},"",`${l}`)}),$p(e,{viewport$:t,header$:r}).pipe(P(c=>i.next(c)),z(()=>i.complete()),f(c=>k({ref:e},c)))})}function Pp(e,{viewport$:t,main$:r,target$:n}){let o=t.pipe(f(({offset:{y:a}})=>a),Rt(2,1),f(([a,s])=>a>s&&s>0),se()),i=r.pipe(f(({active:a})=>a));return ne([i,o]).pipe(f(([a,s])=>!(a&&s)),se(),ee(n.pipe(ke(1))),ye(!0),Ut({delay:250}),f(a=>({hidden:a})))}function sc(e,{viewport$:t,header$:r,main$:n,target$:o}){let i=new I,a=i.pipe(be(),ye(!0));return i.subscribe({next({hidden:s}){e.hidden=s,s?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(ee(a),he("height")).subscribe(({height:s})=>{e.style.top=`${s+16}px`}),b(e,"click").subscribe(s=>{s.preventDefault(),window.scrollTo({top:0})}),Pp(e,{viewport$:t,main$:n,target$:o}).pipe(P(s=>i.next(s)),z(()=>i.complete()),f(s=>k({ref:e},s)))}function cc(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,t.port&&(e.port=t.port),e}function Ip(e,t){let r=new Map;for(let n of $("url",e)){let o=Y("loc",n),i=[cc(new URL(o.textContent),t)];r.set(`${i[0]}`,i);for(let a of $("[rel=alternate]",n)){let s=a.getAttribute("href");s!=null&&i.push(cc(new URL(s),t))}}return r}function dr(e){return ss(new URL("sitemap.xml",e)).pipe(f(t=>Ip(t,new URL(e))),de(()=>K(new Map)),xe())}function lc({document$:e}){let t=new Map;e.pipe(g(()=>$("link[rel=alternate]")),f(r=>new URL(r.href)),O(r=>!t.has(r.toString())),ie(r=>dr(r).pipe(f(n=>[r,n]),de(()=>w)))).subscribe(([r,n])=>{t.set(r.toString().replace(/\/$/,""),n)}),b(document.body,"click").pipe(O(r=>!r.metaKey&&!r.ctrlKey),g(r=>{if(r.target instanceof Element){let n=r.target.closest("a");if(n&&!n.target){let o=[...t].find(([p])=>n.href.startsWith(`${p}/`));if(typeof o=="undefined")return w;let[i,a]=o,s=Ue();if(s.href.startsWith(i))return w;let c=Ne(),l=s.href.replace(c.base,"");l=`${i}/${l}`;let u=a.has(l.split("#")[0])?new URL(l,c.base):new URL(i);return r.preventDefault(),K(u)}}return w})).subscribe(r=>dt(r,!0))}var Ao=_r(Lo());function Rp(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function uc({alert$:e}){Ao.default.isSupported()&&new N(t=>{new Ao.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||Rp(Y(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(P(t=>{t.trigger.focus()}),f(()=>Gt("clipboard.copied"))).subscribe(e)}function pc(e,t){if(!(e.target instanceof Element))return w;let r=e.target.closest("a");if(r===null)return w;if(r.target||e.metaKey||e.ctrlKey)return w;let n=new URL(r.href);return n.search=n.hash="",t.has(`${n}`)?(e.preventDefault(),K(r)):w}function fc(e){let t=new Map;for(let r of $(":scope > *",e.head))t.set(r.outerHTML,r);return t}function mc(e){for(let t of $("[href], [src]",e))for(let r of["href","src"]){let n=t.getAttribute(r);if(n&&!/^(?:[a-z]+:)?\/\//i.test(n)){t[r]=t[r];break}}return K(e)}function jp(e){for(let n of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...X("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let o=we(n),i=we(n,e);typeof o!="undefined"&&typeof i!="undefined"&&o.replaceWith(i)}let t=fc(document);for(let[n,o]of fc(e))t.has(n)?t.delete(n):document.head.appendChild(o);for(let n of t.values()){let o=n.getAttribute("name");o!=="theme-color"&&o!=="color-scheme"&&n.remove()}let r=ht("container");return ot($("script",r)).pipe(g(n=>{let o=e.createElement("script");if(n.src){for(let i of n.getAttributeNames())o.setAttribute(i,n.getAttribute(i));return n.replaceWith(o),new N(i=>{o.onload=()=>i.complete()})}else return o.textContent=n.textContent,n.replaceWith(o),w}),be(),ye(document))}function dc({sitemap$:e,location$:t,viewport$:r,progress$:n}){if(location.protocol==="file:")return Ge;K(document).subscribe(mc);let o=b(document.body,"click").pipe(Qe(e),g(([s,c])=>pc(s,c)),f(({href:s})=>new URL(s)),xe()),i=b(window,"popstate").pipe(f(Ue),xe());o.pipe(fe(r)).subscribe(([s,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",s)}),R(o,i).subscribe(t);let a=t.pipe(J(Ue()),un(),O(([s,c])=>s.pathname!==c.pathname),f(([,s])=>s),g(s=>Sn(s,{progress$:n}).pipe(de(()=>(dt(s,!0),w)))),g(mc),g(jp),xe());return R(a.pipe(fe(t,(s,c)=>c)),a.pipe(g(()=>t),he("hash")),t.pipe(J(Ue()),un(),O(([s,c])=>s.pathname===c.pathname&&s.hash!==c.hash),f(([,s])=>s)),t.pipe(se((s,c)=>s.pathname===c.pathname&&s.hash===c.hash),g(()=>o),P(()=>history.back()))).subscribe(s=>{var c,l;history.state!==null||!s.hash?window.scrollTo(0,(l=(c=history.state)==null?void 0:c.y)!=null?l:0):(history.scrollRestoration="auto",os(s.hash),history.scrollRestoration="manual")}),t.subscribe(()=>{history.scrollRestoration="manual"}),b(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),r.pipe(he("offset"),Ye(100)).subscribe(({offset:s})=>{history.replaceState(s,"")}),X("navigation.instant.prefetch")&&R(b(document.body,"mousemove"),b(document.body,"focusin")).pipe(Qe(e),g(([s,c])=>pc(s,c)),Ye(25),Yn(({href:s})=>s),ln(s=>{let c=document.createElement("link");return c.rel="prefetch",c.href=s.toString(),document.head.appendChild(c),b(c,"load").pipe(f(()=>c),Me(1))})).subscribe(s=>s.remove()),a}function hc(e){var u;let{selectedVersionSitemap:t,selectedVersionBaseURL:r,currentLocation:n,currentBaseURL:o}=e,i=(u=Co(o))==null?void 0:u.pathname;if(i===void 0)return;let a=Fp(n.pathname,i);if(a===void 0)return;let s=Np(t.keys());if(!t.has(s))return;let c=Co(a,s);if(!c||!t.has(c.href))return;let l=Co(a,r);if(l)return l.hash=n.hash,l.search=n.search,l}function Co(e,t){try{return new URL(e,t)}catch(r){return}}function Fp(e,t){if(e.startsWith(t))return e.slice(t.length)}function Up(e,t){let r=Math.min(e.length,t.length),n;for(n=0;nw)),n=r.pipe(f(o=>{let[,i]=t.base.match(/([^/]+)\/?$/);return o.find(({version:a,aliases:s})=>a===i||s.includes(i))||o[0]}));r.pipe(f(o=>new Map(o.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),g(o=>b(document.body,"click").pipe(O(i=>!i.metaKey&&!i.ctrlKey),fe(n),g(([i,a])=>{if(i.target instanceof Element){let s=i.target.closest("a");if(s&&!s.target&&o.has(s.href)){let c=s.href;return!i.target.closest(".md-version")&&o.get(c)===a?w:(i.preventDefault(),K(new URL(c)))}}return w}),g(i=>dr(i).pipe(f(a=>{var s;return(s=hc({selectedVersionSitemap:a,selectedVersionBaseURL:i,currentLocation:Ue(),currentBaseURL:t.base}))!=null?s:i})))))).subscribe(o=>dt(o,!0)),ne([r,n]).subscribe(([o,i])=>{Y(".md-header__topic").appendChild(Es(o,i))}),e.pipe(g(()=>n)).subscribe(o=>{var s;let i=new URL(t.base),a=__md_get("__outdated",sessionStorage,i);if(a===null){a=!0;let c=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(c)||(c=[c]);e:for(let l of c)for(let u of o.aliases.concat(o.version))if(new RegExp(l,"i").test(u)){a=!1;break e}__md_set("__outdated",a,sessionStorage,i)}if(a)for(let c of Te("outdated"))c.hidden=!1})}function bc({document$:e,viewport$:t}){e.pipe(g(()=>$(".md-ellipsis")),ie(r=>Tt(r).pipe(ee(e.pipe(ke(1))),O(n=>n),f(()=>r),Me(1))),O(r=>r.offsetWidth{let n=r.innerText,o=r.closest("a")||r;return o.title=n,X("content.tooltips")?Je(o,{viewport$:t}).pipe(ee(e.pipe(ke(1))),z(()=>o.removeAttribute("title"))):w})).subscribe(),X("content.tooltips")&&e.pipe(g(()=>$(".md-status")),ie(r=>Je(r,{viewport$:t}))).subscribe()}function gc({document$:e,tablet$:t}){e.pipe(g(()=>$(".md-toggle--indeterminate")),P(r=>{r.indeterminate=!0,r.checked=!1}),ie(r=>b(r,"change").pipe(Zn(()=>r.classList.contains("md-toggle--indeterminate")),f(()=>r))),fe(t)).subscribe(([r,n])=>{r.classList.remove("md-toggle--indeterminate"),n&&(r.checked=!1)})}function Dp(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function _c({document$:e}){e.pipe(g(()=>$("[data-md-scrollfix]")),P(t=>t.removeAttribute("data-md-scrollfix")),O(Dp),ie(t=>b(t,"touchstart").pipe(f(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let n=e[r];typeof n=="string"?n=document.createTextNode(n):n.parentNode&&n.parentNode.removeChild(n),r?t.insertBefore(this.previousSibling,n):t.replaceChild(n,this)}}}));function Wp(){return location.protocol==="file:"?wt(`${new URL("search.js",An.base)}`).pipe(f(()=>__index),de(()=>Ge),ae(1)):tt(new URL("search.json",An.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var vt=Ti(),Ur=rs(),hr=is(Ur),xc=ts(),Ke=fs(),Ho=Ir("(min-width: 60em)"),wc=Ir("(min-width: 76.25em)"),Ec=as(),An=Ne(),Tc=we(".md-search")?Wp():Ge,$o=new I;uc({alert$:$o});lc({document$:vt});var Po=new I,Sc=dr(An.base);X("navigation.instant")&&dc({sitemap$:Sc,location$:Ur,viewport$:Ke,progress$:Po}).subscribe(vt);var yc;((yc=An.version)==null?void 0:yc.provider)==="mike"&&vc({document$:vt});R(Ur,hr).pipe(jt(125)).subscribe(()=>{wo("drawer",!1),wo("search",!1)});xc.pipe(O(({mode:e,meta:t})=>e==="global"&&!t)).subscribe(e=>{switch(e.type){case",":case"p":let t=document.querySelector("link[rel=prev]");t instanceof HTMLLinkElement&&dt(t);break;case".":case"n":let r=document.querySelector("link[rel=next]");r instanceof HTMLLinkElement&&dt(r);break;case"/":let n=document.querySelector("[data-md-component=search] button");n instanceof HTMLButtonElement&&n.click();break;case"Enter":let o=xt();o instanceof HTMLLabelElement&&o.click()}});bc({viewport$:Ke,document$:vt});gc({document$:vt,tablet$:Ho});_c({document$:vt});var kt=qs(ht("header"),{viewport$:Ke}),Fr=vt.pipe(f(()=>ht("main")),g(e=>Gs(e,{viewport$:Ke,header$:kt})),ae(1)),Vp=R(...Te("consent").map(e=>ds(e,{target$:hr})),...Te("dialog").map(e=>zs(e,{alert$:$o})),...Te("palette").map(e=>Ys(e)),...Te("progress").map(e=>Js(e,{progress$:Po})),...Te("search").map(e=>Zs(e,{index$:Tc})),...Te("source").map(e=>oc(e))),zp=j(()=>R(...Te("announce").map(e=>ms(e)),...Te("content").map(e=>Vs(e,{sitemap$:Sc,viewport$:Ke,target$:hr,print$:Ec})),...Te("content").map(e=>X("search.highlight")?ec(e,{index$:Tc,location$:Ur}):w),...Te("header").map(e=>Ks(e,{viewport$:Ke,header$:kt,main$:Fr})),...Te("header-title").map(e=>Bs(e,{viewport$:Ke,header$:kt})),...Te("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?_o(wc,()=>ko(e,{viewport$:Ke,header$:kt,main$:Fr})):_o(Ho,()=>ko(e,{viewport$:Ke,header$:kt,main$:Fr}))),...Te("tabs").map(e=>ic(e,{viewport$:Ke,header$:kt})),...Te("toc").map(e=>ac(e,{viewport$:Ke,header$:kt,main$:Fr,target$:hr})),...Te("top").map(e=>sc(e,{viewport$:Ke,header$:kt,main$:Fr,target$:hr})))),Oc=vt.pipe(g(()=>zp),Ft(Vp),ae(1));Oc.subscribe();window.document$=vt;window.location$=Ur;window.target$=hr;window.keyboard$=xc;window.viewport$=Ke;window.tablet$=Ho;window.screen$=wc;window.print$=Ec;window.alert$=$o;window.progress$=Po;window.component$=Oc;})(); diff --git a/site/assets/javascripts/workers/search.b6b7e04f.min.js b/site/assets/javascripts/workers/search.b6b7e04f.min.js deleted file mode 100644 index c93e95d6d..000000000 --- a/site/assets/javascripts/workers/search.b6b7e04f.min.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(()=>{var vt=Object.create;var K=Object.defineProperty,wt=Object.defineProperties,bt=Object.getOwnPropertyDescriptor,Tt=Object.getOwnPropertyDescriptors,Mt=Object.getOwnPropertyNames,W=Object.getOwnPropertySymbols,kt=Object.getPrototypeOf,Y=Object.prototype.hasOwnProperty,Et=Object.prototype.propertyIsEnumerable;var B=(t,e,n)=>e in t?K(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,R=(t,e)=>{for(var n in e||(e={}))Y.call(e,n)&&B(t,n,e[n]);if(W)for(var n of W(e))Et.call(e,n)&&B(t,n,e[n]);return t},Q=(t,e)=>wt(t,Tt(e));var Ft=(t,e)=>()=>{try{return e||t((e={exports:{}}).exports,e),e.exports}catch(n){throw e=0,n}};var Rt=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let l of Mt(e))!Y.call(t,l)&&l!==n&&K(t,l,{get:()=>e[l],enumerable:!(r=bt(e,l))||r.enumerable});return t};var qt=(t,e,n)=>(n=t!=null?vt(kt(t)):{},Rt(e||!t||!t.__esModule?K(n,"default",{value:t,enumerable:!0}):n,t));var L=(t,e,n)=>B(t,typeof e!="symbol"?e+"":e,n);var E=(t,e,n)=>new Promise((r,l)=>{var o=u=>{try{s(n.next(u))}catch(i){l(i)}},a=u=>{try{s(n.throw(u))}catch(i){l(i)}},s=u=>u.done?r(u.value):Promise.resolve(u.value).then(o,a);s((n=n.apply(t,e)).next())});var xt=Ft(mt=>{"use strict";function C(t,e,n={}){return{name:t,from:e,meta:n}}function H(t,e){let n=[{value:t,depth:0}];for(let r=0,l=-1,o=0;r>=0;){let{value:a,depth:s}=n[r];if(l<=s&&a.type==="operator"&&a.data.operands.length>0)for(let u=a.data.operands.length;u>0;)n[++r]={value:a.data.operands[--u],depth:s+1};else{let u=e(a,o++,s);if(typeof u<"u")return u;--r}l=s}}var P=class extends Error{constructor(t,e){super(e),this.code=t}};function $(t,e){let n=zt(t);for(let r=0;r{let{matches:r}=n;for(let l=0;l{let l=e.get(n);return typeof l>"u"&&e.set(n,l=t(n,...r)),l}}function D(t,e){return Object.defineProperty(e,"name",{value:t}),e}function tt(t){return E(this,null,function*(){let e=[];if(typeof t.plugins<"u")for(let n=0;n32)throw new RangeError("Bit format exceeds 32 bits");return t}function nt(t,e,n){let r=N(t),l=N(e),o=typeof n<"u"?N(n):32-r-l;return St({d:r,f:l,x:o})}var T=[0];for(let t=0;t<32;t++)T.push(T[t]|1<=n&&t{e+=r*r}),Math.sqrt(e)}function Pt(t,e){t instanceof J?t.data.forEach((n,r)=>{e(n,r)}):t.forEach((n,r)=>{e({start:n,end:n+1,value:1},r)})}var O=class{constructor(t,e=jt(Math.ceil(t/32))){this.size=t,this.data=e}get(t){return this.data[t>>>5]>>>t&1}set(t){this.data[t>>>5]|=1<<(t&31)}forEach(t){let e=this.size&31;for(let n=0;n>>0;for(let n=0;n0;l++){let{value:o,depth:a}=n[--r],s=e(o,l,a);if(typeof s<"u")return s;for(let u=o.children.length;u>0;)n[r++]={value:o.children[--u],depth:a+1}}}function Vt(t,e){return E(this,null,function*(){let{fields:n,plugins:r=[]}=e,l=nt(t.length,n.length),o=[];for(let u=0;u"u")continue;let f=u<{var m;return(m=g.onFilterInput)==null?void 0:m.call(g,p,f,l)},d);let c=o[i],h=k();d=Array.isArray(d)?d:[d];for(let p=0;p{let v=c.index.get(m.node);typeof v>"u"&&c.index.set(m.node,v=k());let w=c.terms.length;for(let b=0;b{var i;return(i=u.onFilterStore)==null?void 0:i.call(u,s,e,t)}),s})}function Ut(t,e,n,r={}){let l=[];if(e<0||e>=t.count.fields)return l;let o=t.shards[e],a=new Map,{count:s=1/0,depth:u=1/0}=r;for(let i=0;iu)continue;let p=a.get(d);typeof p>"u"&&a.set(d,p={node:f,children:[]});let g=l;h>0&&(g=a.get(o.terms[c]).children),g.length=t.count.fields)return{documents:r,terms:l};let o=t.shards[n];return e.forEach(a=>{let{occurrences:s}=o.terms[a];for(let u=0;u>>t.space.x>>>t.space.f;r.set(i)}l[n].set(a)}),{documents:r,terms:l}}function Bt(t){let{documents:e,terms:n}=U(t);A(e,1);for(let r=0;rnew O(e.length))}}function Kt(t,e,n){let{compiler:r,fields:l,plugins:o=[]}=n,{input:a,scope:s,abort:u=!1}=z(o,(f,c)=>{var h;return(h=c.onFilterQuery)==null?void 0:h.call(c,f,t,n)},e),i={items:[],query:{select:U(t),values:[]}},d=new Map;if(u===!1){let f=r(n),{select:c,values:h}=f(a,t);typeof s<"u"&&V(c.documents,s);let p=new Map;i.query={select:c,values:h},c.terms.forEach((g,m)=>{g.forEach(y=>{let x=t.shards[m],{occurrences:v}=x.terms[y];for(let w=0;w>>t.space.x,F=b>>>t.space.f;if(!c.documents.get(F))continue;let S=p.get(b);typeof S>"u"&&p.set(b,S=new j(k()));let yt=M&T[t.space.x];S.add(yt,y)}})}),c.documents.forEach(g=>{let m={id:g,matches:[]};i.items.push(m),d.set(g,m)}),p.forEach((g,m)=>{let y=m>>>t.space.f,x=m&T[t.space.f];d.get(y).matches.push({id:m,field:l[x].name,value:{filter:g},score:0})})}return z(o,(f,c)=>{var h;return(h=c.onFilterResult)==null?void 0:h.call(c,f,t,n)},i)}function st(t){let{fields:e}=t;return(n,r)=>{if(It(n))return n;let l=[Bt(r)],o=[],a=0;return H(n,({type:s,data:u})=>{switch(s){case"value":let i=e.findIndex(({name:c})=>c===u.field);if(i===-1){l[a++]=U(r);break}let d=u.value;if(typeof d!="object"){let c=new j(k()),h=r.shards[i],p=h.index.get(d);if(typeof p<"u")for(let g=0;gf+1&&a--;){I(l[f].documents,l[a].documents);for(let c=0;cf+1&&a--;){V(l[f].documents,l[a].documents);for(let c=0;cf+1&&a--;)lt(l[f].documents,l[a].documents)}}}),{select:l[0],values:o}}}function Lt(t){return{name:t.name,data:t.data,onFilterOptions:t.onFilterOptions,onFilterInput:t.onFilterInput,onFilterStore:t.onFilterStore,onFilterQuery:t.onFilterQuery,onFilterResult:t.onFilterResult}}function ot(t){return typeof t=="object"&&t!==null&&"type"in t&&"data"in t}function Nt(t){return typeof t=="object"&&t!==null&&"select"in t&&"values"in t}function Gt(t){return t.normalize("NFKD").toLowerCase()}function Ht(t,e){let n=Math.min(t.length,e.length);for(let r=0;r65535)){let o=e(l=t.codePointAt(n),n);if(typeof o<"u")return o}}function ut(t,e,n=0,r=t.length){let l=k();return Jt(t,o=>{l.push(o);let a=e(String.fromCodePoint(...l),l.length);if(typeof a<"u")return a},n,r)}function Wt(t,e,n=0,r=t.length){let l=n;for(let o=0;ln&&e(n,n=l);continue;case 62:n=l+1}l>n&&e(n,l)}function it(t,e,n,r=0){return Wt(t,(l,o)=>e(t,(a,s)=>{r=n({value:t.slice(a,s),index:r,start:a,end:s})},l,o)),r}function Yt(t,e,n,r=0){for(let l=0,o=0;l(a.start+=o,a.end+=o,n(a)),r);return r}function Zt(t){let e=new RegExp(t,"gu");return(n,r,l=0,o=n.length)=>{var u;e.lastIndex=l;let a,s=0;do{a=e.exec(n);let i=(u=a==null?void 0:a.index)!=null?u:o;l"u")continue;let p=f<{var y;return(y=m.onTextInput)==null?void 0:y.call(m,g,p,a)},h),h=Array.isArray(h)?h:[h],Yt(h,n,g=>{let m=z(o,(y,x)=>{var v;return(v=x.onTextTokens)==null?void 0:v.call(x,y)},[g]);for(let y=0;y"u"?s.set(x,[p<{var c;return(c=f.onTextStore)==null?void 0:c.call(f,i,e,t)}),i})}function Xt(t,e,n){let{documents:r,terms:l}=_(t);return n<0||n>=t.count.fields?{documents:r,terms:l}:(e.forEach(o=>{let{occurrences:a}=t.terms[o];for(let s=0;s>>t.space.x;if((u&T[t.space.f])!==n)continue;let i=u>>>t.space.f;r.set(i)}l.set(o)}),{documents:r,terms:l})}function te(t,e){let{documents:n,terms:r}=_(t),l=t.space.f+t.space.x;return e.forEach(o=>{let{occurrences:a}=t.terms[o];for(let s=0;s>>l);r.set(o)}),{documents:n,terms:r}}function _(t){return{documents:new O(t.count.documents),terms:new O(t.terms.length)}}function ee(t,e,n){let{compiler:r,fields:l,plugins:o=[]}=n,{input:a,scope:s,abort:u=!1}=z(o,(f,c)=>{var h;return(h=c.onTextQuery)==null?void 0:h.call(c,f,t,n)},e),i={items:[],query:{select:_(t),values:[]}},d=new Map;if(u===!1){let f=r(n),{select:c,values:h}=f(a,t);typeof s<"u"&&V(c.documents,s);let p=new O(l.length),g=new Map;i.query={select:c,values:h},c.terms.forEach(m=>{A(p,0);for(let x=0;x>>t.space.x,M=w>>>t.space.f;if(!c.documents.get(M))continue;let b=w&T[t.space.f];if(!p.get(b))continue;let F=g.get(w);typeof F>"u"&&g.set(w,F=new j(k()));let S=v&T[t.space.x];F.add(S,m)}}),c.documents.forEach(m=>{let y={id:m,matches:[]};i.items.push(y),d.set(m,y)}),g.forEach((m,y)=>{let x=y>>>t.space.f,v=y&T[t.space.f];d.get(x).matches.push({id:y,field:l[v].name,value:{text:m},score:0})})}return z(o,(f,c)=>{var h;return(h=c.onTextResult)==null?void 0:h.call(c,f,t,n)},i)}function ne(t,e=10){return t.length>1?1+t[t.length-1]-t[0]:e}function re(t,e,n,r=10){let l=[];t.value.text.forEach((s,u)=>{for(let i=0;is.index-u.index);let o=l.slice(0,1),a=0;for(let s=0;sr||i.value===u.value)d=o.map(({index:f})=>f),o=[l[s+1]];else{for(let f=0;fi.index-u.index){let h=o.splice(f+1);d=o.map(({index:p})=>p),o=[...h,l[s+1]]}else d=o.map(({index:h})=>h),o=[l[s+1]];break}}typeof d>"u"&&o.push(l[s+1])}if(typeof d<"u"){let f=n(d,a++);if(typeof f<"u")return f}}if(o.length)return n(o.map(({index:s})=>s),a)}function le(t){let{transform:e,parser:n,fields:r}=t,l=n(t);return(o,a)=>{if(Nt(o))return o;typeof o=="string"&&(o=l(o));let s=[_(a)],u=[],i=0;return H(o,({type:d,data:f})=>{switch(d){case"value":let c=f.value;if(typeof c=="string"){let p=new j(k()),g=a.index.get(e(c));typeof g<"u"&&p.add(g,1),c=p}if(f.field==="*")s[i++]=te(a,c);else{let p=r.findIndex(({name:g})=>g===f.field);s[i++]=Xt(a,c,p)}u.push(Q(R({},f),{value:c}));break;case"operator":let h=i-f.operands.length;switch(f.operator){case"or":for(;i>h+1&&i--;)I(s[h].documents,s[i].documents),I(s[h].terms,s[i].terms);break;case"and":for(;i>h+1&&i--;)V(s[h].documents,s[i].documents),I(s[h].terms,s[i].terms);break;case"not":for(at(s[h].documents),A(s[h].terms,0);i>h+1&&i--;)lt(s[h].documents,s[i].documents)}}}),{select:s[0],values:u}}}function ft(t,e){return H(t,(n,r,l)=>{if(n.type!=="value")return;let o=e(n.data,r,l);if(typeof o<"u")return o})}function ct(t){if(t.length===0)return[];let e=[],n=[];for(let o=0;oo.index-a.index);let r=new Set([n[0].value]),l=n[0].index;for(let o=1;o{t[i].start>l||t[i].end{e.push({start:l,end:o,value:n})})}return new J(ct(e))}function ae(t,e="or",n){let{separator:r}=t;return n!=null||(n=l=>({field:"*",value:l.value})),l=>{let o=[];return it(l,r,a=>{let s=n(a);typeof s<"u"&&o.push({type:"value",data:s})}),{type:"operator",data:{operator:e,operands:o}}}}function se(t,e){return E(this,null,function*(){let n=yield tt(e),r=yield At(n,(o,a)=>{var s;return(s=a.onTextOptions)==null?void 0:s.call(a,o,t)},Q(R({},e),{plugins:n})),l=yield $t(t,r);return D("text",o=>{if(o.type!=="text")throw new P("unsupported");return{type:o.type,data:ee(l,o.data,r)}})})}function q(t){return{name:t.name,data:t.data,onTextOptions:t.onTextOptions,onTextInput:t.onTextInput,onTextTokens:t.onTextTokens,onTextStore:t.onTextStore,onTextQuery:t.onTextQuery,onTextResult:t.onTextResult}}function oe(t){let{handlers:e}=t,n,r=new Map;return Lt({name:"aggregation",onFilterStore(l,o){for(let a=0;a"u")continue;let u=!0;o.documents.forEach(i=>{u=!1}),u&&A(o.documents,1),l.aggregations.push(s(a,o))}}})}function ue(t={}){let{empty:e=!1,limit:n}=t;return(r,{fields:l})=>{let o=r.space.f+r.space.x;return D("term",({type:a,data:s},{documents:u})=>{if(a!=="term")throw new P("unsupported");let i=l.findIndex(({name:f})=>f===s.field),d=Ut(r,i,f=>{let c=0,{occurrences:h}=f;for(let p=0;p>>o)&&c++;if(!(e===!1&&c===0))return{value:f.value,count:c}},R(R({},n),s.limit));return{type:a,data:{field:s.field,value:d}}})}}function ie(t,e="prefix"){return{type:e,data:t}}function fe(t){return typeof t=="object"&&"type"in t&&typeof t.type=="string"&&"data"in t&&typeof t.data=="string"}function ce(t,e={}){var u;let{prefix:n=2,filter:r=[]}=e,l=t.terms,o=new Map,a=Ot(l.length),s=k();for(let i=0;i{var p;return o.set(c,(p=o.get(c))!=null?p:i),h===n||void 0});let f=i?l[i-1]:"";a[i]=Ht(f,d)}for(let i=0;ii-d),{terms:l,index:o,cover:a,exact:s}}function de(t,e){let n="",r=-1,l=-1;if(ut(e,s=>{let u=t.index.get(s);if(typeof u>"u")return!0;n=s,r=u}),r!==-1)for(let s=n.length;ss>r&&sa),index:e.index},{prefix:t.prefix,filter:(l=t.filter)==null?void 0:l.map(r)}))},onTextQuery(e,n,r){let{transform:l,parser:o}=r;if(typeof e.input=="string")e.input=o(r)(e.input);else if(!ot(e.input))return;ft(e.input,a=>{var u;let s=a.value;if(fe(s))s=l(s.data);else return;a.value=(u=de(this.data,s))!=null?u:s})}})}function pe(t){let e=Q(R({},t),{plugins:[]}),n,r,l;return q({name:"filter",onTextOptions(a,s){return E(this,null,function*(){e.plugins=yield tt(t),l=yield Vt(s,e)})},onTextQuery(a){typeof a.filter<"u"&&(n=a.filter,r!=null||(r=st(e)),n.input=r(n.input,l),a.scope=n.input.select.documents)},onTextResult(a){if(typeof n<"u"){let s=!0;a.query.select.documents.forEach(i=>{s=!1}),s||(n.scope=a.query.select.documents);let u=Kt(l,n,e);a.aggregations=u.aggregations,n=void 0}}})}function ht(t,e){let n=[],r=t/e>>>0,l=t%e,o=0;if(r)for(let a=0;as);r.sort((a,s)=>t.terms[a].length-t.terms[s].length||t.terms[a].localeCompare(t.terms[s]));let l=0;for(let a=0;al&&(l=t.terms[a].length);let o=[];for(let a=0;a"u"?u[d].set(f,[r[a]]):c.push(r[a])}}return{index:o,terms:t.terms,idxmp:r}}var ye=[["id","di","rr"],["dr","rd"],["dd"]];function pt(t,e,n=2){if(t.lengthn)return;let a,s,u,i=n+1;for(let d of ye[o]){for(u=a=s=0;an)break;switch(d[u-1]){case"d":a++;break;case"i":s++;break;case"r":a++,s++;break}}else a++,s++;u+=r-a+(l-s),u"u")continue;let a=me(e,o,2);for(let s=0;s"u"))for(let c of f){let h=t.terms[c].length,p=n(t.terms[c],e);typeof p<"u"&&r.add(c,(h-p)/h)}}}}if(r.data.length)return r}function we(t={}){return q({name:"fuzzy",onTextStore(e){var n;(n=this.data)!=null||(this.data=xe({terms:e.terms.map(({value:r})=>r)},t))},onTextQuery(e,n,r){let{transform:l,parser:o}=r;if(typeof e.input=="string")e.input=o(r)(e.input);else if(!ot(e.input))return;ft(e.input,a=>{var u;let s=a.value;if(typeof s=="string")s=l(s);else return;n.index.get(s)||(a.value=(u=ve(this.data,s))!=null?u:s)})}})}function be(){return{tables:new Map}}function Te(t,e={}){let{count:n}=e;return D("term",r=>{let l=dt(r);return(o,a)=>{let s=[];return o.value.text.forEach((u,i)=>{let d=a[u]>>>10,f=a[u]&T[10];for(let p=0;pu.start-i.start),{ranges:ct(s).slice(0,n)}}})}function Me(t){let e,n;return q({name:"highlight",data:be(),onTextInput(r,l){let{tables:o}=this.data;o.set(l,n=k())},onTextTokens(r){for(let l=0;l{let s=l.get(a.id);if(a.value.highlight)return;let u=o(a,s);a.value=Q(R({},a.value),{highlight:u})})}})}function ke(){return{directives:[]}}function gt(...t){return(e,n)=>{for(let r=0;r{if(r!=="match")throw new P("unsupported");let o=Fe(t),a=gt(...e.map(s=>s(n)));return $(n,({matches:s})=>{s.sort(o)}),(s,u)=>{let i=Math.min(s.matches.length,u.matches.length);for(let d=0,f=0;dr*(l.get(a.field)-l.get(s.field))}function Re(t,e={}){let n=dt(t.query),r=G(re),l=G(ne);return(o,a)=>{let s=r(o,n,f=>f),u=r(a,n,f=>f);if(s.length!==u.length)return u.length-s.length;let i=l(s),d=l(u);return i!==d?i-d:s[0]!==u[0]?s[0]-u[0]:0}}function qe(t){let e=new Map;return q({name:"order",data:ke(),onTextOptions(r,l){return E(this,null,function*(){for(let o=0;o"u")throw new P("unknown");o.push(u(r,s))}r.items.sort(gt(...o))}})}function ze(t){let e=t.handler();return q({name:"pagination",onTextQuery(n){return e.onQuery(n,t)},onTextResult(n){return e.onResult(n,t)}})}function Ae(t){let{id:e,size:n=10,from:r=0}=t;if(r-n>=0)return{id:e,size:n,from:r-n}}function Qe(t,e){let{id:n,size:r=10,from:l=0}=t;if(l+rE(null,null,function*(){let e=t.data;switch(e.type){case 0:Z=yield se(e.data.items,{separator:Zt(e.data.config.separator),transform:G(Gt),parser:r=>ae(r,"and",l=>({field:"*",value:ie(l.value),range:{start:l.start,end:l.end,value:l.index}})),compiler:le,fields:[C("title",r=>r.title,{weight:3}),C("text",r=>r.text),C("path",r=>r.path,{weight:2})],plugins:[he(),we(),pe({compiler:st,fields:[C("tags",r=>r.tags)],plugins:[oe({handlers:[ue()]})]}),qe({handlers:[r=>Ee({fields:r.fields,comparators:[Re]})],defaults:{order:[{type:"match",data:{field:"*"}}]}}),()=>q({onTextResult(r){r.total=r.items.length}}),ze({handler:Se,size:10}),Me({handler:r=>Te(r)}),()=>q({onTextResult(r){let{query:l}=r,o=l.values.map(({range:a,value:s})=>{var i,d;let u=!1;return s.forEach((f,c)=>{!u&&c<1&&(u=!0)}),u?-1:((i=a==null?void 0:a.end)!=null?i:0)-((d=a==null?void 0:a.start)!=null?d:0)});X(r,a=>{var s;(s=a.value.highlight)==null||s.ranges.forEach(u=>{u.value=o[u.value]})})}})]}),self.postMessage({type:1});break;case 2:let n=Z({type:"text",data:e.data});self.postMessage({type:3,data:n.data});break}})});var _e=qt(xt());})(); diff --git a/site/assets/javascripts/workers/search.e2d2d235.min.js b/site/assets/javascripts/workers/search.e2d2d235.min.js new file mode 100644 index 000000000..a56d589a8 --- /dev/null +++ b/site/assets/javascripts/workers/search.e2d2d235.min.js @@ -0,0 +1 @@ +"use strict";(()=>{var vt=Object.create;var K=Object.defineProperty,wt=Object.defineProperties,bt=Object.getOwnPropertyDescriptor,Tt=Object.getOwnPropertyDescriptors,Mt=Object.getOwnPropertyNames,W=Object.getOwnPropertySymbols,kt=Object.getPrototypeOf,Y=Object.prototype.hasOwnProperty,Et=Object.prototype.propertyIsEnumerable;var B=(t,e,n)=>e in t?K(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,R=(t,e)=>{for(var n in e||(e={}))Y.call(e,n)&&B(t,n,e[n]);if(W)for(var n of W(e))Et.call(e,n)&&B(t,n,e[n]);return t},Q=(t,e)=>wt(t,Tt(e));var Ft=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Rt=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let l of Mt(e))!Y.call(t,l)&&l!==n&&K(t,l,{get:()=>e[l],enumerable:!(r=bt(e,l))||r.enumerable});return t};var qt=(t,e,n)=>(n=t!=null?vt(kt(t)):{},Rt(e||!t||!t.__esModule?K(n,"default",{value:t,enumerable:!0}):n,t));var L=(t,e,n)=>B(t,typeof e!="symbol"?e+"":e,n);var E=(t,e,n)=>new Promise((r,l)=>{var o=u=>{try{s(n.next(u))}catch(i){l(i)}},a=u=>{try{s(n.throw(u))}catch(i){l(i)}},s=u=>u.done?r(u.value):Promise.resolve(u.value).then(o,a);s((n=n.apply(t,e)).next())});var xt=Ft(mt=>{"use strict";function C(t,e,n={}){return{name:t,from:e,meta:n}}function H(t,e){let n=[{value:t,depth:0}];for(let r=0,l=-1,o=0;r>=0;){let{value:a,depth:s}=n[r];if(l<=s&&a.type==="operator"&&a.data.operands.length>0)for(let u=a.data.operands.length;u>0;)n[++r]={value:a.data.operands[--u],depth:s+1};else{let u=e(a,o++,s);if(typeof u<"u")return u;--r}l=s}}var P=class extends Error{constructor(t,e){super(e),this.code=t}};function $(t,e){let n=zt(t);for(let r=0;r{let{matches:r}=n;for(let l=0;l{let l=e.get(n);return typeof l>"u"&&e.set(n,l=t(n,...r)),l}}function D(t,e){return Object.defineProperty(e,"name",{value:t}),e}function tt(t){return E(this,null,function*(){let e=[];if(typeof t.plugins<"u")for(let n=0;n32)throw new RangeError("Bit format exceeds 32 bits");return t}function nt(t,e,n){let r=N(t),l=N(e),o=typeof n<"u"?N(n):32-r-l;return St({d:r,f:l,x:o})}var T=[0];for(let t=0;t<32;t++)T.push(T[t]|1<=n&&t{e+=r*r}),Math.sqrt(e)}function Pt(t,e){t instanceof J?t.data.forEach((n,r)=>{e(n,r)}):t.forEach((n,r)=>{e({start:n,end:n+1,value:1},r)})}var O=class{constructor(t,e=jt(Math.ceil(t/32))){this.size=t,this.data=e}get(t){return this.data[t>>>5]>>>t&1}set(t){this.data[t>>>5]|=1<<(t&31)}forEach(t){let e=this.size&31;for(let n=0;n>>0;for(let n=0;n0;l++){let{value:o,depth:a}=n[--r],s=e(o,l,a);if(typeof s<"u")return s;for(let u=o.children.length;u>0;)n[r++]={value:o.children[--u],depth:a+1}}}function Vt(t,e){return E(this,null,function*(){let{fields:n,plugins:r=[]}=e,l=nt(t.length,n.length),o=[];for(let u=0;u"u")continue;let f=u<{var m;return(m=g.onFilterInput)==null?void 0:m.call(g,p,f,l)},d);let c=o[i],h=k();d=Array.isArray(d)?d:[d];for(let p=0;p{let v=c.index.get(m.node);typeof v>"u"&&c.index.set(m.node,v=k());let w=c.terms.length;for(let b=0;b{var i;return(i=u.onFilterStore)==null?void 0:i.call(u,s,e,t)}),s})}function Ut(t,e,n,r={}){let l=[];if(e<0||e>=t.count.fields)return l;let o=t.shards[e],a=new Map,{count:s=1/0,depth:u=1/0}=r;for(let i=0;iu)continue;let p=a.get(d);typeof p>"u"&&a.set(d,p={node:f,children:[]});let g=l;h>0&&(g=a.get(o.terms[c]).children),g.length=t.count.fields)return{documents:r,terms:l};let o=t.shards[n];return e.forEach(a=>{let{occurrences:s}=o.terms[a];for(let u=0;u>>t.space.x>>>t.space.f;r.set(i)}l[n].set(a)}),{documents:r,terms:l}}function Bt(t){let{documents:e,terms:n}=U(t);A(e,1);for(let r=0;rnew O(e.length))}}function Kt(t,e,n){let{compiler:r,fields:l,plugins:o=[]}=n,{input:a,scope:s,abort:u=!1}=z(o,(f,c)=>{var h;return(h=c.onFilterQuery)==null?void 0:h.call(c,f,t,n)},e),i={items:[],query:{select:U(t),values:[]}},d=new Map;if(u===!1){let f=r(n),{select:c,values:h}=f(a,t);typeof s<"u"&&V(c.documents,s);let p=new Map;i.query={select:c,values:h},c.terms.forEach((g,m)=>{g.forEach(y=>{let x=t.shards[m],{occurrences:v}=x.terms[y];for(let w=0;w>>t.space.x,F=b>>>t.space.f;if(!c.documents.get(F))continue;let S=p.get(b);typeof S>"u"&&p.set(b,S=new j(k()));let yt=M&T[t.space.x];S.add(yt,y)}})}),c.documents.forEach(g=>{let m={id:g,matches:[]};i.items.push(m),d.set(g,m)}),p.forEach((g,m)=>{let y=m>>>t.space.f,x=m&T[t.space.f];d.get(y).matches.push({id:m,field:l[x].name,value:{filter:g},score:0})})}return z(o,(f,c)=>{var h;return(h=c.onFilterResult)==null?void 0:h.call(c,f,t,n)},i)}function st(t){let{fields:e}=t;return(n,r)=>{if(It(n))return n;let l=[Bt(r)],o=[],a=0;return H(n,({type:s,data:u})=>{switch(s){case"value":let i=e.findIndex(({name:c})=>c===u.field);if(i===-1){l[a++]=U(r);break}let d=u.value;if(typeof d!="object"){let c=new j(k()),h=r.shards[i],p=h.index.get(d);if(typeof p<"u")for(let g=0;gf+1&&a--;){I(l[f].documents,l[a].documents);for(let c=0;cf+1&&a--;){V(l[f].documents,l[a].documents);for(let c=0;cf+1&&a--;)lt(l[f].documents,l[a].documents)}}}),{select:l[0],values:o}}}function Lt(t){return{name:t.name,data:t.data,onFilterOptions:t.onFilterOptions,onFilterInput:t.onFilterInput,onFilterStore:t.onFilterStore,onFilterQuery:t.onFilterQuery,onFilterResult:t.onFilterResult}}function ot(t){return typeof t=="object"&&t!==null&&"type"in t&&"data"in t}function Nt(t){return typeof t=="object"&&t!==null&&"select"in t&&"values"in t}function Gt(t){return t.normalize("NFKD").toLowerCase()}function Ht(t,e){let n=Math.min(t.length,e.length);for(let r=0;r65535)){let o=e(l=t.codePointAt(n),n);if(typeof o<"u")return o}}function ut(t,e,n=0,r=t.length){let l=k();return Jt(t,o=>{l.push(o);let a=e(String.fromCodePoint(...l),l.length);if(typeof a<"u")return a},n,r)}function Wt(t,e,n=0,r=t.length){let l=n;for(let o=0;ln&&e(n,n=l);continue;case 62:n=l+1}l>n&&e(n,l)}function it(t,e,n,r=0){return Wt(t,(l,o)=>e(t,(a,s)=>{r=n({value:t.slice(a,s),index:r,start:a,end:s})},l,o)),r}function Yt(t,e,n,r=0){for(let l=0,o=0;l(a.start+=o,a.end+=o,n(a)),r);return r}function Zt(t){let e=new RegExp(t,"gu");return(n,r,l=0,o=n.length)=>{var u;e.lastIndex=l;let a,s=0;do{a=e.exec(n);let i=(u=a==null?void 0:a.index)!=null?u:o;l"u")continue;let p=f<{var y;return(y=m.onTextInput)==null?void 0:y.call(m,g,p,a)},h),h=Array.isArray(h)?h:[h],Yt(h,n,g=>{let m=z(o,(y,x)=>{var v;return(v=x.onTextTokens)==null?void 0:v.call(x,y)},[g]);for(let y=0;y"u"?s.set(x,[p<{var c;return(c=f.onTextStore)==null?void 0:c.call(f,i,e,t)}),i})}function Xt(t,e,n){let{documents:r,terms:l}=_(t);return n<0||n>=t.count.fields?{documents:r,terms:l}:(e.forEach(o=>{let{occurrences:a}=t.terms[o];for(let s=0;s>>t.space.x;if((u&T[t.space.f])!==n)continue;let i=u>>>t.space.f;r.set(i)}l.set(o)}),{documents:r,terms:l})}function te(t,e){let{documents:n,terms:r}=_(t),l=t.space.f+t.space.x;return e.forEach(o=>{let{occurrences:a}=t.terms[o];for(let s=0;s>>l);r.set(o)}),{documents:n,terms:r}}function _(t){return{documents:new O(t.count.documents),terms:new O(t.terms.length)}}function ee(t,e,n){let{compiler:r,fields:l,plugins:o=[]}=n,{input:a,scope:s,abort:u=!1}=z(o,(f,c)=>{var h;return(h=c.onTextQuery)==null?void 0:h.call(c,f,t,n)},e),i={items:[],query:{select:_(t),values:[]}},d=new Map;if(u===!1){let f=r(n),{select:c,values:h}=f(a,t);typeof s<"u"&&V(c.documents,s);let p=new O(l.length),g=new Map;i.query={select:c,values:h},c.terms.forEach(m=>{A(p,0);for(let x=0;x>>t.space.x,M=w>>>t.space.f;if(!c.documents.get(M))continue;let b=w&T[t.space.f];if(!p.get(b))continue;let F=g.get(w);typeof F>"u"&&g.set(w,F=new j(k()));let S=v&T[t.space.x];F.add(S,m)}}),c.documents.forEach(m=>{let y={id:m,matches:[]};i.items.push(y),d.set(m,y)}),g.forEach((m,y)=>{let x=y>>>t.space.f,v=y&T[t.space.f];d.get(x).matches.push({id:y,field:l[v].name,value:{text:m},score:0})})}return z(o,(f,c)=>{var h;return(h=c.onTextResult)==null?void 0:h.call(c,f,t,n)},i)}function ne(t,e=10){return t.length>1?1+t[t.length-1]-t[0]:e}function re(t,e,n,r=10){let l=[];t.value.text.forEach((s,u)=>{for(let i=0;is.index-u.index);let o=l.slice(0,1),a=0;for(let s=0;sr||i.value===u.value)d=o.map(({index:f})=>f),o=[l[s+1]];else{for(let f=0;fi.index-u.index){let h=o.splice(f+1);d=o.map(({index:p})=>p),o=[...h,l[s+1]]}else d=o.map(({index:h})=>h),o=[l[s+1]];break}}typeof d>"u"&&o.push(l[s+1])}if(typeof d<"u"){let f=n(d,a++);if(typeof f<"u")return f}}if(o.length)return n(o.map(({index:s})=>s),a)}function le(t){let{transform:e,parser:n,fields:r}=t,l=n(t);return(o,a)=>{if(Nt(o))return o;typeof o=="string"&&(o=l(o));let s=[_(a)],u=[],i=0;return H(o,({type:d,data:f})=>{switch(d){case"value":let c=f.value;if(typeof c=="string"){let p=new j(k()),g=a.index.get(e(c));typeof g<"u"&&p.add(g,1),c=p}if(f.field==="*")s[i++]=te(a,c);else{let p=r.findIndex(({name:g})=>g===f.field);s[i++]=Xt(a,c,p)}u.push(Q(R({},f),{value:c}));break;case"operator":let h=i-f.operands.length;switch(f.operator){case"or":for(;i>h+1&&i--;)I(s[h].documents,s[i].documents),I(s[h].terms,s[i].terms);break;case"and":for(;i>h+1&&i--;)V(s[h].documents,s[i].documents),I(s[h].terms,s[i].terms);break;case"not":for(at(s[h].documents),A(s[h].terms,0);i>h+1&&i--;)lt(s[h].documents,s[i].documents)}}}),{select:s[0],values:u}}}function ft(t,e){return H(t,(n,r,l)=>{if(n.type!=="value")return;let o=e(n.data,r,l);if(typeof o<"u")return o})}function ct(t){if(t.length===0)return[];let e=[],n=[];for(let o=0;oo.index-a.index);let r=new Set([n[0].value]),l=n[0].index;for(let o=1;o{t[i].start>l||t[i].end{e.push({start:l,end:o,value:n})})}return new J(ct(e))}function ae(t,e="or",n){let{separator:r}=t;return n!=null||(n=l=>({field:"*",value:l.value})),l=>{let o=[];return it(l,r,a=>{let s=n(a);typeof s<"u"&&o.push({type:"value",data:s})}),{type:"operator",data:{operator:e,operands:o}}}}function se(t,e){return E(this,null,function*(){let n=yield tt(e),r=yield At(n,(o,a)=>{var s;return(s=a.onTextOptions)==null?void 0:s.call(a,o,t)},Q(R({},e),{plugins:n})),l=yield $t(t,r);return D("text",o=>{if(o.type!=="text")throw new P("unsupported");return{type:o.type,data:ee(l,o.data,r)}})})}function q(t){return{name:t.name,data:t.data,onTextOptions:t.onTextOptions,onTextInput:t.onTextInput,onTextTokens:t.onTextTokens,onTextStore:t.onTextStore,onTextQuery:t.onTextQuery,onTextResult:t.onTextResult}}function oe(t){let{handlers:e}=t,n,r=new Map;return Lt({name:"aggregation",onFilterStore(l,o){for(let a=0;a"u")continue;let u=!0;o.documents.forEach(i=>{u=!1}),u&&A(o.documents,1),l.aggregations.push(s(a,o))}}})}function ue(t={}){let{empty:e=!1,limit:n}=t;return(r,{fields:l})=>{let o=r.space.f+r.space.x;return D("term",({type:a,data:s},{documents:u})=>{if(a!=="term")throw new P("unsupported");let i=l.findIndex(({name:f})=>f===s.field),d=Ut(r,i,f=>{let c=0,{occurrences:h}=f;for(let p=0;p>>o)&&c++;if(!(e===!1&&c===0))return{value:f.value,count:c}},R(R({},n),s.limit));return{type:a,data:{field:s.field,value:d}}})}}function ie(t,e="prefix"){return{type:e,data:t}}function fe(t){return typeof t=="object"&&"type"in t&&typeof t.type=="string"&&"data"in t&&typeof t.data=="string"}function ce(t,e={}){var u;let{prefix:n=2,filter:r=[]}=e,l=t.terms,o=new Map,a=Ot(l.length),s=k();for(let i=0;i{var p;return o.set(c,(p=o.get(c))!=null?p:i),h===n||void 0});let f=i?l[i-1]:"";a[i]=Ht(f,d)}for(let i=0;ii-d),{terms:l,index:o,cover:a,exact:s}}function de(t,e){let n="",r=-1,l=-1;if(ut(e,s=>{let u=t.index.get(s);if(typeof u>"u")return!0;n=s,r=u}),r!==-1)for(let s=n.length;ss>r&&sa),index:e.index},{prefix:t.prefix,filter:(l=t.filter)==null?void 0:l.map(r)}))},onTextQuery(e,n,r){let{transform:l,parser:o}=r;if(typeof e.input=="string")e.input=o(r)(e.input);else if(!ot(e.input))return;ft(e.input,a=>{var u;let s=a.value;if(fe(s))s=l(s.data);else return;a.value=(u=de(this.data,s))!=null?u:s})}})}function pe(t){let e=Q(R({},t),{plugins:[]}),n,r,l;return q({name:"filter",onTextOptions(a,s){return E(this,null,function*(){e.plugins=yield tt(t),l=yield Vt(s,e)})},onTextQuery(a){typeof a.filter<"u"&&(n=a.filter,r!=null||(r=st(e)),n.input=r(n.input,l),a.scope=n.input.select.documents)},onTextResult(a){if(typeof n<"u"){let s=!0;a.query.select.documents.forEach(i=>{s=!1}),s||(n.scope=a.query.select.documents);let u=Kt(l,n,e);a.aggregations=u.aggregations,n=void 0}}})}function ht(t,e){let n=[],r=t/e>>>0,l=t%e,o=0;if(r)for(let a=0;as);r.sort((a,s)=>t.terms[a].length-t.terms[s].length||t.terms[a].localeCompare(t.terms[s]));let l=0;for(let a=0;al&&(l=t.terms[a].length);let o=[];for(let a=0;a"u"?u[d].set(f,[r[a]]):c.push(r[a])}}return{index:o,terms:t.terms,idxmp:r}}var ye=[["id","di","rr"],["dr","rd"],["dd"]];function pt(t,e,n=2){if(t.lengthn)return;let a,s,u,i=n+1;for(let d of ye[o]){for(u=a=s=0;an)break;switch(d[u-1]){case"d":a++;break;case"i":s++;break;case"r":a++,s++;break}}else a++,s++;u+=r-a+(l-s),u"u")continue;let a=me(e,o,2);for(let s=0;s"u"))for(let c of f){let h=t.terms[c].length,p=n(t.terms[c],e);typeof p<"u"&&r.add(c,(h-p)/h)}}}}if(r.data.length)return r}function we(t={}){return q({name:"fuzzy",onTextStore(e){var n;(n=this.data)!=null||(this.data=xe({terms:e.terms.map(({value:r})=>r)},t))},onTextQuery(e,n,r){let{transform:l,parser:o}=r;if(typeof e.input=="string")e.input=o(r)(e.input);else if(!ot(e.input))return;ft(e.input,a=>{var u;let s=a.value;if(typeof s=="string")s=l(s);else return;n.index.get(s)||(a.value=(u=ve(this.data,s))!=null?u:s)})}})}function be(){return{tables:new Map}}function Te(t,e={}){let{count:n}=e;return D("term",r=>{let l=dt(r);return(o,a)=>{let s=[];return o.value.text.forEach((u,i)=>{let d=a[u]>>>10,f=a[u]&T[10];for(let p=0;pu.start-i.start),{ranges:ct(s).slice(0,n)}}})}function Me(t){let e,n;return q({name:"highlight",data:be(),onTextInput(r,l){let{tables:o}=this.data;o.set(l,n=k())},onTextTokens(r){for(let l=0;l{let s=l.get(a.id);if(a.value.highlight)return;let u=o(a,s);a.value=Q(R({},a.value),{highlight:u})})}})}function ke(){return{directives:[]}}function gt(...t){return(e,n)=>{for(let r=0;r{if(r!=="match")throw new P("unsupported");let o=Fe(t),a=gt(...e.map(s=>s(n)));return $(n,({matches:s})=>{s.sort(o)}),(s,u)=>{let i=Math.min(s.matches.length,u.matches.length);for(let d=0,f=0;dr*(l.get(a.field)-l.get(s.field))}function Re(t,e={}){let n=dt(t.query),r=G(re),l=G(ne);return(o,a)=>{let s=r(o,n,f=>f),u=r(a,n,f=>f);if(s.length!==u.length)return u.length-s.length;let i=l(s),d=l(u);return i!==d?i-d:s[0]!==u[0]?s[0]-u[0]:0}}function qe(t){let e=new Map;return q({name:"order",data:ke(),onTextOptions(r,l){return E(this,null,function*(){for(let o=0;o"u")throw new P("unknown");o.push(u(r,s))}r.items.sort(gt(...o))}})}function ze(t){let e=t.handler();return q({name:"pagination",onTextQuery(n){return e.onQuery(n,t)},onTextResult(n){return e.onResult(n,t)}})}function Ae(t){let{id:e,size:n=10,from:r=0}=t;if(r-n>=0)return{id:e,size:n,from:r-n}}function Qe(t,e){let{id:n,size:r=10,from:l=0}=t;if(l+rE(null,null,function*(){let e=t.data;switch(e.type){case 0:Z=yield se(e.data.items,{separator:Zt(e.data.config.separator),transform:G(Gt),parser:r=>ae(r,"and",l=>({field:"*",value:ie(l.value),range:{start:l.start,end:l.end,value:l.index}})),compiler:le,fields:[C("title",r=>r.title,{weight:3}),C("text",r=>r.text),C("path",r=>r.path,{weight:2})],plugins:[he(),we(),pe({compiler:st,fields:[C("tags",r=>r.tags)],plugins:[oe({handlers:[ue()]})]}),qe({handlers:[r=>Ee({fields:r.fields,comparators:[Re]})],defaults:{order:[{type:"match",data:{field:"*"}}]}}),()=>q({onTextResult(r){r.total=r.items.length}}),ze({handler:Se,size:10}),Me({handler:r=>Te(r)}),()=>q({onTextResult(r){let{query:l}=r,o=l.values.map(({range:a,value:s})=>{var i,d;let u=!1;return s.forEach((f,c)=>{!u&&c<1&&(u=!0)}),u?-1:((i=a==null?void 0:a.end)!=null?i:0)-((d=a==null?void 0:a.start)!=null?d:0)});X(r,a=>{var s;(s=a.value.highlight)==null||s.ranges.forEach(u=>{u.value=o[u.value]})})}})]}),self.postMessage({type:1});break;case 2:let n=Z({type:"text",data:e.data});self.postMessage({type:3,data:n.data});break}})});var _e=qt(xt());})(); diff --git a/site/assets/stylesheets/classic/main.82a87433.min.css b/site/assets/stylesheets/classic/main.96fc3bb8.min.css similarity index 52% rename from site/assets/stylesheets/classic/main.82a87433.min.css rename to site/assets/stylesheets/classic/main.96fc3bb8.min.css index 6011a1f9b..d880a5202 100644 --- a/site/assets/stylesheets/classic/main.82a87433.min.css +++ b/site/assets/stylesheets/classic/main.96fc3bb8.min.css @@ -1 +1 @@ -@charset "UTF-8";html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;box-sizing:border-box}*,:after,:before{box-sizing:inherit}@media (prefers-reduced-motion){*,:after,:before{transition:none!important}}body{margin:0}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}hr{border:0;box-sizing:initial;display:block;height:.05rem;overflow:visible;padding:0}small{font-size:80%}sub,sup{line-height:1em}img{border-style:none}table{border-collapse:initial;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{background:#0000;border:0;font-family:inherit;font-size:inherit;margin:0;padding:0}input{border:0;outline:none}:root{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3;--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:#526cfe1a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-scheme=default]{color-scheme:light}[data-md-color-scheme=default] img[src$="#gh-dark-mode-only"],[data-md-color-scheme=default] img[src$="#only-dark"]{display:none}:root,[data-md-color-scheme=default]{--md-hue:225deg;--md-default-fg-color:#000000de;--md-default-fg-color--light:#0000008a;--md-default-fg-color--lighter:#00000052;--md-default-fg-color--lightest:#00000012;--md-default-bg-color:#fff;--md-default-bg-color--light:#ffffffb3;--md-default-bg-color--lighter:#ffffff4d;--md-default-bg-color--lightest:#ffffff1f;--md-code-fg-color:#36464e;--md-code-bg-color:#f5f5f5;--md-code-bg-color--light:#f5f5f5b3;--md-code-bg-color--lighter:#f5f5f54d;--md-code-hl-color:#4287ff;--md-code-hl-color--light:#4287ff1a;--md-code-hl-number-color:#d52a2a;--md-code-hl-special-color:#db1457;--md-code-hl-function-color:#a846b9;--md-code-hl-constant-color:#6e59d9;--md-code-hl-keyword-color:#3f6ec6;--md-code-hl-string-color:#1c7d4d;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-del-color:#f5503d26;--md-typeset-ins-color:#0bd57026;--md-typeset-kbd-color:#fafafa;--md-typeset-kbd-accent-color:#fff;--md-typeset-kbd-border-color:#b8b8b8;--md-typeset-mark-color:#ffff0080;--md-typeset-table-color:#0000001f;--md-typeset-table-color--light:rgba(0,0,0,.035);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-warning-fg-color:#000000de;--md-warning-bg-color:#ff9;--md-footer-fg-color:#fff;--md-footer-fg-color--light:#ffffffb3;--md-footer-fg-color--lighter:#ffffff73;--md-footer-bg-color:#000000de;--md-footer-bg-color--dark:#00000052;--md-shadow-z1:0 0.2rem 0.5rem #0000000d,0 0 0.05rem #0000001a;--md-shadow-z2:0 0.2rem 0.5rem #0000001a,0 0 0.05rem #00000040;--md-shadow-z3:0 0.2rem 0.5rem #0003,0 0 0.05rem #00000059;--color-foreground:0 0 0;--color-background:255 255 255;--color-background-subtle:240 240 240;--color-backdrop:255 255 255}.md-icon svg{fill:currentcolor;display:block;height:1.2rem;width:1.2rem}.md-icon svg.lucide{fill:#0000;stroke:currentcolor}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--md-text-font-family:var(--md-text-font,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif;--md-code-font-family:var(--md-code-font,_),SFMono-Regular,Consolas,Menlo,monospace}aside,body,input{font-feature-settings:"kern","liga";color:var(--md-typeset-color);font-family:var(--md-text-font-family)}code,kbd,pre{font-feature-settings:"kern";font-family:var(--md-code-font-family)}:root{--md-typeset-table-sort-icon:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--asc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--desc:url('data:image/svg+xml;charset=utf-8,')}.md-typeset{-webkit-print-color-adjust:exact;color-adjust:exact;font-size:.8rem;line-height:1.6;overflow-wrap:break-word}@media print{.md-typeset{font-size:.68rem}}.md-typeset blockquote,.md-typeset dl,.md-typeset figure,.md-typeset ol,.md-typeset pre,.md-typeset ul{margin-bottom:1em;margin-top:1em}.md-typeset h1{color:var(--md-default-fg-color--light);font-size:2em;line-height:1.3;margin:0 0 1.25em}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{font-size:1.5625em;line-height:1.4;margin:1.6em 0 .64em}.md-typeset h3{font-size:1.25em;font-weight:400;letter-spacing:-.01em;line-height:1.5;margin:1.6em 0 .8em}.md-typeset h2+h3{margin-top:.8em}.md-typeset h4{font-weight:700;letter-spacing:-.01em;margin:1em 0}.md-typeset h5,.md-typeset h6{color:var(--md-default-fg-color--light);font-size:.8em;font-weight:700;letter-spacing:-.01em;margin:1.25em 0}.md-typeset h5{text-transform:uppercase}.md-typeset h5 code{text-transform:none}.md-typeset hr{border-bottom:.05rem solid var(--md-default-fg-color--lightest);display:flow-root;margin:1.5em 0}.md-typeset a{color:var(--md-typeset-a-color);word-break:break-word}.md-typeset a,.md-typeset a:before{transition:color 125ms}.md-typeset a:focus,.md-typeset a:hover{color:var(--md-accent-fg-color)}.md-typeset a:focus code,.md-typeset a:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset a code{color:var(--md-typeset-a-color)}.md-typeset a.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset code,.md-typeset kbd,.md-typeset pre{color:var(--md-code-fg-color);direction:ltr;font-variant-ligatures:none;transition:background-color 125ms}@media print{.md-typeset code,.md-typeset kbd,.md-typeset pre{white-space:pre-wrap}}.md-typeset code{background-color:var(--md-code-bg-color);border-radius:.1rem;-webkit-box-decoration-break:clone;box-decoration-break:clone;font-size:.85em;padding:0 .2941176471em;transition:color 125ms,background-color 125ms;word-break:break-word}.md-typeset code:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset pre{display:flow-root;line-height:1.4;position:relative}.md-typeset pre>code{-webkit-box-decoration-break:slice;box-decoration-break:slice;box-shadow:none;display:block;margin:0;outline-color:var(--md-accent-fg-color);overflow:auto;padding:.7720588235em 1.1764705882em;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin;touch-action:auto;word-break:normal}.md-typeset pre>code:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-typeset pre>code::-webkit-scrollbar{height:.2rem;width:.2rem}.md-typeset pre>code::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset pre>code::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}.md-typeset kbd{background-color:var(--md-typeset-kbd-color);border-radius:.1rem;box-shadow:0 .1rem 0 .05rem var(--md-typeset-kbd-border-color),0 .1rem 0 var(--md-typeset-kbd-border-color),0 -.1rem .2rem var(--md-typeset-kbd-accent-color) inset;color:var(--md-default-fg-color);display:inline-block;font-size:.75em;padding:0 .6666666667em;vertical-align:text-top;word-break:break-word}.md-typeset mark{background-color:var(--md-typeset-mark-color);-webkit-box-decoration-break:clone;box-decoration-break:clone;color:inherit;word-break:break-word}.md-typeset abbr{cursor:help;text-decoration:none}.md-typeset [data-preview],.md-typeset abbr{border-bottom:.05rem dotted var(--md-default-fg-color--light)}.md-typeset small{opacity:.75}[dir=ltr] .md-typeset sub,[dir=ltr] .md-typeset sup{margin-left:.078125em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-right:.078125em}[dir=ltr] .md-typeset blockquote{padding-left:.6rem}[dir=rtl] .md-typeset blockquote{padding-right:.6rem}[dir=ltr] .md-typeset blockquote{border-left:.2rem solid var(--md-default-fg-color--lighter)}[dir=rtl] .md-typeset blockquote{border-right:.2rem solid var(--md-default-fg-color--lighter)}.md-typeset blockquote{color:var(--md-default-fg-color--light);margin-left:0;margin-right:0}.md-typeset ul{list-style-type:disc}.md-typeset ul[type]{list-style-type:revert-layer}[dir=ltr] .md-typeset ol,[dir=ltr] .md-typeset ul{margin-left:.625em}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-right:.625em}.md-typeset ol,.md-typeset ul{padding:0}.md-typeset ol:not([hidden]),.md-typeset ul:not([hidden]){display:flow-root}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}.md-typeset ol ol ol ol,.md-typeset ul ol ol ol{list-style-type:upper-alpha}.md-typeset ol ol ol ol ol,.md-typeset ul ol ol ol ol{list-style-type:upper-roman}.md-typeset ol[type],.md-typeset ul[type]{list-style-type:revert-layer}[dir=ltr] .md-typeset ol li,[dir=ltr] .md-typeset ul li{margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-right:1.25em}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}[dir=ltr] .md-typeset ol li ol,[dir=ltr] .md-typeset ol li ul,[dir=ltr] .md-typeset ul li ol,[dir=ltr] .md-typeset ul li ul{margin-left:.625em}[dir=rtl] .md-typeset ol li ol,[dir=rtl] .md-typeset ol li ul,[dir=rtl] .md-typeset ul li ol,[dir=rtl] .md-typeset ul li ul{margin-right:.625em}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset dd{margin-left:1.875em}[dir=rtl] .md-typeset dd{margin-right:1.875em}.md-typeset dd{margin-bottom:1.5em;margin-top:1em}.md-typeset img,.md-typeset svg,.md-typeset video{height:auto;max-width:100%}.md-typeset img[align=left]{margin:1em 1em 1em 0}.md-typeset img[align=right]{margin:1em 0 1em 1em}.md-typeset img[align]:only-child{margin-top:0}.md-typeset figure{display:flow-root;margin:1em auto;max-width:100%;text-align:center;width:fit-content}.md-typeset figure img{display:block;margin:0 auto}.md-typeset figcaption{font-style:italic;margin:1em auto;max-width:24rem}.md-typeset iframe{max-width:100%}.md-typeset table:not([class]){background-color:var(--md-default-bg-color);border:.05rem solid var(--md-typeset-table-color);border-radius:.1rem;display:inline-block;font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto}@media print{.md-typeset table:not([class]){display:table}}.md-typeset table:not([class])+*{margin-top:1.5em}.md-typeset table:not([class]) td>:first-child,.md-typeset table:not([class]) th>:first-child{margin-top:0}.md-typeset table:not([class]) td>:last-child,.md-typeset table:not([class]) th>:last-child{margin-bottom:0}.md-typeset table:not([class]) td:not([align]),.md-typeset table:not([class]) th:not([align]){text-align:left}[dir=rtl] .md-typeset table:not([class]) td:not([align]),[dir=rtl] .md-typeset table:not([class]) th:not([align]){text-align:right}.md-typeset table:not([class]) th{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) td{border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) tbody tr{transition:background-color 125ms}.md-typeset table:not([class]) tbody tr:hover{background-color:var(--md-typeset-table-color--light);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset}.md-typeset table:not([class]) a{word-break:normal}.md-typeset table th[role=columnheader]{cursor:pointer}[dir=ltr] .md-typeset table th[role=columnheader]:after{margin-left:.5em}[dir=rtl] .md-typeset table th[role=columnheader]:after{margin-right:.5em}.md-typeset table th[role=columnheader]:after{content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-typeset-table-sort-icon);mask-image:var(--md-typeset-table-sort-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset table th[role=columnheader]:hover:after{background-color:var(--md-default-fg-color--lighter)}.md-typeset table th[role=columnheader][aria-sort=ascending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--asc);mask-image:var(--md-typeset-table-sort-icon--asc)}.md-typeset table th[role=columnheader][aria-sort=descending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--desc);mask-image:var(--md-typeset-table-sort-icon--desc)}.md-typeset__scrollwrap{margin:1em -.8rem;overflow-x:auto;touch-action:auto}.md-typeset__table{display:inline-block;margin-bottom:.5em;padding:0 .8rem}@media print{.md-typeset__table{display:block}}html .md-typeset__table table{display:table;margin:0;overflow:hidden;width:100%}@media screen and (max-width:44.984375em){.md-content__inner>pre{margin:1em -.8rem}.md-content__inner>pre code{border-radius:0}}.md-typeset .md-author{border-radius:100%;display:block;flex-shrink:0;height:1.6rem;overflow:hidden;position:relative;transition:color 125ms,transform 125ms;width:1.6rem}.md-typeset .md-author img{display:block}.md-typeset .md-author--more{background:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--lighter);font-size:.6rem;font-weight:700;line-height:1.6rem;text-align:center}.md-typeset .md-author--long{height:2.4rem;width:2.4rem}.md-typeset a.md-author{transform:scale(1)}.md-typeset a.md-author img{border-radius:100%;filter:grayscale(100%) opacity(75%);transition:filter 125ms}.md-typeset a.md-author:focus,.md-typeset a.md-author:hover{transform:scale(1.1);z-index:1}.md-typeset a.md-author:focus img,.md-typeset a.md-author:hover img{filter:grayscale(0)}.md-banner{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color);overflow:auto}@media print{.md-banner{display:none}}.md-banner--warning{background-color:var(--md-warning-bg-color);color:var(--md-warning-fg-color)}.md-banner__inner{font-size:.7rem;margin:.6rem auto;padding:0 .8rem}[dir=ltr] .md-banner__button{float:right}[dir=rtl] .md-banner__button{float:left}.md-banner__button{color:inherit;cursor:pointer;transition:opacity .25s}.no-js .md-banner__button{display:none}.md-banner__button:hover{opacity:.7}html{scrollbar-gutter:stable;font-size:125%;height:100%;overflow-x:hidden}@media screen and (min-width:100em){html{font-size:137.5%}}@media screen and (min-width:125em){html{font-size:150%}}body{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;font-size:.5rem;min-height:100%;position:relative;width:100%}@media print{body{display:block}}@media screen and (max-width:59.984375em){body[data-md-scrolllock]{position:fixed}}.md-grid{margin-left:auto;margin-right:auto;max-width:61rem}.md-container{display:flex;flex-direction:column;flex-grow:1}@media print{.md-container{display:block}}.md-main{flex-grow:1}.md-main__inner{display:flex;height:100%;margin-top:1.5rem}.md-ellipsis{overflow:hidden;text-overflow:ellipsis}.md-toggle{display:none}.md-option{height:0;opacity:0;position:absolute;width:0}.md-option:checked+label:not([hidden]){display:block}.md-option.focus-visible+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-skip{background-color:var(--md-default-fg-color);border-radius:.1rem;color:var(--md-default-bg-color);font-size:.64rem;margin:.5rem;opacity:0;outline-color:var(--md-accent-fg-color);padding:.3rem .5rem;position:fixed;transform:translateY(.4rem);z-index:-1}.md-skip:focus{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 175ms 75ms;z-index:10}@page{margin:25mm}:root{--md-clipboard-icon:url('data:image/svg+xml;charset=utf-8,')}.md-clipboard{border-radius:.1rem;color:var(--md-default-fg-color--lightest);cursor:pointer;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em;z-index:1}@media print{.md-clipboard{display:none}}.md-clipboard:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}:hover>.md-clipboard{color:var(--md-default-fg-color--light)}.md-clipboard:focus,.md-clipboard:hover{color:var(--md-accent-fg-color)}.md-clipboard:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-image:var(--md-clipboard-icon);mask-image:var(--md-clipboard-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-clipboard--inline{cursor:pointer}.md-clipboard--inline code{transition:color .25s,background-color .25s}.md-clipboard--inline:focus code,.md-clipboard--inline:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}:root{--md-code-select-icon:url('data:image/svg+xml;charset=utf-8,');--md-code-copy-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-code__content{display:grid}.md-code__nav{background-color:var(--md-code-bg-color--lighter);border-radius:.1rem;display:flex;gap:.2rem;padding:.2rem;position:absolute;right:.25em;top:.25em;transition:background-color .25s;z-index:1}:hover>.md-code__nav{background-color:var(--md-code-bg-color--light)}.md-code__button{color:var(--md-default-fg-color--lightest);cursor:pointer;display:block;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em}:hover>*>.md-code__button{color:var(--md-default-fg-color--light)}.md-code__button.focus-visible,.md-code__button:hover{color:var(--md-accent-fg-color)}.md-code__button--active{color:var(--md-default-fg-color)!important}.md-code__button:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-code__button[data-md-type=select]:after{-webkit-mask-image:var(--md-code-select-icon);mask-image:var(--md-code-select-icon)}.md-code__button[data-md-type=copy]:after{-webkit-mask-image:var(--md-code-copy-icon);mask-image:var(--md-code-copy-icon)}@keyframes consent{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@keyframes overlay{0%{opacity:0}to{opacity:1}}.md-consent__overlay{animation:overlay .25s both;-webkit-backdrop-filter:blur(.1rem);backdrop-filter:blur(.1rem);background-color:#0000008a;height:100%;opacity:1;position:fixed;top:0;width:100%;z-index:5}.md-consent__inner{animation:consent .5s cubic-bezier(.1,.7,.1,1) both;background-color:var(--md-default-bg-color);border:0;border-radius:.1rem;bottom:0;box-shadow:0 0 .2rem #0000001a,0 .2rem .4rem #0003;max-height:100%;overflow:auto;padding:0;position:fixed;width:100%;z-index:5}.md-consent__form{padding:.8rem}.md-consent__settings{display:none;margin:1em 0}input:checked+.md-consent__settings{display:block}.md-consent__controls{margin-bottom:.8rem}.md-typeset .md-consent__controls .md-button{display:inline}@media screen and (max-width:44.984375em){.md-typeset .md-consent__controls .md-button{display:block;margin-top:.4rem;text-align:center;width:100%}}.md-consent label{cursor:pointer}.md-content{flex-grow:1;min-width:0}.md-content__inner{margin:0 .8rem 1.2rem;padding-top:.6rem}@media screen and (min-width:76.25em){[dir=ltr] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}[dir=ltr] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner,[dir=rtl] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=rtl] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}}.md-content__inner:before{content:"";display:block;height:.4rem}.md-content__inner>:last-child{margin-bottom:0}[dir=ltr] .md-content__button{float:right}[dir=rtl] .md-content__button{float:left}[dir=ltr] .md-content__button{margin-left:.4rem}[dir=rtl] .md-content__button{margin-right:.4rem}.md-content__button{margin:.4rem 0;padding:0}@media print{.md-content__button{display:none}}.md-typeset .md-content__button{color:var(--md-default-fg-color--lighter)}.md-content__button svg{display:inline;vertical-align:top}[dir=rtl] .md-content__button svg{transform:scaleX(-1)}.md-content__button svg.lucide{fill:#0000;stroke:currentcolor}[dir=ltr] .md-dialog{right:.8rem}[dir=rtl] .md-dialog{left:.8rem}.md-dialog{background-color:var(--md-default-fg-color);border-radius:.1rem;bottom:.8rem;box-shadow:var(--md-shadow-z3);min-width:11.1rem;opacity:0;padding:.4rem .6rem;pointer-events:none;position:fixed;transform:translateY(100%);transition:transform 0ms .4s,opacity .4s;z-index:4}@media print{.md-dialog{display:none}}.md-dialog--active{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(.075,.85,.175,1),opacity .4s}.md-dialog__inner{color:var(--md-default-bg-color);font-size:.7rem}.md-feedback{margin:2em 0 1em;text-align:center}.md-feedback fieldset{border:none;margin:0;padding:0}.md-feedback__title{font-weight:700;margin:1em auto}.md-feedback__inner{position:relative}.md-feedback__list{display:flex;flex-wrap:wrap;place-content:baseline center;position:relative}.md-feedback__list:hover .md-icon:not(:disabled){color:var(--md-default-fg-color--lighter)}:disabled .md-feedback__list{min-height:1.8rem}.md-feedback__icon{color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;margin:0 .1rem;transition:color 125ms}.md-feedback__icon:not(:disabled).md-icon:hover{color:var(--md-accent-fg-color)}.md-feedback__icon:disabled{color:var(--md-default-fg-color--lightest);pointer-events:none}.md-feedback__note{opacity:0;position:relative;transform:translateY(.4rem);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-feedback__note>*{margin:0 auto;max-width:16rem}:disabled .md-feedback__note{opacity:1;transform:translateY(0)}@media print{.md-feedback{display:none}}.md-footer{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color)}@media print{.md-footer{display:none}}.md-footer__inner{justify-content:space-between;overflow:auto;padding:.2rem}.md-footer__inner:not([hidden]){display:flex}.md-footer__link{align-items:end;display:flex;flex-grow:0.01;margin-bottom:.4rem;margin-top:1rem;max-width:100%;outline-color:var(--md-accent-fg-color);overflow:hidden;transition:opacity .25s}.md-footer__link:focus,.md-footer__link:hover{opacity:.7}[dir=rtl] .md-footer__link svg{transform:scaleX(-1)}@media screen and (max-width:44.984375em){.md-footer__link--prev{flex-shrink:0}.md-footer__link--prev .md-footer__title{display:none}}[dir=ltr] .md-footer__link--next{margin-left:auto}[dir=rtl] .md-footer__link--next{margin-right:auto}.md-footer__link--next{text-align:right}[dir=rtl] .md-footer__link--next{text-align:left}.md-footer__title{flex-grow:1;font-size:.9rem;margin-bottom:.7rem;max-width:calc(100% - 2.4rem);padding:0 1rem;white-space:nowrap}.md-footer__button{margin:.2rem;padding:.4rem}.md-footer__direction{font-size:.64rem;opacity:.7}.md-footer-meta{background-color:var(--md-footer-bg-color--dark)}.md-footer-meta__inner{display:flex;flex-wrap:wrap;justify-content:space-between;padding:.2rem}html .md-footer-meta.md-typeset a{color:var(--md-footer-fg-color--light)}html .md-footer-meta.md-typeset a:focus,html .md-footer-meta.md-typeset a:hover{color:var(--md-footer-fg-color)}.md-copyright{color:var(--md-footer-fg-color--lighter);font-size:.64rem;margin:auto .6rem;padding:.4rem 0;width:100%}@media screen and (min-width:45em){.md-copyright{width:auto}}.md-copyright__highlight{color:var(--md-footer-fg-color--light)}.md-social{display:inline-flex;gap:.2rem;margin:0 .4rem;padding:.2rem 0 .6rem}@media screen and (min-width:45em){.md-social{padding:.6rem 0}}.md-social__link{display:inline-block;height:1.6rem;text-align:center;width:1.6rem}.md-social__link:before{line-height:1.9}.md-social__link svg{fill:currentcolor;max-height:.8rem;vertical-align:-25%}.md-social__link svg.lucide{fill:#0000;stroke:currentcolor}.md-typeset .md-button{border:.1rem solid;border-radius:.1rem;color:var(--md-primary-fg-color);cursor:pointer;display:inline-block;font-weight:700;padding:.625em 2em;transition:color 125ms,background-color 125ms,border-color 125ms}.md-typeset .md-button--primary{background-color:var(--md-primary-fg-color);border-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color)}.md-typeset .md-button:focus,.md-typeset .md-button:hover{background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[dir=ltr] .md-typeset .md-input{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .md-input,[dir=rtl] .md-typeset .md-input{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .md-input{border-top-left-radius:.1rem}.md-typeset .md-input{border-bottom:.1rem solid var(--md-default-fg-color--lighter);box-shadow:var(--md-shadow-z1);font-size:.8rem;height:1.8rem;padding:0 .6rem;transition:border .25s,box-shadow .25s}.md-typeset .md-input:focus,.md-typeset .md-input:hover{border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input--stretch{width:100%}.md-header{background-color:var(--md-primary-fg-color);box-shadow:0 0 .2rem #0000,0 .2rem .4rem #0000;color:var(--md-primary-bg-color);display:block;left:0;position:sticky;right:0;top:0;z-index:4}@media print{.md-header{display:none}}.md-header[hidden]{transform:translateY(-100%);transition:transform .25s cubic-bezier(.8,0,.6,1),box-shadow .25s}.md-header--shadow{box-shadow:0 0 .2rem #0000001a,0 .2rem .4rem #0003;transition:transform .25s cubic-bezier(.1,.7,.1,1),box-shadow .25s}.md-header__inner{align-items:center;display:flex;padding:0 .2rem}.md-header__button{color:currentcolor;cursor:pointer;margin:.2rem;outline-color:var(--md-accent-fg-color);padding:.4rem;position:relative;transition:opacity .25s;vertical-align:middle;z-index:1}.md-header__button:hover{opacity:.7}.md-header__button:not([hidden]){display:inline-block}.md-header__button:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-header__button.md-logo{margin:.2rem;padding:.4rem}@media screen and (max-width:76.234375em){.md-header__button.md-logo{display:none}}.md-header__button.md-logo img,.md-header__button.md-logo svg{fill:currentcolor;display:block;height:1.2rem;width:auto}@media screen and (min-width:60em){.md-header__button[for=__search]{display:none}}.no-js .md-header__button[for=__search]{display:none}[dir=rtl] .md-header__button[for=__search] svg{transform:scaleX(-1)}@media screen and (min-width:76.25em){.md-header__button[for=__drawer]{display:none}}.md-header__topic{display:flex;max-width:100%;position:absolute;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;white-space:nowrap}.md-header__topic+.md-header__topic{opacity:0;pointer-events:none;transform:translateX(1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__topic+.md-header__topic{transform:translateX(-1.25rem)}.md-header__topic:first-child{font-weight:700}[dir=ltr] .md-header__title{margin-left:1rem;margin-right:.4rem}[dir=rtl] .md-header__title{margin-left:.4rem;margin-right:1rem}.md-header__title{flex-grow:1;font-size:.9rem;height:2.4rem;line-height:2.4rem}.md-header__title--active .md-header__topic{opacity:0;pointer-events:none;transform:translateX(-1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__title--active .md-header__topic{transform:translateX(1.25rem)}.md-header__title--active .md-header__topic+.md-header__topic{opacity:1;pointer-events:auto;transform:translateX(0);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;z-index:0}.md-header__title>.md-header__ellipsis{height:100%;position:relative;width:100%}.md-header__option{display:flex;flex-shrink:0;max-width:100%;white-space:nowrap}.md-header__option>input{bottom:0}.md-header__source{display:none}@media screen and (min-width:60em){[dir=ltr] .md-header__source{margin-left:1rem}[dir=rtl] .md-header__source{margin-right:1rem}.md-header__source{display:block;max-width:11.7rem;width:11.7rem}}@media screen and (min-width:76.25em){[dir=ltr] .md-header__source{margin-left:1.4rem}[dir=rtl] .md-header__source{margin-right:1.4rem}}.md-meta{color:var(--md-default-fg-color--light);font-size:.7rem;line-height:1.3}.md-meta__list{display:inline-flex;flex-wrap:wrap;list-style:none;margin:0;padding:0}.md-meta__item:not(:last-child):after{content:"·";margin-left:.2rem;margin-right:.2rem}.md-meta__link{color:var(--md-typeset-a-color)}.md-meta__link:focus,.md-meta__link:hover{color:var(--md-accent-fg-color)}.md-draft{background-color:#ff1744;border-radius:.125em;color:#fff;display:inline-block;font-weight:700;padding-left:.5714285714em;padding-right:.5714285714em}:root{--md-nav-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-nav-icon--next:url('data:image/svg+xml;charset=utf-8,');--md-toc-icon:url('data:image/svg+xml;charset=utf-8,')}.md-nav{font-size:.7rem;line-height:1.3}.md-nav__title{color:var(--md-default-fg-color--light);display:block;font-weight:700;overflow:hidden;padding:0 .6rem;text-overflow:ellipsis}.md-nav__title .md-nav__button{display:none}.md-nav__title .md-nav__button img{height:100%;width:auto}.md-nav__title .md-nav__button.md-logo img,.md-nav__title .md-nav__button.md-logo svg{fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__list{list-style:none;margin:0;padding:0}.md-nav__link{align-items:flex-start;display:flex;gap:.4rem;margin-top:.625em;scroll-snap-align:start;transition:color 125ms}.md-nav__link--passed,.md-nav__link--passed code{color:var(--md-default-fg-color--light)}.md-nav__item .md-nav__link--active,.md-nav__item .md-nav__link--active code{color:var(--md-typeset-a-color)}.md-nav__link .md-ellipsis{position:relative}.md-nav__link .md-ellipsis code{word-break:normal}[dir=ltr] .md-nav__link .md-icon:last-child{margin-left:auto}[dir=rtl] .md-nav__link .md-icon:last-child{margin-right:auto}.md-nav__link .md-typeset{font-size:.7rem;line-height:1.3}.md-nav__link svg{fill:currentcolor;flex-shrink:0;height:1.3em;position:relative;width:1.3em}.md-nav__link svg.lucide{fill:#0000;stroke:currentcolor}.md-nav__link[for]:focus,.md-nav__link[for]:hover,.md-nav__link[href]:focus,.md-nav__link[href]:hover{color:var(--md-accent-fg-color);cursor:pointer}.md-nav__link[for]:focus code,.md-nav__link[for]:hover code,.md-nav__link[href]:focus code,.md-nav__link[href]:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-nav__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-nav--primary .md-nav__link[for=__toc]{display:none}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{background-color:currentcolor;display:block;height:100%;-webkit-mask-image:var(--md-toc-icon);mask-image:var(--md-toc-icon);width:100%}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:none}.md-nav__container>.md-nav__link{margin-top:0}.md-nav__container>.md-nav__link:first-child{flex-grow:1;min-width:0}.md-nav__icon{flex-shrink:0}.md-nav__source{display:none}@media screen and (max-width:76.234375em){.md-nav--primary,.md-nav--primary .md-nav{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;height:100%;left:0;position:absolute;right:0;top:0;z-index:1}.md-nav--primary .md-nav__item,.md-nav--primary .md-nav__title{font-size:.8rem;line-height:1.5}.md-nav--primary .md-nav__title{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);cursor:pointer;height:5.6rem;line-height:2.4rem;padding:3rem .8rem .2rem;position:relative;white-space:nowrap}[dir=ltr] .md-nav--primary .md-nav__title .md-nav__icon{left:.4rem}[dir=rtl] .md-nav--primary .md-nav__title .md-nav__icon{right:.4rem}.md-nav--primary .md-nav__title .md-nav__icon{display:block;height:1.2rem;margin:.2rem;position:absolute;top:.4rem;width:1.2rem}.md-nav--primary .md-nav__title .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--prev);mask-image:var(--md-nav-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}.md-nav--primary .md-nav__title~.md-nav__list{background-color:var(--md-default-bg-color);box-shadow:0 .05rem 0 var(--md-default-fg-color--lightest) inset;overflow-y:auto;overscroll-behavior-y:contain;scroll-snap-type:y mandatory;touch-action:pan-y}.md-nav--primary .md-nav__title~.md-nav__list>:first-child{border-top:0}.md-nav--primary .md-nav__title[for=__drawer]{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);font-weight:700}.md-nav--primary .md-nav__title .md-logo{display:block;left:.2rem;margin:.2rem;padding:.4rem;position:absolute;right:.2rem;top:.2rem}.md-nav--primary .md-nav__list{flex:1}.md-nav--primary .md-nav__item{border-top:.05rem solid var(--md-default-fg-color--lightest)}.md-nav--primary .md-nav__item--active>.md-nav__link{color:var(--md-typeset-a-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:focus,.md-nav--primary .md-nav__item--active>.md-nav__link:hover{color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__link{margin-top:0;padding:.6rem .8rem}.md-nav--primary .md-nav__link svg{margin-top:.1em}.md-nav--primary .md-nav__link>.md-nav__link{padding:0}[dir=ltr] .md-nav--primary .md-nav__link .md-nav__icon{margin-right:-.2rem}[dir=rtl] .md-nav--primary .md-nav__link .md-nav__icon{margin-left:-.2rem}.md-nav--primary .md-nav__link .md-nav__icon{font-size:1.2rem;height:1.2rem;width:1.2rem}.md-nav--primary .md-nav__link .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-nav--primary .md-nav__icon:after{transform:scale(-1)}.md-nav--primary .md-nav--secondary .md-nav{background-color:initial;position:static}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:1.4rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-right:1.4rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-right:2rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:2.6rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-right:2.6rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:3.2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-right:3.2rem}.md-nav--secondary{background-color:initial}.md-nav__toggle~.md-nav{display:flex;opacity:0;transform:translateX(100%);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity 125ms 50ms}[dir=rtl] .md-nav__toggle~.md-nav{transform:translateX(-100%)}.md-nav__toggle:checked~.md-nav{opacity:1;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 125ms 125ms}.md-nav__toggle:checked~.md-nav>.md-nav__list{backface-visibility:hidden}}@media screen and (max-width:59.984375em){.md-nav--primary .md-nav__link[for=__toc]{display:flex}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--primary .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:flex}.md-nav__source{background-color:var(--md-primary-fg-color--dark);color:var(--md-primary-bg-color);display:block;padding:0 .2rem}}@media screen and (min-width:60em) and (max-width:76.234375em){.md-nav--integrated .md-nav__link[for=__toc]{display:flex}.md-nav--integrated .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--integrated .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--integrated .md-nav__link[for=__toc]~.md-nav{display:flex}}@media screen and (min-width:60em){.md-nav{margin-bottom:-.4rem}.md-nav--secondary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--secondary .md-nav__title[for=__toc]{scroll-snap-align:start}.md-nav--secondary .md-nav__title .md-nav__icon{display:none}[dir=ltr] .md-nav--secondary .md-nav__list{padding-left:.6rem}[dir=rtl] .md-nav--secondary .md-nav__list{padding-right:.6rem}.md-nav--secondary .md-nav__list{padding-bottom:.4rem}[dir=ltr] .md-nav--secondary .md-nav__item>.md-nav__link{margin-right:.4rem}[dir=rtl] .md-nav--secondary .md-nav__item>.md-nav__link{margin-left:.4rem}}@media screen and (min-width:76.25em){.md-nav{margin-bottom:-.4rem;transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav--primary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--primary .md-nav__title[for=__drawer]{scroll-snap-align:start}.md-nav--primary .md-nav__title .md-nav__icon{display:none}[dir=ltr] .md-nav--primary .md-nav__list{padding-left:.6rem}[dir=rtl] .md-nav--primary .md-nav__list{padding-right:.6rem}.md-nav--primary .md-nav__list{padding-bottom:.4rem}[dir=ltr] .md-nav--primary .md-nav__item>.md-nav__link{margin-right:.4rem}[dir=rtl] .md-nav--primary .md-nav__item>.md-nav__link{margin-left:.4rem}.md-nav__toggle~.md-nav{display:grid;grid-template-rows:minmax(.4rem,0fr);opacity:0;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .25s,visibility 0ms .25s;visibility:collapse}.md-nav__toggle~.md-nav>.md-nav__list{overflow:hidden}.md-nav__toggle.md-toggle--indeterminate~.md-nav,.md-nav__toggle:checked~.md-nav{grid-template-rows:minmax(.4rem,1fr);opacity:1;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .15s .1s,visibility 0ms;visibility:visible}.md-nav__toggle.md-toggle--indeterminate~.md-nav{transition:none}.md-nav__item--nested>.md-nav>.md-nav__title{display:none}.md-nav__item--section{display:block;margin:1.25em 0}.md-nav__item--section:last-child{margin-bottom:0}.md-nav__item--section>.md-nav__link{font-weight:700}.md-nav__item--section>.md-nav__link[for]{color:var(--md-default-fg-color--light)}.md-nav__item--section>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav__item--section>.md-nav__link .md-icon,.md-nav__item--section>.md-nav__link>[for]{display:none}[dir=ltr] .md-nav__item--section>.md-nav{margin-left:-.6rem}[dir=rtl] .md-nav__item--section>.md-nav{margin-right:-.6rem}.md-nav__item--section>.md-nav{display:block;opacity:1;visibility:visible}.md-nav__item--section>.md-nav>.md-nav__list>.md-nav__item{padding:0}.md-nav__icon{border-radius:100%;height:.9rem;transition:background-color .25s;width:.9rem}.md-nav__icon:hover{background-color:var(--md-accent-fg-color--transparent)}.md-nav__icon:after{background-color:currentcolor;border-radius:100%;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:transform .25s;vertical-align:-.1rem;width:100%}[dir=rtl] .md-nav__icon:after{transform:rotate(180deg)}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link .md-nav__icon:after,.md-nav__item--nested .md-toggle--indeterminate~.md-nav__link .md-nav__icon:after{transform:rotate(90deg)}.md-nav--lifted>.md-nav__list>.md-nav__item,.md-nav--lifted>.md-nav__title{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active{display:block}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);margin-top:0;position:sticky;top:0;z-index:1}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active.md-nav__item--section{margin:0}[dir=ltr] .md-nav--lifted>.md-nav__list>.md-nav__item>.md-nav:not(.md-nav--secondary){margin-left:-.6rem}[dir=rtl] .md-nav--lifted>.md-nav__list>.md-nav__item>.md-nav:not(.md-nav--secondary){margin-right:-.6rem}.md-nav--lifted>.md-nav__list>.md-nav__item>[for]{color:var(--md-default-fg-color--light)}.md-nav--lifted .md-nav[data-md-level="1"]{grid-template-rows:minmax(.4rem,1fr);opacity:1;visibility:visible}[dir=ltr] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-left:.05rem solid var(--md-primary-fg-color)}[dir=rtl] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-right:.05rem solid var(--md-primary-fg-color)}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{display:block;margin-bottom:1.25em;opacity:1;visibility:visible}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__list{overflow:visible;padding-bottom:0}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__title{display:none}}.md-pagination{font-size:.8rem;font-weight:700;gap:.4rem}.md-pagination,.md-pagination>*{align-items:center;display:flex;justify-content:center}.md-pagination>*{border-radius:.2rem;height:1.8rem;min-width:1.8rem;text-align:center}.md-pagination__current{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light)}.md-pagination__link{transition:color 125ms,background-color 125ms}.md-pagination__link:focus,.md-pagination__link:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-pagination__link:focus svg,.md-pagination__link:hover svg{color:var(--md-accent-fg-color)}.md-pagination__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-pagination__link svg{fill:currentcolor;color:var(--md-default-fg-color--lighter);display:block;max-height:100%;width:1.2rem}:root{--md-path-icon:url('data:image/svg+xml;charset=utf-8,')}.md-path{font-size:.7rem;margin:0 .8rem;overflow:auto;padding-top:1.2rem}.md-path:not([hidden]){display:block}@media screen and (min-width:76.25em){.md-path{margin:0 1.2rem}}.md-path__list{align-items:center;display:flex;gap:.2rem;list-style:none;margin:0;padding:0}.md-path__item:not(:first-child){display:inline-flex;gap:.2rem;white-space:nowrap}.md-path__item:not(:first-child):before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline;height:.8rem;-webkit-mask-image:var(--md-path-icon);mask-image:var(--md-path-icon);width:.8rem}.md-path__link{align-items:center;color:var(--md-default-fg-color--light);display:flex}.md-path__link:focus,.md-path__link:hover{color:var(--md-accent-fg-color)}:root{--md-post-pin-icon:url('data:image/svg+xml;charset=utf-8,')}.md-post__back{border-bottom:.05rem solid var(--md-default-fg-color--lightest);margin-bottom:1.2rem;padding-bottom:1.2rem}@media screen and (max-width:76.234375em){.md-post__back{display:none}}[dir=rtl] .md-post__back svg{transform:scaleX(-1)}.md-post__authors{display:flex;flex-direction:column;gap:.6rem;margin:0 .6rem 1.2rem}.md-post .md-post__meta a{transition:color 125ms}.md-post .md-post__meta a:focus,.md-post .md-post__meta a:hover{color:var(--md-accent-fg-color)}.md-post__title{color:var(--md-default-fg-color--light);font-weight:700}.md-post--excerpt{margin-bottom:3.2rem}.md-post--excerpt .md-post__header{align-items:center;display:flex;gap:.6rem;min-height:1.6rem}.md-post--excerpt .md-post__authors{align-items:center;display:inline-flex;flex-direction:row;gap:.2rem;margin:0;min-height:2.4rem}[dir=ltr] .md-post--excerpt .md-post__meta .md-meta__list{margin-right:.4rem}[dir=rtl] .md-post--excerpt .md-post__meta .md-meta__list{margin-left:.4rem}.md-post--excerpt .md-post__content>:first-child{--md-scroll-margin:6rem;margin-top:0}.md-post>.md-nav--secondary{margin:1em 0}.md-pin{background:var(--md-default-fg-color--lightest);border-radius:1rem;margin-top:-.05rem;padding:.2rem}.md-pin:after{background-color:currentcolor;content:"";display:block;height:.6rem;margin:0 auto;-webkit-mask-image:var(--md-post-pin-icon);mask-image:var(--md-post-pin-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.6rem}.md-profile{align-items:center;display:flex;font-size:.7rem;gap:.6rem;line-height:1.4;width:100%}.md-profile__description{flex-grow:1}.md-content--post{display:flex}@media screen and (max-width:76.234375em){.md-content--post{flex-flow:column-reverse}}.md-content--post>.md-content__inner{flex-grow:1;min-width:0}@media screen and (min-width:76.25em){[dir=ltr] .md-content--post>.md-content__inner{margin-left:1.2rem}[dir=rtl] .md-content--post>.md-content__inner{margin-right:1.2rem}}@media screen and (max-width:76.234375em){.md-sidebar.md-sidebar--post{padding:0;position:static;width:100%}.md-sidebar.md-sidebar--post .md-sidebar__scrollwrap{overflow:visible}.md-sidebar.md-sidebar--post .md-sidebar__inner{padding:0}.md-sidebar.md-sidebar--post .md-post__meta{margin-left:.6rem;margin-right:.6rem}.md-sidebar.md-sidebar--post .md-nav__item{border:none;display:inline}.md-sidebar.md-sidebar--post .md-nav__list{display:inline-flex;flex-wrap:wrap;gap:.6rem;padding-bottom:.6rem;padding-top:.6rem}.md-sidebar.md-sidebar--post .md-nav__link{padding:0}.md-sidebar.md-sidebar--post .md-nav{height:auto;margin-bottom:0;position:static}}:root{--md-progress-value:0;--md-progress-delay:400ms}.md-progress{background:var(--md-primary-bg-color);height:.075rem;opacity:min(clamp(0,var(--md-progress-value),1),clamp(0,100 - var(--md-progress-value),1));position:fixed;top:0;transform:scaleX(calc(var(--md-progress-value)*1%));transform-origin:left;transition:transform .5s cubic-bezier(.19,1,.22,1),opacity .25s var(--md-progress-delay);width:100%;z-index:4}:root{--md-search-icon:url('data:image/svg+xml;charset=utf-8,')}.md-search{position:relative}@media screen and (min-width:60em){.md-search{padding:.2rem 0}}@media screen and (max-width:59.984375em){.md-search{display:none}}.no-js .md-search{display:none}[dir=ltr] .md-search__button{padding-left:1.9rem;padding-right:2.2rem}[dir=rtl] .md-search__button{padding-left:2.2rem;padding-right:1.9rem}.md-search__button{background:var(--md-primary-fg-color);color:var(--md-primary-bg-color);cursor:pointer;font-size:.7rem;position:relative;text-align:left}@media screen and (min-width:45em){.md-search__button{background-color:#00000042;border-radius:.2rem;height:1.6rem;transition:background-color .4s,color .4s;width:8.9rem}.md-search__button:focus,.md-search__button:hover{background-color:#ffffff1f;color:var(--md-primary-bg-color)}}[dir=ltr] .md-search__button:before{left:0}[dir=rtl] .md-search__button:before{right:0}.md-search__button:before{background-color:var(--md-primary-bg-color);content:"";height:1rem;margin-left:.5rem;-webkit-mask-image:var(--md-search-icon);mask-image:var(--md-search-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.3rem;width:1rem}.md-search__button:after{background:#00000042;border-radius:.1rem;content:"Ctrl+K";display:block;font-size:.6rem;padding:.1rem .2rem;position:absolute;right:.6rem;top:.35rem}[data-platform^=Mac] .md-search__button:after{content:"⌘K"}.md-select{position:relative;z-index:1}.md-select__inner{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);left:50%;margin-top:.2rem;max-height:0;opacity:0;position:absolute;top:calc(100% - .2rem);transform:translate3d(-50%,.3rem,0);transition:transform .25s 375ms,opacity .25s .25s,max-height 0ms .5s}@media screen and (max-width:59.984375em){.md-select__inner{left:100%;transform:translate3d(-100%,.3rem,0)}}.md-select:focus-within .md-select__inner,.md-select:hover .md-select__inner{max-height:min(75vh,28rem);opacity:1;transform:translate3d(-50%,0,0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}@media screen and (max-width:59.984375em){.md-select:focus-within .md-select__inner,.md-select:hover .md-select__inner{transform:translate3d(-100%,0,0)}}.md-select__inner:after{border-bottom:.2rem solid #0000;border-bottom-color:var(--md-default-bg-color);border-left:.2rem solid #0000;border-right:.2rem solid #0000;border-top:0;content:"";filter:drop-shadow(0 -1px 0 var(--md-default-fg-color--lightest));height:0;left:50%;margin-left:-.2rem;margin-top:-.2rem;position:absolute;top:0;width:0}@media screen and (max-width:59.984375em){.md-select__inner:after{left:auto;right:1rem}}.md-select__list{border-radius:.1rem;font-size:.8rem;list-style-type:none;margin:0;max-height:inherit;overflow:auto;padding:0}.md-select__item{line-height:1.8rem}[dir=ltr] .md-select__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-select__link{padding-left:1.2rem;padding-right:.6rem}.md-select__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:background-color .25s,color .25s;width:100%}.md-select__link:focus,.md-select__link:hover{color:var(--md-accent-fg-color)}.md-select__link:focus{background-color:var(--md-default-fg-color--lightest)}.md-sidebar{align-self:flex-start;flex-shrink:0;padding:1.2rem 0;position:sticky;top:2.4rem;width:12.1rem}@media print{.md-sidebar{display:none}}@media screen and (max-width:76.234375em){[dir=ltr] .md-sidebar--primary{left:-12.1rem}[dir=rtl] .md-sidebar--primary{right:-12.1rem}.md-sidebar--primary{background-color:var(--md-default-bg-color);display:block;height:100%;position:fixed;top:0;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;width:12.1rem;z-index:5}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:var(--md-shadow-z3);transform:translateX(12.1rem)}[dir=rtl] [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{transform:translateX(-12.1rem)}.md-sidebar--primary .md-sidebar__scrollwrap{bottom:0;left:0;margin:0;overflow:hidden;overscroll-behavior-y:contain;position:absolute;right:0;scroll-snap-type:none;top:0}}@media screen and (min-width:76.25em){.md-sidebar{height:0}.no-js .md-sidebar{height:auto}.md-header--lifted~.md-container .md-sidebar{top:4.8rem}}.md-sidebar--secondary{display:none;order:2}@media screen and (min-width:60em){.md-sidebar--secondary{height:0}.no-js .md-sidebar--secondary{height:auto}.md-sidebar--secondary:not([hidden]){display:block}.md-sidebar--secondary .md-sidebar__scrollwrap{touch-action:pan-y}}.md-sidebar__scrollwrap{backface-visibility:hidden;margin:0 .2rem;overflow-y:auto;scrollbar-color:var(--md-default-fg-color--lighter) #0000}@media screen and (min-width:60em){.md-sidebar__scrollwrap{scrollbar-gutter:stable;scrollbar-width:thin}}.md-sidebar__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-sidebar__scrollwrap:focus-within,.md-sidebar__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb:hover,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@supports selector(::-webkit-scrollbar){.md-sidebar__scrollwrap{scrollbar-gutter:auto}[dir=ltr] .md-sidebar__inner{padding-right:calc(100% - 11.5rem)}[dir=rtl] .md-sidebar__inner{padding-left:calc(100% - 11.5rem)}}@media screen and (max-width:76.234375em){.md-overlay{background-color:#0000008a;height:0;opacity:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0;z-index:5}[data-md-toggle=drawer]:checked~.md-overlay{height:100%;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@keyframes facts{0%{height:0}to{height:.65rem}}@keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}:root{--md-source-forks-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-repositories-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-stars-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-source{backface-visibility:hidden;display:block;font-size:.65rem;line-height:1.2;outline-color:var(--md-accent-fg-color);transition:opacity .25s;white-space:nowrap}.md-source:hover{opacity:.7}.md-source__icon{display:inline-block;height:2.4rem;vertical-align:middle;width:2rem}[dir=ltr] .md-source__icon svg{margin-left:.6rem}[dir=rtl] .md-source__icon svg{margin-right:.6rem}.md-source__icon svg{margin-top:.6rem}[dir=ltr] .md-source__icon+.md-source__repository{padding-left:2rem}[dir=rtl] .md-source__icon+.md-source__repository{padding-right:2rem}[dir=ltr] .md-source__icon+.md-source__repository{margin-left:-2rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-right:-2rem}[dir=ltr] .md-source__repository{margin-left:.6rem}[dir=rtl] .md-source__repository{margin-right:.6rem}.md-source__repository{display:inline-block;max-width:calc(100% - 1.2rem);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}.md-source__facts{display:flex;font-size:.55rem;gap:.4rem;list-style-type:none;margin:.1rem 0 0;opacity:.75;overflow:hidden;padding:0;width:100%}.md-source__repository--active .md-source__facts{animation:facts .25s ease-in}.md-source__fact{overflow:hidden;text-overflow:ellipsis}.md-source__repository--active .md-source__fact{animation:fact .4s ease-out}[dir=ltr] .md-source__fact:before{margin-right:.1rem}[dir=rtl] .md-source__fact:before{margin-left:.1rem}.md-source__fact:before{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-top;width:.6rem}.md-source__fact:nth-child(1n+2){flex-shrink:0}.md-source__fact--version:before{-webkit-mask-image:var(--md-source-version-icon);mask-image:var(--md-source-version-icon)}.md-source__fact--stars:before{-webkit-mask-image:var(--md-source-stars-icon);mask-image:var(--md-source-stars-icon)}.md-source__fact--forks:before{-webkit-mask-image:var(--md-source-forks-icon);mask-image:var(--md-source-forks-icon)}.md-source__fact--repositories:before{-webkit-mask-image:var(--md-source-repositories-icon);mask-image:var(--md-source-repositories-icon)}.md-source-file{margin:1em 0}[dir=ltr] .md-source-file__fact{margin-right:.6rem}[dir=rtl] .md-source-file__fact{margin-left:.6rem}.md-source-file__fact{align-items:center;color:var(--md-default-fg-color--light);display:inline-flex;font-size:.68rem;gap:.3rem}.md-source-file__fact .md-icon{flex-shrink:0;margin-bottom:.05rem}[dir=ltr] .md-source-file__fact .md-author{float:left}[dir=rtl] .md-source-file__fact .md-author{float:right}.md-source-file__fact .md-author{margin-right:.2rem}.md-source-file__fact svg{width:.9rem}:root{--md-status:url('data:image/svg+xml;charset=utf-8,');--md-status--new:url('data:image/svg+xml;charset=utf-8,');--md-status--deprecated:url('data:image/svg+xml;charset=utf-8,');--md-status--encrypted:url('data:image/svg+xml;charset=utf-8,')}.md-status:after{background-color:var(--md-default-fg-color--light);content:"";display:inline-block;height:1.125em;-webkit-mask-image:var(--md-status);mask-image:var(--md-status);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-bottom;width:1.125em}.md-status:hover:after{background-color:currentcolor}.md-status--new:after{-webkit-mask-image:var(--md-status--new);mask-image:var(--md-status--new)}.md-status--deprecated:after{-webkit-mask-image:var(--md-status--deprecated);mask-image:var(--md-status--deprecated)}.md-status--encrypted:after{-webkit-mask-image:var(--md-status--encrypted);mask-image:var(--md-status--encrypted)}.md-tabs{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);display:block;line-height:1.3;overflow:auto;width:100%;z-index:3}@media print{.md-tabs{display:none}}@media screen and (max-width:76.234375em){.md-tabs{display:none}}.md-tabs[hidden]{pointer-events:none}[dir=ltr] .md-tabs__list{margin-left:.2rem}[dir=rtl] .md-tabs__list{margin-right:.2rem}.md-tabs__list{contain:content;display:flex;list-style:none;margin:0;overflow:auto;padding:0;scrollbar-width:none;white-space:nowrap}.md-tabs__list::-webkit-scrollbar{display:none}.md-tabs__item{height:2.4rem;padding-left:.6rem;padding-right:.6rem}.md-tabs__item--active .md-tabs__link{color:inherit;opacity:1}.md-tabs__link{backface-visibility:hidden;display:flex;font-size:.7rem;margin-top:.8rem;opacity:.7;outline-color:var(--md-accent-fg-color);outline-offset:.2rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s}.md-tabs__link:focus,.md-tabs__link:hover{color:inherit;opacity:1}[dir=ltr] .md-tabs__link svg{margin-right:.4rem}[dir=rtl] .md-tabs__link svg{margin-left:.4rem}.md-tabs__link svg{fill:currentcolor;height:1.3em}.md-tabs__item:nth-child(2) .md-tabs__link{transition-delay:20ms}.md-tabs__item:nth-child(3) .md-tabs__link{transition-delay:40ms}.md-tabs__item:nth-child(4) .md-tabs__link{transition-delay:60ms}.md-tabs__item:nth-child(5) .md-tabs__link{transition-delay:80ms}.md-tabs__item:nth-child(6) .md-tabs__link{transition-delay:.1s}.md-tabs__item:nth-child(7) .md-tabs__link{transition-delay:.12s}.md-tabs__item:nth-child(8) .md-tabs__link{transition-delay:.14s}.md-tabs__item:nth-child(9) .md-tabs__link{transition-delay:.16s}.md-tabs__item:nth-child(10) .md-tabs__link{transition-delay:.18s}.md-tabs__item:nth-child(11) .md-tabs__link{transition-delay:.2s}.md-tabs__item:nth-child(12) .md-tabs__link{transition-delay:.22s}.md-tabs__item:nth-child(13) .md-tabs__link{transition-delay:.24s}.md-tabs__item:nth-child(14) .md-tabs__link{transition-delay:.26s}.md-tabs__item:nth-child(15) .md-tabs__link{transition-delay:.28s}.md-tabs__item:nth-child(16) .md-tabs__link{transition-delay:.3s}.md-tabs[hidden] .md-tabs__link{opacity:0;transform:translateY(50%);transition:transform 0ms .1s,opacity .1s}:root{--md-tag-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-tags:not([hidden]){display:inline-flex;flex-wrap:wrap;gap:.5em;margin-bottom:.75em;margin-top:-.125em}.md-typeset .md-tag{align-items:center;background:var(--md-default-fg-color--lightest);border-radius:2.4rem;display:inline-flex;font-size:.64rem;font-size:min(.8em,.64rem);font-weight:700;gap:.5em;letter-spacing:normal;line-height:1.6;padding:.3125em .78125em}.md-typeset .md-tag[href]{-webkit-tap-highlight-color:transparent;color:inherit;outline:none;transition:color 125ms,background-color 125ms}.md-typeset .md-tag[href]:focus,.md-typeset .md-tag[href]:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[id]>.md-typeset .md-tag{vertical-align:text-top}.md-typeset .md-tag-shadow{opacity:.5}.md-typeset .md-tag-icon:before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-tag-icon);mask-image:var(--md-tag-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset .md-tag-icon[href]:focus:before,.md-typeset .md-tag-icon[href]:hover:before{background-color:var(--md-accent-bg-color)}@keyframes pulse{0%{transform:scale(.95)}75%{transform:scale(1)}to{transform:scale(.95)}}:root{--md-annotation-bg-icon:url('data:image/svg+xml;charset=utf-8,');--md-annotation-icon:url('data:image/svg+xml;charset=utf-8,')}.md-tooltip{backface-visibility:hidden;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);font-family:var(--md-text-font-family);left:clamp(var(--md-tooltip-0,0rem) + .8rem,var(--md-tooltip-x),100vw + var(--md-tooltip-0,0rem) + .8rem - var(--md-tooltip-width) - 2 * .8rem);max-width:calc(100vw - 1.6rem);opacity:0;position:absolute;top:var(--md-tooltip-y);transform:translateY(-.4rem);transition:transform 0ms .25s,opacity .25s,z-index .25s;width:var(--md-tooltip-width);z-index:0}.md-tooltip--active{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,z-index 0ms;z-index:2}.md-tooltip--inline{font-weight:700;-webkit-user-select:none;user-select:none;width:auto}.md-tooltip--inline:not(.md-tooltip--active){transform:translateY(.2rem) scale(.9)}.md-tooltip--inline .md-tooltip__inner{font-size:.5rem;padding:.2rem .4rem}[hidden]+.md-tooltip--inline{display:none}.focus-visible>.md-tooltip,.md-tooltip:target{outline:var(--md-accent-fg-color) auto}.md-tooltip__inner{font-size:.64rem;padding:.8rem}.md-tooltip__inner.md-typeset>:first-child{margin-top:0}.md-tooltip__inner.md-typeset>:last-child{margin-bottom:0}.md-annotation{font-style:normal;font-weight:400;outline:none;text-align:initial;vertical-align:text-bottom;white-space:normal}[dir=rtl] .md-annotation{direction:rtl}code .md-annotation{font-family:var(--md-code-font-family);font-size:inherit}.md-annotation:not([hidden]){display:inline-block;line-height:1.25}.md-annotation__index{border-radius:.01px;cursor:pointer;display:inline-block;margin-left:.4ch;margin-right:.4ch;outline:none;overflow:hidden;position:relative;-webkit-user-select:none;user-select:none;vertical-align:text-top;z-index:0}.md-annotation .md-annotation__index{transition:z-index .25s}@media screen{.md-annotation__index{width:2.2ch}[data-md-visible]>.md-annotation__index{animation:pulse 2s infinite}.md-annotation__index:before{background:var(--md-default-bg-color);-webkit-mask-image:var(--md-annotation-bg-icon);mask-image:var(--md-annotation-bg-icon)}.md-annotation__index:after,.md-annotation__index:before{content:"";height:2.2ch;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:-.1ch;width:2.2ch;z-index:-1}.md-annotation__index:after{background-color:var(--md-default-fg-color--lighter);-webkit-mask-image:var(--md-annotation-icon);mask-image:var(--md-annotation-icon);transform:scale(1.0001);transition:background-color .25s,transform .25s}.md-tooltip--active+.md-annotation__index:after{transform:rotate(45deg)}.md-tooltip--active+.md-annotation__index:after,:hover>.md-annotation__index:after{background-color:var(--md-accent-fg-color)}}.md-tooltip--active+.md-annotation__index{animation-play-state:paused;transition-duration:0ms;z-index:2}.md-annotation__index [data-md-annotation-id]{display:inline-block}@media print{.md-annotation__index [data-md-annotation-id]{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);font-weight:700;padding:0 .6ch;white-space:nowrap}.md-annotation__index [data-md-annotation-id]:after{content:attr(data-md-annotation-id)}}.md-typeset .md-annotation-list{counter-reset:annotation;list-style:none!important}.md-typeset .md-annotation-list li{position:relative}[dir=ltr] .md-typeset .md-annotation-list li:before{left:-2.125em}[dir=rtl] .md-typeset .md-annotation-list li:before{right:-2.125em}.md-typeset .md-annotation-list li:before{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);content:counter(annotation);counter-increment:annotation;font-size:.8875em;font-weight:700;height:2ch;line-height:1.25;min-width:2ch;padding:0 .6ch;position:absolute;text-align:center;top:.25em}:root{--md-tooltip-width:20rem;--md-tooltip-tail:0.3rem}.md-tooltip2{backface-visibility:hidden;color:var(--md-default-fg-color);font-family:var(--md-text-font-family);opacity:0;pointer-events:none;position:absolute;top:calc(var(--md-tooltip-host-y) + var(--md-tooltip-y));transform:translateY(-.4rem);transform-origin:calc(var(--md-tooltip-host-x) + var(--md-tooltip-x)) 0;transition:transform 0ms .25s,opacity .25s,z-index .25s;width:100%;z-index:0}.md-tooltip2:before{border-left:var(--md-tooltip-tail) solid #0000;border-right:var(--md-tooltip-tail) solid #0000;content:"";display:block;left:clamp(1.5 * .8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-tail),100vw - 2 * var(--md-tooltip-tail) - 1.5 * .8rem);position:absolute;z-index:1}.md-tooltip2--top:before{border-top:var(--md-tooltip-tail) solid var(--md-default-bg-color);bottom:calc(var(--md-tooltip-tail)*-1 + .025rem);filter:drop-shadow(0 1px 0 hsla(0,0%,0%,.05))}.md-tooltip2--bottom:before{border-bottom:var(--md-tooltip-tail) solid var(--md-default-bg-color);filter:drop-shadow(0 -1px 0 hsla(0,0%,0%,.05));top:calc(var(--md-tooltip-tail)*-1 + .025rem)}.md-tooltip2[role=dialog]:after{content:"";display:block;height:.8rem;left:clamp(.8rem,var(--md-tooltip-host-x) - .8rem,100vw - var(--md-tooltip-width) - .8rem);pointer-events:auto;position:absolute;width:var(--md-tooltip-width);z-index:1}.md-tooltip2[role=dialog].md-tooltip2--top:after{top:100%}.md-tooltip2[role=dialog].md-tooltip2--bottom:after{bottom:100%}.md-tooltip2--active{opacity:1;transform:translateY(0);transition:transform .4s cubic-bezier(0,1,.5,1),opacity .25s,z-index 0ms;z-index:4}.md-tooltip2__inner{scrollbar-gutter:stable;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);left:clamp(.8rem,var(--md-tooltip-host-x) - .8rem,100vw - var(--md-tooltip-width) - .8rem);max-height:40vh;max-width:calc(100vw - 1.6rem);position:relative;scrollbar-width:thin}.md-tooltip2__inner::-webkit-scrollbar{height:.2rem;width:.2rem}.md-tooltip2__inner::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-tooltip2__inner::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}[role=dialog]>.md-tooltip2__inner{font-size:.64rem;overflow:auto;padding:0 .8rem;pointer-events:auto;width:var(--md-tooltip-width)}[role=dialog]>.md-tooltip2__inner:after,[role=dialog]>.md-tooltip2__inner:before{content:"";display:block;height:.8rem;position:sticky;width:100%;z-index:10}[role=dialog]>.md-tooltip2__inner:before{background:linear-gradient(var(--md-default-bg-color),#0000 75%);top:0}[role=dialog]>.md-tooltip2__inner:after{background:linear-gradient(#0000,var(--md-default-bg-color) 75%);bottom:0}[role=tooltip]>.md-tooltip2__inner{font-size:.5rem;font-weight:700;left:clamp(.8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-width)/2,100vw - var(--md-tooltip-width) - .8rem);max-width:min(100vw - 2 * .8rem,400px);padding:.2rem .4rem;-webkit-user-select:none;user-select:none;width:fit-content}.md-tooltip2__inner.md-typeset>:first-child{margin-top:0}.md-tooltip2__inner.md-typeset>:last-child{margin-bottom:0}[dir=ltr] .md-top{margin-left:50%}[dir=rtl] .md-top{margin-right:50%}.md-top{background-color:var(--md-default-bg-color);border-radius:1.6rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);cursor:pointer;display:block;font-size:.7rem;outline:none;padding:.4rem .8rem;position:fixed;top:3.2rem;transform:translate(-50%);transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms;z-index:2}@media print{.md-top{display:none}}[dir=rtl] .md-top{transform:translate(50%)}.md-top[hidden]{opacity:0;pointer-events:none;transform:translate(-50%,.2rem);transition-duration:0ms}[dir=rtl] .md-top[hidden]{transform:translate(50%,.2rem)}.md-top:focus,.md-top:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top svg{display:inline-block;vertical-align:-.5em}.md-top.lucide{fill:#0000;stroke:currentcolor}@keyframes hoverfix{0%{pointer-events:none}}:root{--md-version-icon:url('data:image/svg+xml;charset=utf-8,\3c !--! Font Awesome Free 7.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2026 Fonticons, Inc.-->')}.md-version{flex-shrink:0;font-size:.8rem;height:2.4rem}[dir=ltr] .md-version__current{margin-left:1.4rem;margin-right:.4rem}[dir=rtl] .md-version__current{margin-left:.4rem;margin-right:1.4rem}.md-version__current{color:inherit;cursor:pointer;outline:none;position:relative;top:.05rem}[dir=ltr] .md-version__current:after{margin-left:.4rem}[dir=rtl] .md-version__current:after{margin-right:.4rem}.md-version__current:after{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-image:var(--md-version-icon);mask-image:var(--md-version-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.4rem}.md-version__alias{margin-left:.3rem;opacity:.7}.md-version__list{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);list-style-type:none;margin:.2rem .8rem;max-height:0;opacity:0;overflow:auto;padding:0;position:absolute;scroll-snap-type:y mandatory;top:.15rem;transition:max-height 0ms .5s,opacity .25s .25s;z-index:3}.md-version:focus-within .md-version__list,.md-version:hover .md-version__list{max-height:10rem;opacity:1;transition:max-height 0ms,opacity .25s}@media (hover:none),(pointer:coarse){.md-version:hover .md-version__list{animation:hoverfix .25s forwards}.md-version:focus-within .md-version__list{animation:none}}.md-version__item{line-height:1.8rem}[dir=ltr] .md-version__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-version__link{padding-left:1.2rem;padding-right:.6rem}.md-version__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:color .25s,background-color .25s;white-space:nowrap;width:100%}.md-version__link:focus,.md-version__link:hover{color:var(--md-accent-fg-color)}.md-version__link:focus{background-color:var(--md-default-fg-color--lightest)}html.glightbox-open{height:100%;overflow:initial}html .gslide .gslide-description{background:var(--md-default-bg-color);-webkit-user-select:text;user-select:text}html .gslide .gslide-title{color:var(--md-default-fg-color);font-size:.8rem;margin-bottom:.4rem;margin-top:0}html .gslide .gslide-desc{color:var(--md-default-fg-color--light);font-size:.7rem}:root{--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .admonition,.md-typeset details{background-color:var(--md-admonition-bg-color);border:.075rem solid #448aff;border-radius:.2rem;box-shadow:var(--md-shadow-z1);color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .6rem;page-break-inside:avoid;transition:box-shadow 125ms}@media print{.md-typeset .admonition,.md-typeset details{box-shadow:none}}.md-typeset .admonition:focus-within,.md-typeset details:focus-within{box-shadow:0 0 0 .2rem #448aff1a}.md-typeset .admonition>*,.md-typeset details>*{box-sizing:border-box}.md-typeset .admonition .admonition,.md-typeset .admonition details,.md-typeset details .admonition,.md-typeset details details{margin-bottom:1em;margin-top:1em}.md-typeset .admonition .md-typeset__scrollwrap,.md-typeset details .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset .admonition .md-typeset__table,.md-typeset details .md-typeset__table{padding:0 .6rem}.md-typeset .admonition>.tabbed-set:only-child,.md-typeset details>.tabbed-set:only-child{margin-top:0}html .md-typeset .admonition>:last-child,html .md-typeset details>:last-child{margin-bottom:.6rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{padding-left:2rem;padding-right:.6rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{padding-left:.6rem;padding-right:2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-left-width:.2rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-right-width:.2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset .admonition-title,.md-typeset summary{background-color:#448aff1a;border:none;font-weight:700;margin:0 -.6rem;padding-bottom:.4rem;padding-top:.4rem;position:relative}html .md-typeset .admonition-title:last-child,html .md-typeset summary:last-child{margin-bottom:0}[dir=ltr] .md-typeset .admonition-title:before,[dir=ltr] .md-typeset summary:before{left:.6rem}[dir=rtl] .md-typeset .admonition-title:before,[dir=rtl] .md-typeset summary:before{right:.6rem}.md-typeset .admonition-title:before,.md-typeset summary:before{background-color:#448aff;content:"";height:1rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;width:1rem}.md-typeset .admonition-title code,.md-typeset summary code{box-shadow:0 0 0 .05rem var(--md-default-fg-color--lightest)}.md-typeset .admonition.note,.md-typeset details.note{border-color:#448aff}.md-typeset .admonition.note:focus-within,.md-typeset details.note:focus-within{box-shadow:0 0 0 .2rem #448aff1a}.md-typeset .note>.admonition-title,.md-typeset .note>summary{background-color:#448aff1a}.md-typeset .note>.admonition-title:before,.md-typeset .note>summary:before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note)}.md-typeset .note>.admonition-title:after,.md-typeset .note>summary:after{color:#448aff}.md-typeset .admonition.abstract,.md-typeset details.abstract{border-color:#00b0ff}.md-typeset .admonition.abstract:focus-within,.md-typeset details.abstract:focus-within{box-shadow:0 0 0 .2rem #00b0ff1a}.md-typeset .abstract>.admonition-title,.md-typeset .abstract>summary{background-color:#00b0ff1a}.md-typeset .abstract>.admonition-title:before,.md-typeset .abstract>summary:before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract)}.md-typeset .abstract>.admonition-title:after,.md-typeset .abstract>summary:after{color:#00b0ff}.md-typeset .admonition.info,.md-typeset details.info{border-color:#00b8d4}.md-typeset .admonition.info:focus-within,.md-typeset details.info:focus-within{box-shadow:0 0 0 .2rem #00b8d41a}.md-typeset .info>.admonition-title,.md-typeset .info>summary{background-color:#00b8d41a}.md-typeset .info>.admonition-title:before,.md-typeset .info>summary:before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info)}.md-typeset .info>.admonition-title:after,.md-typeset .info>summary:after{color:#00b8d4}.md-typeset .admonition.tip,.md-typeset details.tip{border-color:#00bfa5}.md-typeset .admonition.tip:focus-within,.md-typeset details.tip:focus-within{box-shadow:0 0 0 .2rem #00bfa51a}.md-typeset .tip>.admonition-title,.md-typeset .tip>summary{background-color:#00bfa51a}.md-typeset .tip>.admonition-title:before,.md-typeset .tip>summary:before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip)}.md-typeset .tip>.admonition-title:after,.md-typeset .tip>summary:after{color:#00bfa5}.md-typeset .admonition.success,.md-typeset details.success{border-color:#00c853}.md-typeset .admonition.success:focus-within,.md-typeset details.success:focus-within{box-shadow:0 0 0 .2rem #00c8531a}.md-typeset .success>.admonition-title,.md-typeset .success>summary{background-color:#00c8531a}.md-typeset .success>.admonition-title:before,.md-typeset .success>summary:before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success)}.md-typeset .success>.admonition-title:after,.md-typeset .success>summary:after{color:#00c853}.md-typeset .admonition.question,.md-typeset details.question{border-color:#64dd17}.md-typeset .admonition.question:focus-within,.md-typeset details.question:focus-within{box-shadow:0 0 0 .2rem #64dd171a}.md-typeset .question>.admonition-title,.md-typeset .question>summary{background-color:#64dd171a}.md-typeset .question>.admonition-title:before,.md-typeset .question>summary:before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question)}.md-typeset .question>.admonition-title:after,.md-typeset .question>summary:after{color:#64dd17}.md-typeset .admonition.warning,.md-typeset details.warning{border-color:#ff9100}.md-typeset .admonition.warning:focus-within,.md-typeset details.warning:focus-within{box-shadow:0 0 0 .2rem #ff91001a}.md-typeset .warning>.admonition-title,.md-typeset .warning>summary{background-color:#ff91001a}.md-typeset .warning>.admonition-title:before,.md-typeset .warning>summary:before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning)}.md-typeset .warning>.admonition-title:after,.md-typeset .warning>summary:after{color:#ff9100}.md-typeset .admonition.failure,.md-typeset details.failure{border-color:#ff5252}.md-typeset .admonition.failure:focus-within,.md-typeset details.failure:focus-within{box-shadow:0 0 0 .2rem #ff52521a}.md-typeset .failure>.admonition-title,.md-typeset .failure>summary{background-color:#ff52521a}.md-typeset .failure>.admonition-title:before,.md-typeset .failure>summary:before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure)}.md-typeset .failure>.admonition-title:after,.md-typeset .failure>summary:after{color:#ff5252}.md-typeset .admonition.danger,.md-typeset details.danger{border-color:#ff1744}.md-typeset .admonition.danger:focus-within,.md-typeset details.danger:focus-within{box-shadow:0 0 0 .2rem #ff17441a}.md-typeset .danger>.admonition-title,.md-typeset .danger>summary{background-color:#ff17441a}.md-typeset .danger>.admonition-title:before,.md-typeset .danger>summary:before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger)}.md-typeset .danger>.admonition-title:after,.md-typeset .danger>summary:after{color:#ff1744}.md-typeset .admonition.bug,.md-typeset details.bug{border-color:#f50057}.md-typeset .admonition.bug:focus-within,.md-typeset details.bug:focus-within{box-shadow:0 0 0 .2rem #f500571a}.md-typeset .bug>.admonition-title,.md-typeset .bug>summary{background-color:#f500571a}.md-typeset .bug>.admonition-title:before,.md-typeset .bug>summary:before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug)}.md-typeset .bug>.admonition-title:after,.md-typeset .bug>summary:after{color:#f50057}.md-typeset .admonition.example,.md-typeset details.example{border-color:#7c4dff}.md-typeset .admonition.example:focus-within,.md-typeset details.example:focus-within{box-shadow:0 0 0 .2rem #7c4dff1a}.md-typeset .example>.admonition-title,.md-typeset .example>summary{background-color:#7c4dff1a}.md-typeset .example>.admonition-title:before,.md-typeset .example>summary:before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example)}.md-typeset .example>.admonition-title:after,.md-typeset .example>summary:after{color:#7c4dff}.md-typeset .admonition.quote,.md-typeset details.quote{border-color:#9e9e9e}.md-typeset .admonition.quote:focus-within,.md-typeset details.quote:focus-within{box-shadow:0 0 0 .2rem #9e9e9e1a}.md-typeset .quote>.admonition-title,.md-typeset .quote>summary{background-color:#9e9e9e1a}.md-typeset .quote>.admonition-title:before,.md-typeset .quote>summary:before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote)}.md-typeset .quote>.admonition-title:after,.md-typeset .quote>summary:after{color:#9e9e9e}:root{--md-footnotes-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .footnote{color:var(--md-default-fg-color--light);font-size:.64rem}[dir=ltr] .md-typeset .footnote>ol{margin-left:0}[dir=rtl] .md-typeset .footnote>ol{margin-right:0}.md-typeset .footnote>ol>li{transition:color 125ms}.md-typeset .footnote>ol>li:target{color:var(--md-default-fg-color)}.md-typeset .footnote>ol>li:focus-within .footnote-backref{opacity:1;transform:translateX(0);transition:none}.md-typeset .footnote>ol>li:hover .footnote-backref,.md-typeset .footnote>ol>li:target .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li>:first-child{margin-top:0}.md-typeset .footnote-ref{font-size:.75em;font-weight:700}html .md-typeset .footnote-ref{outline-offset:.1rem}.md-typeset [id^="fnref:"]:target>.footnote-ref{outline:auto}.md-typeset .footnote-backref{color:var(--md-typeset-a-color);display:inline-block;font-size:0;opacity:0;transform:translateX(.25rem);transition:color .25s,transform .25s .25s,opacity 125ms .25s;vertical-align:text-bottom}@media print{.md-typeset .footnote-backref{color:var(--md-typeset-a-color);opacity:1;transform:translateX(0)}}[dir=rtl] .md-typeset .footnote-backref{transform:translateX(-.25rem)}.md-typeset .footnote-backref:hover{color:var(--md-accent-fg-color)}.md-typeset .footnote-backref:before{background-color:currentcolor;content:"";display:inline-block;height:.8rem;-webkit-mask-image:var(--md-footnotes-icon);mask-image:var(--md-footnotes-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.8rem}[dir=rtl] .md-typeset .footnote-backref:before{transform:scaleX(-1)}[dir=ltr] .md-typeset .headerlink{margin-left:.5rem}[dir=rtl] .md-typeset .headerlink{margin-right:.5rem}.md-typeset .headerlink{color:var(--md-default-fg-color--lighter);display:inline-block;opacity:0;transition:color .25s,opacity 125ms}@media print{.md-typeset .headerlink{display:none}}.md-typeset .headerlink:focus,.md-typeset :hover>.headerlink,.md-typeset :target>.headerlink{opacity:1;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset .headerlink:hover,.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset :target{--md-scroll-margin:3.6rem;--md-scroll-offset:0rem;scroll-margin-top:calc(var(--md-scroll-margin) - var(--md-scroll-offset))}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset :target{--md-scroll-margin:6rem}}.md-typeset h1:target,.md-typeset h2:target,.md-typeset h3:target{--md-scroll-offset:0.2rem}.md-typeset h4:target{--md-scroll-offset:0.15rem}.doc-contents td code{word-break:normal!important}.doc-md-description,.doc-md-description>p:first-child{display:inline}.md-typeset h5 .doc-object-name{text-transform:none}.doc .md-typeset__table,.doc .md-typeset__table table{display:table!important;width:100%}.doc .md-typeset__table tr{display:table-row}.doc-param-default,.doc-type_param-default{float:right}.doc-heading-parameter,.doc-heading-type_parameter{display:inline}.md-typeset .doc-heading-parameter{font-size:inherit}.doc-heading-parameter .headerlink,.doc-heading-type_parameter .headerlink{margin-left:0!important;margin-right:.2rem}.doc-section-title{font-weight:700}.doc-signature .autorefs{color:inherit;text-decoration-style:dotted}:host,:root,[data-md-color-scheme=default]{--doc-symbol-parameter-fg-color:#829bd1;--doc-symbol-type_parameter-fg-color:#829bd1;--doc-symbol-attribute-fg-color:#953800;--doc-symbol-function-fg-color:#8250df;--doc-symbol-method-fg-color:#8250df;--doc-symbol-class-fg-color:#0550ae;--doc-symbol-type_alias-fg-color:#0550ae;--doc-symbol-module-fg-color:#5cad0f;--doc-symbol-parameter-bg-color:#829bd11a;--doc-symbol-type_parameter-bg-color:#829bd11a;--doc-symbol-attribute-bg-color:#9538001a;--doc-symbol-function-bg-color:#8250df1a;--doc-symbol-method-bg-color:#8250df1a;--doc-symbol-class-bg-color:#0550ae1a;--doc-symbol-type_alias-bg-color:#0550ae1a;--doc-symbol-module-bg-color:#5cad0f1a}[data-md-color-scheme=slate]{--doc-symbol-parameter-fg-color:#829bd1;--doc-symbol-type_parameter-fg-color:#829bd1;--doc-symbol-attribute-fg-color:#ffa657;--doc-symbol-function-fg-color:#d2a8ff;--doc-symbol-method-fg-color:#d2a8ff;--doc-symbol-class-fg-color:#79c0ff;--doc-symbol-type_alias-fg-color:#79c0ff;--doc-symbol-module-fg-color:#baff79;--doc-symbol-parameter-bg-color:#829bd11a;--doc-symbol-type_parameter-bg-color:#829bd11a;--doc-symbol-attribute-bg-color:#ffa6571a;--doc-symbol-function-bg-color:#d2a8ff1a;--doc-symbol-method-bg-color:#d2a8ff1a;--doc-symbol-class-bg-color:#79c0ff1a;--doc-symbol-type_alias-bg-color:#79c0ff1a;--doc-symbol-module-bg-color:#baff791a}code.doc-symbol{border-radius:.1rem;font-size:.85em;font-weight:700;padding:0 .3em}a code.doc-symbol-parameter,code.doc-symbol-parameter{background-color:var(--doc-symbol-parameter-bg-color);color:var(--doc-symbol-parameter-fg-color)}code.doc-symbol-parameter:after{content:"param"}a code.doc-symbol-type_parameter,code.doc-symbol-type_parameter{background-color:var(--doc-symbol-type_parameter-bg-color);color:var(--doc-symbol-type_parameter-fg-color)}code.doc-symbol-type_parameter:after{content:"type-param"}a code.doc-symbol-attribute,code.doc-symbol-attribute{background-color:var(--doc-symbol-attribute-bg-color);color:var(--doc-symbol-attribute-fg-color)}code.doc-symbol-attribute:after{content:"attr"}a code.doc-symbol-function,code.doc-symbol-function{background-color:var(--doc-symbol-function-bg-color);color:var(--doc-symbol-function-fg-color)}code.doc-symbol-function:after{content:"func"}a code.doc-symbol-method,code.doc-symbol-method{background-color:var(--doc-symbol-method-bg-color);color:var(--doc-symbol-method-fg-color)}code.doc-symbol-method:after{content:"meth"}a code.doc-symbol-class,code.doc-symbol-class{background-color:var(--doc-symbol-class-bg-color);color:var(--doc-symbol-class-fg-color)}code.doc-symbol-class:after{content:"class"}a code.doc-symbol-type_alias,code.doc-symbol-type_alias{background-color:var(--doc-symbol-type_alias-bg-color);color:var(--doc-symbol-type_alias-fg-color)}code.doc-symbol-type_alias:after{content:"type"}a code.doc-symbol-module,code.doc-symbol-module{background-color:var(--doc-symbol-module-bg-color);color:var(--doc-symbol-module-fg-color)}code.doc-symbol-module:after{content:"mod"}:root{--md-admonition-icon--mkdocstrings-source:url('data:image/svg+xml;charset=utf-8,') }.md-typeset .admonition.mkdocstrings-source,.md-typeset details.mkdocstrings-source{border:none;padding:0}.md-typeset .admonition.mkdocstrings-source:focus-within,.md-typeset details.mkdocstrings-source:focus-within{box-shadow:none}.md-typeset .mkdocstrings-source>.admonition-title,.md-typeset .mkdocstrings-source>summary{background-color:inherit}.md-typeset .mkdocstrings-source>.admonition-title:before,.md-typeset .mkdocstrings-source>summary:before{background-color:var(--md-default-fg-color);-webkit-mask-image:var(--md-admonition-icon--mkdocstrings-source);mask-image:var(--md-admonition-icon--mkdocstrings-source)}.md-typeset div.arithmatex{overflow:auto}@media screen and (max-width:44.984375em){.md-typeset div.arithmatex{margin:0 -.8rem}.md-typeset div.arithmatex>*{width:min-content}}.md-typeset div.arithmatex>*{margin-left:auto!important;margin-right:auto!important;padding:0 .8rem;touch-action:auto}.md-typeset div.arithmatex>* mjx-container{margin:0!important}.md-typeset div.arithmatex mjx-assistive-mml{height:0}.md-typeset del.critic{background-color:var(--md-typeset-del-color)}.md-typeset del.critic,.md-typeset ins.critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset ins.critic{background-color:var(--md-typeset-ins-color)}.md-typeset .critic.comment{-webkit-box-decoration-break:clone;box-decoration-break:clone;color:var(--md-code-hl-comment-color)}.md-typeset .critic.comment:before{content:"/* "}.md-typeset .critic.comment:after{content:" */"}.md-typeset .critic.block{box-shadow:none;display:block;margin:1em 0;overflow:auto;padding-left:.8rem;padding-right:.8rem}.md-typeset .critic.block>:first-child{margin-top:.5em}.md-typeset .critic.block>:last-child{margin-bottom:.5em}:root{--md-details-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset details{display:flow-root;overflow:visible;padding-top:0}.md-typeset details[open]>summary:after{transform:rotate(90deg)}.md-typeset details:not([open]){box-shadow:none;padding-bottom:0}.md-typeset details:not([open])>summary{border-radius:.1rem}[dir=ltr] .md-typeset summary{padding-right:1.8rem}[dir=rtl] .md-typeset summary{padding-left:1.8rem}[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset summary{cursor:pointer;display:block;min-height:1rem;overflow:hidden}.md-typeset summary.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset summary:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[dir=ltr] .md-typeset summary:after{right:.4rem}[dir=rtl] .md-typeset summary:after{left:.4rem}.md-typeset summary:after{background-color:currentcolor;content:"";height:1rem;-webkit-mask-image:var(--md-details-icon);mask-image:var(--md-details-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;transform:rotate(0deg);transition:transform .25s;width:1rem}[dir=rtl] .md-typeset summary:after{transform:rotate(180deg)}.md-typeset summary::marker{display:none}.md-typeset summary::-webkit-details-marker{display:none}.md-typeset .emojione,.md-typeset .gemoji,.md-typeset .twemoji{--md-icon-size:1.125em;display:inline-flex;height:var(--md-icon-size);vertical-align:text-top}.md-typeset .emojione svg,.md-typeset .gemoji svg,.md-typeset .twemoji svg{fill:currentcolor;max-height:100%;width:var(--md-icon-size)}.md-typeset .emojione svg.lucide,.md-typeset .gemoji svg.lucide,.md-typeset .twemoji svg.lucide{fill:#0000;stroke:currentcolor}.md-typeset .lg,.md-typeset .xl,.md-typeset .xxl,.md-typeset .xxxl{vertical-align:text-bottom}.md-typeset .middle{vertical-align:middle}.md-typeset .lg{--md-icon-size:1.5em}.md-typeset .xl{--md-icon-size:2.25em}.md-typeset .xxl{--md-icon-size:3em}.md-typeset .xxxl{--md-icon-size:4em}.highlight .o,.highlight .ow{color:var(--md-code-hl-operator-color)}.highlight .p{color:var(--md-code-hl-punctuation-color)}.highlight .cpf,.highlight .l,.highlight .s,.highlight .s1,.highlight .s2,.highlight .sb,.highlight .sc,.highlight .si,.highlight .ss{color:var(--md-code-hl-string-color)}.highlight .cp,.highlight .se,.highlight .sh,.highlight .sr,.highlight .sx{color:var(--md-code-hl-special-color)}.highlight .il,.highlight .m,.highlight .mb,.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:var(--md-code-hl-number-color)}.highlight .k,.highlight .kd,.highlight .kn,.highlight .kp,.highlight .kr,.highlight .kt{color:var(--md-code-hl-keyword-color)}.highlight .kc,.highlight .n{color:var(--md-code-hl-name-color)}.highlight .bp,.highlight .nb,.highlight .no{color:var(--md-code-hl-constant-color)}.highlight .nc,.highlight .ne,.highlight .nf,.highlight .nn{color:var(--md-code-hl-function-color)}.highlight .nd,.highlight .ni,.highlight .nl,.highlight .nt{color:var(--md-code-hl-keyword-color)}.highlight .c,.highlight .c1,.highlight .ch,.highlight .cm,.highlight .cs,.highlight .sd{color:var(--md-code-hl-comment-color)}.highlight .na,.highlight .nv,.highlight .vc,.highlight .vg,.highlight .vi{color:var(--md-code-hl-variable-color)}.highlight .ge,.highlight .gh,.highlight .go,.highlight .gp,.highlight .gr,.highlight .gs,.highlight .gt,.highlight .gu{color:var(--md-code-hl-generic-color)}.highlight .gd,.highlight .gi{border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight .gd{background-color:var(--md-typeset-del-color)}.highlight .gi{background-color:var(--md-typeset-ins-color)}.highlight .hll{background-color:var(--md-code-hl-color--light);box-shadow:2px 0 0 0 var(--md-code-hl-color) inset;display:block;margin:0 -1.1764705882em;padding:0 1.1764705882em}.highlight span.filename{background-color:var(--md-code-bg-color);border-bottom:.05rem solid var(--md-default-fg-color--lightest);border-top-left-radius:.1rem;border-top-right-radius:.1rem;display:flow-root;font-size:.85em;font-weight:700;margin-top:1em;padding:.6617647059em 1.1764705882em;position:relative}.highlight span.filename+pre{margin-top:0}.highlight span.filename+pre>code{border-top-left-radius:0;border-top-right-radius:0}.highlight [data-linenos]:before{background-color:var(--md-code-bg-color);box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;color:var(--md-default-fg-color--light);content:attr(data-linenos);float:left;left:-1.1764705882em;margin-left:-1.1764705882em;margin-right:1.1764705882em;padding-left:1.1764705882em;position:sticky;-webkit-user-select:none;user-select:none;z-index:3}.highlight code>span[id^=__span]>:last-child .md-annotation{margin-right:2.4rem}.highlight code[data-md-copying]{display:initial}.highlight code[data-md-copying] .hll{display:contents}.highlight code[data-md-copying] .md-annotation{display:none}.highlighttable{display:flow-root}.highlighttable tbody,.highlighttable td{display:block;padding:0}.highlighttable tr{display:flex}.highlighttable pre{margin:0}.highlighttable th.filename{flex-grow:1;padding:0;text-align:left}.highlighttable th.filename span.filename{margin-top:0}.highlighttable .linenos{background-color:var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-top-left-radius:.1rem;font-size:.85em;padding:.7720588235em 0 .7720588235em 1.1764705882em;-webkit-user-select:none;user-select:none}.highlighttable .linenodiv{box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset}.highlighttable .linenodiv pre{color:var(--md-default-fg-color--light);text-align:right}.highlighttable .linenodiv span[class]{padding-right:.5882352941em}.highlighttable .code{flex:1;min-width:0}.linenodiv a{color:inherit}.md-typeset .highlighttable{direction:ltr;margin:1em 0}.md-typeset .highlighttable>tbody>tr>.code>div>pre>code{border-bottom-left-radius:0;border-top-left-radius:0}.md-typeset .highlight+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset .highlight+.result:after{clear:both;content:"";display:block}@media screen and (max-width:44.984375em){.md-content__inner>.highlight{margin:1em -.8rem}.md-content__inner>.highlight>.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.code>div>pre>code,.md-content__inner>.highlight>.highlighttable>tbody>tr>.filename span.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.linenos,.md-content__inner>.highlight>pre>code{border-radius:0}.md-content__inner>.highlight+.result{border-left-width:0;border-radius:0;border-right-width:0;margin-left:-.8rem;margin-right:-.8rem}}.md-typeset .keys kbd:after,.md-typeset .keys kbd:before{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys span{color:var(--md-default-fg-color--light);padding:0 .2em}.md-typeset .keys .key-alt:before,.md-typeset .keys .key-left-alt:before,.md-typeset .keys .key-right-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-command:before,.md-typeset .keys .key-left-command:before,.md-typeset .keys .key-right-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-control:before,.md-typeset .keys .key-left-control:before,.md-typeset .keys .key-right-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-left-meta:before,.md-typeset .keys .key-meta:before,.md-typeset .keys .key-right-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-left-option:before,.md-typeset .keys .key-option:before,.md-typeset .keys .key-right-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-left-shift:before,.md-typeset .keys .key-right-shift:before,.md-typeset .keys .key-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-left-super:before,.md-typeset .keys .key-right-super:before,.md-typeset .keys .key-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-left-windows:before,.md-typeset .keys .key-right-windows:before,.md-typeset .keys .key-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-arrow-down:before{content:"↓";padding-right:.4em}.md-typeset .keys .key-arrow-left:before{content:"←";padding-right:.4em}.md-typeset .keys .key-arrow-right:before{content:"→";padding-right:.4em}.md-typeset .keys .key-arrow-up:before{content:"↑";padding-right:.4em}.md-typeset .keys .key-backspace:before{content:"⌫";padding-right:.4em}.md-typeset .keys .key-backtab:before{content:"⇤";padding-right:.4em}.md-typeset .keys .key-caps-lock:before{content:"⇪";padding-right:.4em}.md-typeset .keys .key-clear:before{content:"⌧";padding-right:.4em}.md-typeset .keys .key-context-menu:before{content:"☰";padding-right:.4em}.md-typeset .keys .key-delete:before{content:"⌦";padding-right:.4em}.md-typeset .keys .key-eject:before{content:"⏏";padding-right:.4em}.md-typeset .keys .key-end:before{content:"⤓";padding-right:.4em}.md-typeset .keys .key-escape:before{content:"⎋";padding-right:.4em}.md-typeset .keys .key-home:before{content:"⤒";padding-right:.4em}.md-typeset .keys .key-insert:before{content:"⎀";padding-right:.4em}.md-typeset .keys .key-page-down:before{content:"⇟";padding-right:.4em}.md-typeset .keys .key-page-up:before{content:"⇞";padding-right:.4em}.md-typeset .keys .key-print-screen:before{content:"⎙";padding-right:.4em}.md-typeset .keys .key-tab:after{content:"⇥";padding-left:.4em}.md-typeset .keys .key-num-enter:after{content:"⌤";padding-left:.4em}.md-typeset .keys .key-enter:after{content:"⏎";padding-left:.4em}:root{--md-tabbed-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-tabbed-icon--next:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .tabbed-set{border-radius:.1rem;display:flex;flex-flow:column wrap;margin:1em 0;position:relative}.md-typeset .tabbed-set>input{height:0;opacity:0;position:absolute;width:0}.md-typeset .tabbed-set>input:target{--md-scroll-offset:0.625em}.md-typeset .tabbed-set>input.focus-visible~.tabbed-labels:before{background-color:var(--md-accent-fg-color)}.md-typeset .tabbed-labels{-ms-overflow-style:none;box-shadow:0 -.05rem var(--md-default-fg-color--lightest) inset;display:flex;max-width:100%;overflow:auto;scrollbar-width:none}@media print{.md-typeset .tabbed-labels{display:contents}}@media screen{.js .md-typeset .tabbed-labels{position:relative}.js .md-typeset .tabbed-labels:before{background:var(--md-default-fg-color);bottom:0;content:"";display:block;height:2px;left:0;position:absolute;transform:translateX(var(--md-indicator-x));transition:width 225ms,background-color .25s,transform .25s;transition-timing-function:cubic-bezier(.4,0,.2,1);width:var(--md-indicator-width)}}.md-typeset .tabbed-labels::-webkit-scrollbar{display:none}.md-typeset .tabbed-labels>label{border-bottom:.1rem solid #0000;border-radius:.1rem .1rem 0 0;color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;font-size:.64rem;font-weight:700;padding:.78125em 1.25em .625em;scroll-margin-inline-start:1rem;transition:background-color .25s,color .25s;white-space:nowrap;width:auto}@media print{.md-typeset .tabbed-labels>label:first-child{order:1}.md-typeset .tabbed-labels>label:nth-child(2){order:2}.md-typeset .tabbed-labels>label:nth-child(3){order:3}.md-typeset .tabbed-labels>label:nth-child(4){order:4}.md-typeset .tabbed-labels>label:nth-child(5){order:5}.md-typeset .tabbed-labels>label:nth-child(6){order:6}.md-typeset .tabbed-labels>label:nth-child(7){order:7}.md-typeset .tabbed-labels>label:nth-child(8){order:8}.md-typeset .tabbed-labels>label:nth-child(9){order:9}.md-typeset .tabbed-labels>label:nth-child(10){order:10}.md-typeset .tabbed-labels>label:nth-child(11){order:11}.md-typeset .tabbed-labels>label:nth-child(12){order:12}.md-typeset .tabbed-labels>label:nth-child(13){order:13}.md-typeset .tabbed-labels>label:nth-child(14){order:14}.md-typeset .tabbed-labels>label:nth-child(15){order:15}.md-typeset .tabbed-labels>label:nth-child(16){order:16}.md-typeset .tabbed-labels>label:nth-child(17){order:17}.md-typeset .tabbed-labels>label:nth-child(18){order:18}.md-typeset .tabbed-labels>label:nth-child(19){order:19}.md-typeset .tabbed-labels>label:nth-child(20){order:20}}.md-typeset .tabbed-labels>label:hover{color:var(--md-default-fg-color)}.md-typeset .tabbed-labels>label>[href]:first-child{color:inherit}.md-typeset .tabbed-labels--linked>label{padding:0}.md-typeset .tabbed-labels--linked>label>a{display:block;padding:.78125em 1.25em .625em}.md-typeset .tabbed-content{width:100%}@media print{.md-typeset .tabbed-content{display:contents}}.md-typeset .tabbed-block{display:none}@media print{.md-typeset .tabbed-block{display:block}.md-typeset .tabbed-block:first-child{order:1}.md-typeset .tabbed-block:nth-child(2){order:2}.md-typeset .tabbed-block:nth-child(3){order:3}.md-typeset .tabbed-block:nth-child(4){order:4}.md-typeset .tabbed-block:nth-child(5){order:5}.md-typeset .tabbed-block:nth-child(6){order:6}.md-typeset .tabbed-block:nth-child(7){order:7}.md-typeset .tabbed-block:nth-child(8){order:8}.md-typeset .tabbed-block:nth-child(9){order:9}.md-typeset .tabbed-block:nth-child(10){order:10}.md-typeset .tabbed-block:nth-child(11){order:11}.md-typeset .tabbed-block:nth-child(12){order:12}.md-typeset .tabbed-block:nth-child(13){order:13}.md-typeset .tabbed-block:nth-child(14){order:14}.md-typeset .tabbed-block:nth-child(15){order:15}.md-typeset .tabbed-block:nth-child(16){order:16}.md-typeset .tabbed-block:nth-child(17){order:17}.md-typeset .tabbed-block:nth-child(18){order:18}.md-typeset .tabbed-block:nth-child(19){order:19}.md-typeset .tabbed-block:nth-child(20){order:20}}.md-typeset .tabbed-block>.highlight:first-child>pre,.md-typeset .tabbed-block>pre:first-child{margin:0}.md-typeset .tabbed-block>.highlight:first-child>pre>code,.md-typeset .tabbed-block>pre:first-child>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child>.filename{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable{margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.filename span.filename,.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.linenos{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.code>div>pre>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child+.result{margin-top:-.125em}.md-typeset .tabbed-block>.tabbed-set{margin:0}.md-typeset .tabbed-button{align-self:center;border-radius:100%;color:var(--md-default-fg-color--light);cursor:pointer;display:block;height:.9rem;margin-top:.1rem;pointer-events:auto;transition:background-color .25s;width:.9rem}.md-typeset .tabbed-button:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset .tabbed-button:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-tabbed-icon--prev);mask-image:var(--md-tabbed-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color .25s,transform .25s;width:100%}.md-typeset .tabbed-control{background:linear-gradient(to right,var(--md-default-bg-color) 60%,#0000);display:flex;height:1.9rem;justify-content:start;pointer-events:none;position:absolute;transition:opacity 125ms;width:1.2rem}[dir=rtl] .md-typeset .tabbed-control{transform:rotate(180deg)}.md-typeset .tabbed-control[hidden]{opacity:0}.md-typeset .tabbed-control--next{background:linear-gradient(to left,var(--md-default-bg-color) 60%,#0000);justify-content:end;right:0}.md-typeset .tabbed-control--next .tabbed-button:after{-webkit-mask-image:var(--md-tabbed-icon--next);mask-image:var(--md-tabbed-icon--next)}@media screen and (max-width:44.984375em){[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels{margin:0 -.8rem;max-width:100vw;scroll-padding-inline-start:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels:after{content:""}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-right:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-left:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-right:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{width:2rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-left:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-right:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-left:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{width:2rem}}@media screen{.md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){color:var(--md-default-fg-color)}.md-typeset .no-js .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .no-js .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .no-js .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .no-js .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .no-js .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .no-js .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .no-js .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .no-js .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .no-js .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .no-js .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .no-js .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .no-js .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .no-js .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .no-js .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .no-js .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .no-js .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .no-js .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .no-js .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .no-js .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .no-js .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.md-typeset [role=dialog] .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset [role=dialog] .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset [role=dialog] .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset [role=dialog] .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset [role=dialog] .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset [role=dialog] .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset [role=dialog] .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset [role=dialog] .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset [role=dialog] .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset [role=dialog] .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset [role=dialog] .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset [role=dialog] .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset [role=dialog] .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset [role=dialog] .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset [role=dialog] .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset [role=dialog] .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset [role=dialog] .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset [role=dialog] .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset [role=dialog] .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset [role=dialog] .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.no-js .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.no-js .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.no-js .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.no-js .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.no-js .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.no-js .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.no-js .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.no-js .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.no-js .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.no-js .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.no-js .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.no-js .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.no-js .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.no-js .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.no-js .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.no-js .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.no-js .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.no-js .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.no-js .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.no-js .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),[role=dialog] .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,[role=dialog] .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),[role=dialog] .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),[role=dialog] .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),[role=dialog] .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),[role=dialog] .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),[role=dialog] .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),[role=dialog] .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),[role=dialog] .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),[role=dialog] .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),[role=dialog] .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),[role=dialog] .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),[role=dialog] .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),[role=dialog] .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),[role=dialog] .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),[role=dialog] .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),[role=dialog] .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),[role=dialog] .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),[role=dialog] .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),[role=dialog] .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){border-color:var(--md-default-fg-color)}}.md-typeset .tabbed-set>input:first-child.focus-visible~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10).focus-visible~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11).focus-visible~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12).focus-visible~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13).focus-visible~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14).focus-visible~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15).focus-visible~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16).focus-visible~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17).focus-visible~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18).focus-visible~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19).focus-visible~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2).focus-visible~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20).focus-visible~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3).focus-visible~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4).focus-visible~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5).focus-visible~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6).focus-visible~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7).focus-visible~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8).focus-visible~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9).focus-visible~.tabbed-labels>:nth-child(9){color:var(--md-accent-fg-color)}.md-typeset .tabbed-set>input:first-child:checked~.tabbed-content>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-content>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-content>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-content>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-content>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-content>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-content>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-content>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-content>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-content>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-content>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-content>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-content>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-content>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-content>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-content>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-content>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-content>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-content>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-content>:nth-child(9){display:block}:root{--md-tasklist-icon:url('data:image/svg+xml;charset=utf-8,');--md-tasklist-icon--checked:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .task-list-item{list-style-type:none;position:relative}[dir=ltr] .md-typeset .task-list-item [type=checkbox]{left:-2em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{right:-2em}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}[dir=ltr] .md-typeset .task-list-indicator:before{left:-1.5em}[dir=rtl] .md-typeset .task-list-indicator:before{right:-1.5em}.md-typeset .task-list-indicator:before{background-color:var(--md-default-fg-color--lightest);content:"";height:1.25em;-webkit-mask-image:var(--md-tasklist-icon);mask-image:var(--md-tasklist-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.15em;width:1.25em}.md-typeset [type=checkbox]:checked+.task-list-indicator:before{background-color:#00e676;-webkit-mask-image:var(--md-tasklist-icon--checked);mask-image:var(--md-tasklist-icon--checked)}@media print{.giscus,[id=__comments]{display:none}}:root>*{--md-mermaid-font-family:var(--md-text-font-family),sans-serif;--md-mermaid-edge-color:var(--md-code-fg-color);--md-mermaid-node-bg-color:var(--md-accent-fg-color--transparent);--md-mermaid-node-fg-color:var(--md-accent-fg-color);--md-mermaid-label-bg-color:var(--md-default-bg-color);--md-mermaid-label-fg-color:var(--md-code-fg-color);--md-mermaid-sequence-actor-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actor-fg-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-actor-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-actor-line-color:var(--md-default-fg-color--lighter);--md-mermaid-sequence-actorman-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actorman-line-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-box-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-box-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-label-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-label-fg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-loop-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-loop-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-loop-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-message-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-message-line-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-note-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-border-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-number-bg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-number-fg-color:var(--md-accent-bg-color)}.mermaid{line-height:normal;margin:1em 0}.md-typeset .grid{grid-gap:.4rem;display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,16rem),1fr));margin:1em 0}.md-typeset .grid.cards>ol,.md-typeset .grid.cards>ul{display:contents}.md-typeset .grid.cards>ol>li,.md-typeset .grid.cards>ul>li,.md-typeset .grid>.card{border:.05rem solid var(--md-default-fg-color--lightest);border-radius:.1rem;display:block;margin:0;padding:.8rem;transition:border .25s,box-shadow .25s}.md-typeset .grid.cards>ol>li:focus-within,.md-typeset .grid.cards>ol>li:hover,.md-typeset .grid.cards>ul>li:focus-within,.md-typeset .grid.cards>ul>li:hover,.md-typeset .grid>.card:focus-within,.md-typeset .grid>.card:hover{border-color:#0000;box-shadow:var(--md-shadow-z2)}.md-typeset .grid.cards>ol>li>hr,.md-typeset .grid.cards>ul>li>hr,.md-typeset .grid>.card>hr{margin-bottom:1em;margin-top:1em}.md-typeset .grid.cards>ol>li>:first-child,.md-typeset .grid.cards>ul>li>:first-child,.md-typeset .grid>.card>:first-child{margin-top:0}.md-typeset .grid.cards>ol>li>:last-child,.md-typeset .grid.cards>ul>li>:last-child,.md-typeset .grid>.card>:last-child{margin-bottom:0}.md-typeset .grid>*,.md-typeset .grid>.admonition,.md-typeset .grid>.highlight>*,.md-typeset .grid>.highlighttable,.md-typeset .grid>.md-typeset details,.md-typeset .grid>details,.md-typeset .grid>pre{margin-bottom:0;margin-top:0}.md-typeset .grid>.highlight>pre:only-child,.md-typeset .grid>.highlight>pre>code,.md-typeset .grid>.highlighttable,.md-typeset .grid>.highlighttable>tbody,.md-typeset .grid>.highlighttable>tbody>tr,.md-typeset .grid>.highlighttable>tbody>tr>.code,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre>code{height:100%}.md-typeset .grid>.tabbed-set{margin-bottom:0;margin-top:0}@media screen and (min-width:45em){[dir=ltr] .md-typeset .inline{float:left}[dir=rtl] .md-typeset .inline{float:right}[dir=ltr] .md-typeset .inline{margin-right:.8rem}[dir=rtl] .md-typeset .inline{margin-left:.8rem}.md-typeset .inline{margin-bottom:.8rem;margin-top:0;width:11.7rem}[dir=ltr] .md-typeset .inline.end{float:right}[dir=rtl] .md-typeset .inline.end{float:left}[dir=ltr] .md-typeset .inline.end{margin-left:.8rem;margin-right:0}[dir=rtl] .md-typeset .inline.end{margin-left:0;margin-right:.8rem}} \ No newline at end of file +@charset "UTF-8";html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;box-sizing:border-box}*,:after,:before{box-sizing:inherit}@media (prefers-reduced-motion){*,:after,:before{transition:none!important}}body{margin:0}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}hr{border:0;box-sizing:initial;display:block;height:.05rem;overflow:visible;padding:0}small{font-size:80%}sub,sup{line-height:1em}img{border-style:none}table{border-collapse:initial;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{background:#0000;border:0;font-family:inherit;font-size:inherit;margin:0;padding:0}input{border:0;outline:none}:root{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3;--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:#526cfe1a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-scheme=default]{color-scheme:light}[data-md-color-scheme=default] img[src$="#gh-dark-mode-only"],[data-md-color-scheme=default] img[src$="#only-dark"]{display:none}:root,[data-md-color-scheme=default]{--md-hue:225deg;--md-default-fg-color:#000000de;--md-default-fg-color--light:#0000008a;--md-default-fg-color--lighter:#00000052;--md-default-fg-color--lightest:#00000012;--md-default-bg-color:#fff;--md-default-bg-color--light:#ffffffb3;--md-default-bg-color--lighter:#ffffff4d;--md-default-bg-color--lightest:#ffffff1f;--md-code-fg-color:#36464e;--md-code-bg-color:#f5f5f5;--md-code-bg-color--light:#f5f5f5b3;--md-code-bg-color--lighter:#f5f5f54d;--md-code-hl-color:#4287ff;--md-code-hl-color--light:#4287ff1a;--md-code-hl-number-color:#d52a2a;--md-code-hl-special-color:#db1457;--md-code-hl-function-color:#a846b9;--md-code-hl-constant-color:#6e59d9;--md-code-hl-keyword-color:#3f6ec6;--md-code-hl-string-color:#1c7d4d;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-del-color:#f5503d26;--md-typeset-ins-color:#0bd57026;--md-typeset-kbd-color:#fafafa;--md-typeset-kbd-accent-color:#fff;--md-typeset-kbd-border-color:#b8b8b8;--md-typeset-mark-color:#ffff0080;--md-typeset-table-color:#0000001f;--md-typeset-table-color--light:rgba(0,0,0,.035);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-warning-fg-color:#000000de;--md-warning-bg-color:#ff9;--md-footer-fg-color:#fff;--md-footer-fg-color--light:#ffffffb3;--md-footer-fg-color--lighter:#ffffff73;--md-footer-bg-color:#000000de;--md-footer-bg-color--dark:#00000052;--md-shadow-z1:0 0.2rem 0.5rem #0000000d,0 0 0.05rem #0000001a;--md-shadow-z2:0 0.2rem 0.5rem #0000001a,0 0 0.05rem #00000040;--md-shadow-z3:0 0.2rem 0.5rem #0003,0 0 0.05rem #00000059;--color-foreground:0 0 0;--color-background:255 255 255;--color-background-subtle:240 240 240;--color-backdrop:255 255 255}.md-icon svg{fill:currentcolor;display:block;height:1.2rem;width:1.2rem}.md-icon svg.lucide{fill:#0000;stroke:currentcolor}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--md-text-font-family:var(--md-text-font,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif;--md-code-font-family:var(--md-code-font,_),SFMono-Regular,Consolas,Menlo,monospace}aside,body,input{font-feature-settings:"kern","liga";color:var(--md-typeset-color);font-family:var(--md-text-font-family)}code,kbd,pre{font-feature-settings:"kern";font-family:var(--md-code-font-family)}:root{--md-typeset-table-sort-icon:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--asc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--desc:url('data:image/svg+xml;charset=utf-8,')}.md-typeset{-webkit-print-color-adjust:exact;color-adjust:exact;font-size:.8rem;line-height:1.6;overflow-wrap:break-word}@media print{.md-typeset{font-size:.68rem}}.md-typeset blockquote,.md-typeset dl,.md-typeset figure,.md-typeset ol,.md-typeset pre,.md-typeset ul{margin-bottom:1em;margin-top:1em}.md-typeset h1{color:var(--md-default-fg-color--light);font-size:2em;line-height:1.3;margin:0 0 1.25em}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{font-size:1.5625em;line-height:1.4;margin:1.6em 0 .64em}.md-typeset h3{font-size:1.25em;font-weight:400;letter-spacing:-.01em;line-height:1.5;margin:1.6em 0 .8em}.md-typeset h2+h3{margin-top:.8em}.md-typeset h4{font-weight:700;letter-spacing:-.01em;margin:1em 0}.md-typeset h5,.md-typeset h6{color:var(--md-default-fg-color--light);font-size:.8em;font-weight:700;letter-spacing:-.01em;margin:1.25em 0}.md-typeset h5{text-transform:uppercase}.md-typeset h5 code{text-transform:none}.md-typeset hr{border-bottom:.05rem solid var(--md-default-fg-color--lightest);display:flow-root;margin:1.5em 0}.md-typeset a{color:var(--md-typeset-a-color);word-break:break-word}.md-typeset a,.md-typeset a:before{transition:color 125ms}.md-typeset a:focus,.md-typeset a:hover{color:var(--md-accent-fg-color)}.md-typeset a:focus code,.md-typeset a:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset a code{color:var(--md-typeset-a-color)}.md-typeset a.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset code,.md-typeset kbd,.md-typeset pre{color:var(--md-code-fg-color);direction:ltr;font-variant-ligatures:none;transition:background-color 125ms}@media print{.md-typeset code,.md-typeset kbd,.md-typeset pre{white-space:pre-wrap}}.md-typeset code{background-color:var(--md-code-bg-color);border-radius:.1rem;-webkit-box-decoration-break:clone;box-decoration-break:clone;font-size:.85em;padding:0 .2941176471em;transition:color 125ms,background-color 125ms;word-break:break-word}.md-typeset code:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset pre{display:flow-root;line-height:1.4;position:relative}.md-typeset pre>code{-webkit-box-decoration-break:slice;box-decoration-break:slice;box-shadow:none;display:block;margin:0;outline-color:var(--md-accent-fg-color);overflow:auto;padding:.7720588235em 1.1764705882em;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin;touch-action:auto;word-break:normal}.md-typeset pre>code:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-typeset pre>code::-webkit-scrollbar{height:.2rem;width:.2rem}.md-typeset pre>code::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset pre>code::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}.md-typeset kbd{background-color:var(--md-typeset-kbd-color);border-radius:.1rem;box-shadow:0 .1rem 0 .05rem var(--md-typeset-kbd-border-color),0 .1rem 0 var(--md-typeset-kbd-border-color),0 -.1rem .2rem var(--md-typeset-kbd-accent-color) inset;color:var(--md-default-fg-color);display:inline-block;font-size:.75em;padding:0 .6666666667em;vertical-align:text-top;word-break:break-word}.md-typeset mark{background-color:var(--md-typeset-mark-color);-webkit-box-decoration-break:clone;box-decoration-break:clone;color:inherit;word-break:break-word}.md-typeset abbr{cursor:help;text-decoration:none}.md-typeset [data-preview],.md-typeset abbr{border-bottom:.05rem dotted var(--md-default-fg-color--light)}.md-typeset small{opacity:.75}[dir=ltr] .md-typeset sub,[dir=ltr] .md-typeset sup{margin-left:.078125em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-right:.078125em}[dir=ltr] .md-typeset blockquote{padding-left:.6rem}[dir=rtl] .md-typeset blockquote{padding-right:.6rem}[dir=ltr] .md-typeset blockquote{border-left:.2rem solid var(--md-default-fg-color--lighter)}[dir=rtl] .md-typeset blockquote{border-right:.2rem solid var(--md-default-fg-color--lighter)}.md-typeset blockquote{color:var(--md-default-fg-color--light);margin-left:0;margin-right:0}.md-typeset ul{list-style-type:disc}.md-typeset ul[type]{list-style-type:revert-layer}[dir=ltr] .md-typeset ol,[dir=ltr] .md-typeset ul{margin-left:.625em}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-right:.625em}.md-typeset ol,.md-typeset ul{padding:0}.md-typeset ol:not([hidden]),.md-typeset ul:not([hidden]){display:flow-root}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}.md-typeset ol ol ol ol,.md-typeset ul ol ol ol{list-style-type:upper-alpha}.md-typeset ol ol ol ol ol,.md-typeset ul ol ol ol ol{list-style-type:upper-roman}.md-typeset ol[type],.md-typeset ul[type]{list-style-type:revert-layer}[dir=ltr] .md-typeset ol li,[dir=ltr] .md-typeset ul li{margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-right:1.25em}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}[dir=ltr] .md-typeset ol li ol,[dir=ltr] .md-typeset ol li ul,[dir=ltr] .md-typeset ul li ol,[dir=ltr] .md-typeset ul li ul{margin-left:.625em}[dir=rtl] .md-typeset ol li ol,[dir=rtl] .md-typeset ol li ul,[dir=rtl] .md-typeset ul li ol,[dir=rtl] .md-typeset ul li ul{margin-right:.625em}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset dd{margin-left:1.875em}[dir=rtl] .md-typeset dd{margin-right:1.875em}.md-typeset dd{margin-bottom:1.5em;margin-top:1em}.md-typeset img,.md-typeset svg,.md-typeset video{height:auto;max-width:100%}.md-typeset img[align=left]{margin:1em 1em 1em 0}.md-typeset img[align=right]{margin:1em 0 1em 1em}.md-typeset img[align]:only-child{margin-top:0}.md-typeset figure{display:flow-root;margin:1em auto;max-width:100%;text-align:center;width:fit-content}.md-typeset figure img{display:block;margin:0 auto}.md-typeset figcaption{font-style:italic;margin:1em auto;max-width:24rem}.md-typeset iframe{max-width:100%}.md-typeset table:not([class]){background-color:var(--md-default-bg-color);border:.05rem solid var(--md-typeset-table-color);border-radius:.1rem;display:inline-block;font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto}@media print{.md-typeset table:not([class]){display:table}}.md-typeset table:not([class])+*{margin-top:1.5em}.md-typeset table:not([class]) td>:first-child,.md-typeset table:not([class]) th>:first-child{margin-top:0}.md-typeset table:not([class]) td>:last-child,.md-typeset table:not([class]) th>:last-child{margin-bottom:0}.md-typeset table:not([class]) td:not([align]),.md-typeset table:not([class]) th:not([align]){text-align:left}[dir=rtl] .md-typeset table:not([class]) td:not([align]),[dir=rtl] .md-typeset table:not([class]) th:not([align]){text-align:right}.md-typeset table:not([class]) th{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) td{border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) tbody tr{transition:background-color 125ms}.md-typeset table:not([class]) tbody tr:hover{background-color:var(--md-typeset-table-color--light);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset}.md-typeset table:not([class]) a{word-break:normal}.md-typeset table th[role=columnheader]{cursor:pointer}[dir=ltr] .md-typeset table th[role=columnheader]:after{margin-left:.5em}[dir=rtl] .md-typeset table th[role=columnheader]:after{margin-right:.5em}.md-typeset table th[role=columnheader]:after{content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-typeset-table-sort-icon);mask-image:var(--md-typeset-table-sort-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset table th[role=columnheader]:hover:after{background-color:var(--md-default-fg-color--lighter)}.md-typeset table th[role=columnheader][aria-sort=ascending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--asc);mask-image:var(--md-typeset-table-sort-icon--asc)}.md-typeset table th[role=columnheader][aria-sort=descending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--desc);mask-image:var(--md-typeset-table-sort-icon--desc)}.md-typeset__scrollwrap{margin:1em -.8rem;overflow-x:auto;touch-action:auto}.md-typeset__table{display:inline-block;margin-bottom:.5em;padding:0 .8rem}@media print{.md-typeset__table{display:block}}html .md-typeset__table table{display:table;margin:0;overflow:hidden;width:100%}@media screen and (max-width:44.984375em){.md-content__inner>pre{margin:1em -.8rem}.md-content__inner>pre code{border-radius:0}}.md-typeset .md-author{border-radius:100%;display:block;flex-shrink:0;height:1.6rem;overflow:hidden;position:relative;transition:color 125ms,transform 125ms;width:1.6rem}.md-typeset .md-author img{display:block}.md-typeset .md-author--more{background:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--lighter);font-size:.6rem;font-weight:700;line-height:1.6rem;text-align:center}.md-typeset .md-author--long{height:2.4rem;width:2.4rem}.md-typeset a.md-author{transform:scale(1)}.md-typeset a.md-author img{border-radius:100%;filter:grayscale(100%) opacity(75%);transition:filter 125ms}.md-typeset a.md-author:focus,.md-typeset a.md-author:hover{transform:scale(1.1);z-index:1}.md-typeset a.md-author:focus img,.md-typeset a.md-author:hover img{filter:grayscale(0)}.md-banner{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color);overflow:auto}@media print{.md-banner{display:none}}.md-banner--warning{background-color:var(--md-warning-bg-color);color:var(--md-warning-fg-color)}.md-banner__inner{font-size:.7rem;margin:.6rem auto;padding:0 .8rem}[dir=ltr] .md-banner__button{float:right}[dir=rtl] .md-banner__button{float:left}.md-banner__button{color:inherit;cursor:pointer;transition:opacity .25s}.no-js .md-banner__button{display:none}.md-banner__button:hover{opacity:.7}html{scrollbar-gutter:stable;font-size:125%;height:100%;overflow-x:hidden}@media screen and (min-width:100em){html{font-size:137.5%}}@media screen and (min-width:125em){html{font-size:150%}}body{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;font-size:.5rem;min-height:100%;position:relative;width:100%}@media print{body{display:block}}@media screen and (max-width:59.984375em){body[data-md-scrolllock]{position:fixed}}.md-grid{margin-left:auto;margin-right:auto;max-width:61rem}.md-container{display:flex;flex-direction:column;flex-grow:1}@media print{.md-container{display:block}}.md-main{flex-grow:1}.md-main__inner{display:flex;height:100%;margin-top:1.5rem}.md-ellipsis{overflow:hidden;text-overflow:ellipsis}.md-toggle{display:none}.md-option{height:0;opacity:0;position:absolute;width:0}.md-option:checked+label:not([hidden]){display:block}.md-option.focus-visible+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-skip{background-color:var(--md-default-fg-color);border-radius:.1rem;color:var(--md-default-bg-color);font-size:.64rem;margin:.5rem;opacity:0;outline-color:var(--md-accent-fg-color);padding:.3rem .5rem;position:fixed;transform:translateY(.4rem);z-index:-1}.md-skip:focus{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 175ms 75ms;z-index:10}@page{margin:25mm}:root{--md-clipboard-icon:url('data:image/svg+xml;charset=utf-8,')}.md-clipboard{border-radius:.1rem;color:var(--md-default-fg-color--lightest);cursor:pointer;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em;z-index:1}@media print{.md-clipboard{display:none}}.md-clipboard:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}:hover>.md-clipboard{color:var(--md-default-fg-color--light)}.md-clipboard:focus,.md-clipboard:hover{color:var(--md-accent-fg-color)}.md-clipboard:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-image:var(--md-clipboard-icon);mask-image:var(--md-clipboard-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-clipboard--inline{cursor:pointer}.md-clipboard--inline code{transition:color .25s,background-color .25s}.md-clipboard--inline:focus code,.md-clipboard--inline:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}:root{--md-code-select-icon:url('data:image/svg+xml;charset=utf-8,');--md-code-copy-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-code__content{display:grid}.md-code__nav{background-color:var(--md-code-bg-color--lighter);border-radius:.1rem;display:flex;gap:.2rem;padding:.2rem;position:absolute;right:.25em;top:.25em;transition:background-color .25s;z-index:1}:hover>.md-code__nav{background-color:var(--md-code-bg-color--light)}.md-code__button{color:var(--md-default-fg-color--lightest);cursor:pointer;display:block;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em}:hover>*>.md-code__button{color:var(--md-default-fg-color--light)}.md-code__button.focus-visible,.md-code__button:hover{color:var(--md-accent-fg-color)}.md-code__button--active{color:var(--md-default-fg-color)!important}.md-code__button:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-code__button[data-md-type=select]:after{-webkit-mask-image:var(--md-code-select-icon);mask-image:var(--md-code-select-icon)}.md-code__button[data-md-type=copy]:after{-webkit-mask-image:var(--md-code-copy-icon);mask-image:var(--md-code-copy-icon)}@keyframes consent{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@keyframes overlay{0%{opacity:0}to{opacity:1}}.md-consent__overlay{animation:overlay .25s both;-webkit-backdrop-filter:blur(.1rem);backdrop-filter:blur(.1rem);background-color:#0000008a;height:100%;opacity:1;position:fixed;top:0;width:100%;z-index:5}.md-consent__inner{animation:consent .5s cubic-bezier(.1,.7,.1,1) both;background-color:var(--md-default-bg-color);border:0;border-radius:.1rem;bottom:0;box-shadow:0 0 .2rem #0000001a,0 .2rem .4rem #0003;max-height:100%;overflow:auto;padding:0;position:fixed;width:100%;z-index:5}.md-consent__form{padding:.8rem}.md-consent__settings{display:none;margin:1em 0}input:checked+.md-consent__settings{display:block}.md-consent__controls{margin-bottom:.8rem}.md-typeset .md-consent__controls .md-button{display:inline}@media screen and (max-width:44.984375em){.md-typeset .md-consent__controls .md-button{display:block;margin-top:.4rem;text-align:center;width:100%}}.md-consent label{cursor:pointer}.md-content{flex-grow:1;min-width:0}.md-content__inner{margin:0 .8rem 1.2rem;padding-top:.6rem}@media screen and (min-width:76.25em){[dir=ltr] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}[dir=ltr] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner,[dir=rtl] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=rtl] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}}.md-content__inner:before{content:"";display:block;height:.4rem}.md-content__inner>:last-child{margin-bottom:0}[dir=ltr] .md-content__button{float:right}[dir=rtl] .md-content__button{float:left}[dir=ltr] .md-content__button{margin-left:.4rem}[dir=rtl] .md-content__button{margin-right:.4rem}.md-content__button{margin:.4rem 0;padding:0}@media print{.md-content__button{display:none}}.md-typeset .md-content__button{color:var(--md-default-fg-color--lighter)}.md-content__button svg{display:inline;vertical-align:top}[dir=rtl] .md-content__button svg{transform:scaleX(-1)}.md-content__button svg.lucide{fill:#0000;stroke:currentcolor}[dir=ltr] .md-dialog{right:.8rem}[dir=rtl] .md-dialog{left:.8rem}.md-dialog{background-color:var(--md-default-fg-color);border-radius:.1rem;bottom:.8rem;box-shadow:var(--md-shadow-z3);min-width:11.1rem;opacity:0;padding:.4rem .6rem;pointer-events:none;position:fixed;transform:translateY(100%);transition:transform 0ms .4s,opacity .4s;z-index:4}@media print{.md-dialog{display:none}}.md-dialog--active{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(.075,.85,.175,1),opacity .4s}.md-dialog__inner{color:var(--md-default-bg-color);font-size:.7rem}.md-feedback{margin:2em 0 1em;text-align:center}.md-feedback fieldset{border:none;margin:0;padding:0}.md-feedback__title{font-weight:700;margin:1em auto}.md-feedback__inner{position:relative}.md-feedback__list{display:flex;flex-wrap:wrap;place-content:baseline center;position:relative}.md-feedback__list:hover .md-icon:not(:disabled){color:var(--md-default-fg-color--lighter)}:disabled .md-feedback__list{min-height:1.8rem}.md-feedback__icon{color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;margin:0 .1rem;transition:color 125ms}.md-feedback__icon:not(:disabled).md-icon:hover{color:var(--md-accent-fg-color)}.md-feedback__icon:disabled{color:var(--md-default-fg-color--lightest);pointer-events:none}.md-feedback__note{opacity:0;position:relative;transform:translateY(.4rem);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-feedback__note>*{margin:0 auto;max-width:16rem}:disabled .md-feedback__note{opacity:1;transform:translateY(0)}@media print{.md-feedback{display:none}}.md-footer{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color)}@media print{.md-footer{display:none}}.md-footer__inner{justify-content:space-between;overflow:auto;padding:.2rem}.md-footer__inner:not([hidden]){display:flex}.md-footer__link{align-items:end;display:flex;flex-grow:0.01;margin-bottom:.4rem;margin-top:1rem;max-width:100%;outline-color:var(--md-accent-fg-color);overflow:hidden;transition:opacity .25s}.md-footer__link:focus,.md-footer__link:hover{opacity:.7}[dir=rtl] .md-footer__link svg{transform:scaleX(-1)}@media screen and (max-width:44.984375em){.md-footer__link--prev{flex-shrink:0}.md-footer__link--prev .md-footer__title{display:none}}[dir=ltr] .md-footer__link--next{margin-left:auto}[dir=rtl] .md-footer__link--next{margin-right:auto}.md-footer__link--next{text-align:right}[dir=rtl] .md-footer__link--next{text-align:left}.md-footer__title{flex-grow:1;font-size:.9rem;margin-bottom:.7rem;max-width:calc(100% - 2.4rem);padding:0 1rem;white-space:nowrap}.md-footer__button{margin:.2rem;padding:.4rem}.md-footer__direction{font-size:.64rem;opacity:.7}.md-footer-meta{background-color:var(--md-footer-bg-color--dark)}.md-footer-meta__inner{display:flex;flex-wrap:wrap;justify-content:space-between;padding:.2rem}html .md-footer-meta.md-typeset a{color:var(--md-footer-fg-color--light)}html .md-footer-meta.md-typeset a:focus,html .md-footer-meta.md-typeset a:hover{color:var(--md-footer-fg-color)}.md-copyright{color:var(--md-footer-fg-color--lighter);font-size:.64rem;margin:auto .6rem;padding:.4rem 0;width:100%}@media screen and (min-width:45em){.md-copyright{width:auto}}.md-copyright__highlight{color:var(--md-footer-fg-color--light)}.md-social{display:inline-flex;gap:.2rem;margin:0 .4rem;padding:.2rem 0 .6rem}@media screen and (min-width:45em){.md-social{padding:.6rem 0}}.md-social__link{display:inline-block;height:1.6rem;text-align:center;width:1.6rem}.md-social__link:before{line-height:1.9}.md-social__link svg{fill:currentcolor;max-height:.8rem;vertical-align:-25%}.md-social__link svg.lucide{fill:#0000;stroke:currentcolor}.md-typeset .md-button{border:.1rem solid;border-radius:.1rem;color:var(--md-primary-fg-color);cursor:pointer;display:inline-block;font-weight:700;padding:.625em 2em;transition:color 125ms,background-color 125ms,border-color 125ms}.md-typeset .md-button--primary{background-color:var(--md-primary-fg-color);border-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color)}.md-typeset .md-button:focus,.md-typeset .md-button:hover{background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[dir=ltr] .md-typeset .md-input{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .md-input,[dir=rtl] .md-typeset .md-input{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .md-input{border-top-left-radius:.1rem}.md-typeset .md-input{border-bottom:.1rem solid var(--md-default-fg-color--lighter);box-shadow:var(--md-shadow-z1);font-size:.8rem;height:1.8rem;padding:0 .6rem;transition:border .25s,box-shadow .25s}.md-typeset .md-input:focus,.md-typeset .md-input:hover{border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input--stretch{width:100%}.md-header{background-color:var(--md-primary-fg-color);box-shadow:0 0 .2rem #0000,0 .2rem .4rem #0000;color:var(--md-primary-bg-color);display:block;left:0;position:sticky;right:0;top:0;z-index:4}@media print{.md-header{display:none}}.md-header[hidden]{transform:translateY(-100%);transition:transform .25s cubic-bezier(.8,0,.6,1),box-shadow .25s}.md-header--shadow{box-shadow:0 0 .2rem #0000001a,0 .2rem .4rem #0003;transition:transform .25s cubic-bezier(.1,.7,.1,1),box-shadow .25s}.md-header__inner{align-items:center;display:flex;padding:0 .2rem}.md-header__button{color:currentcolor;cursor:pointer;margin:.2rem;outline-color:var(--md-accent-fg-color);padding:.4rem;position:relative;transition:opacity .25s;vertical-align:middle;z-index:1}.md-header__button:hover{opacity:.7}.md-header__button:not([hidden]){display:inline-block}.md-header__button:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-header__button.md-logo{margin:.2rem;padding:.4rem}@media screen and (max-width:76.234375em){.md-header__button.md-logo{display:none}}.md-header__button.md-logo img,.md-header__button.md-logo svg{fill:currentcolor;display:block;height:1.2rem;width:auto}@media screen and (min-width:60em){.md-header__button[for=__search]{display:none}}.no-js .md-header__button[for=__search]{display:none}[dir=rtl] .md-header__button[for=__search] svg{transform:scaleX(-1)}@media screen and (min-width:76.25em){.md-header__button[for=__drawer]{display:none}}.md-header__topic{display:flex;max-width:100%;position:absolute;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;white-space:nowrap}.md-header__topic+.md-header__topic{opacity:0;pointer-events:none;transform:translateX(1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__topic+.md-header__topic{transform:translateX(-1.25rem)}.md-header__topic:first-child{font-weight:700}[dir=ltr] .md-header__title{margin-left:1rem;margin-right:.4rem}[dir=rtl] .md-header__title{margin-left:.4rem;margin-right:1rem}.md-header__title{flex-grow:1;font-size:.9rem;height:2.4rem;line-height:2.4rem}.md-header__title--active .md-header__topic{opacity:0;pointer-events:none;transform:translateX(-1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__title--active .md-header__topic{transform:translateX(1.25rem)}.md-header__title--active .md-header__topic+.md-header__topic{opacity:1;pointer-events:auto;transform:translateX(0);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;z-index:0}.md-header__title>.md-header__ellipsis{height:100%;position:relative;width:100%}.md-header__option{display:flex;flex-shrink:0;max-width:100%;white-space:nowrap}.md-header__option>input{bottom:0}.md-header__source{display:none}@media screen and (min-width:60em){[dir=ltr] .md-header__source{margin-left:1rem}[dir=rtl] .md-header__source{margin-right:1rem}.md-header__source{display:block;max-width:11.7rem;width:11.7rem}}@media screen and (min-width:76.25em){[dir=ltr] .md-header__source{margin-left:1.4rem}[dir=rtl] .md-header__source{margin-right:1.4rem}}.md-meta{color:var(--md-default-fg-color--light);font-size:.7rem;line-height:1.3}.md-meta__list{display:inline-flex;flex-wrap:wrap;list-style:none;margin:0;padding:0}.md-meta__item:not(:last-child):after{content:"·";margin-left:.2rem;margin-right:.2rem}.md-meta__link{color:var(--md-typeset-a-color)}.md-meta__link:focus,.md-meta__link:hover{color:var(--md-accent-fg-color)}.md-draft{background-color:#ff1744;border-radius:.125em;color:#fff;display:inline-block;font-weight:700;padding-left:.5714285714em;padding-right:.5714285714em}:root{--md-nav-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-nav-icon--next:url('data:image/svg+xml;charset=utf-8,');--md-toc-icon:url('data:image/svg+xml;charset=utf-8,')}.md-nav{font-size:.7rem;line-height:1.3}.md-nav__title{color:var(--md-default-fg-color--light);display:block;font-weight:700;overflow:hidden;padding:0 .6rem;text-overflow:ellipsis}.md-nav__title .md-nav__button{display:none}.md-nav__title .md-nav__button img{height:100%;width:auto}.md-nav__title .md-nav__button.md-logo img,.md-nav__title .md-nav__button.md-logo svg{fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__list{list-style:none;margin:0;padding:0}.md-nav__link{align-items:flex-start;display:flex;gap:.4rem;margin-top:.625em;scroll-snap-align:start;transition:color 125ms}.md-nav__link--passed,.md-nav__link--passed code{color:var(--md-default-fg-color--light)}.md-nav__item .md-nav__link--active,.md-nav__item .md-nav__link--active code{color:var(--md-typeset-a-color)}.md-nav__link .md-ellipsis{position:relative}.md-nav__link .md-ellipsis code{word-break:normal}[dir=ltr] .md-nav__link .md-icon:last-child{margin-left:auto}[dir=rtl] .md-nav__link .md-icon:last-child{margin-right:auto}.md-nav__link .md-typeset{font-size:.7rem;line-height:1.3}.md-nav__link svg{fill:currentcolor;flex-shrink:0;height:1.3em;position:relative;width:1.3em}.md-nav__link svg.lucide{fill:#0000;stroke:currentcolor}.md-nav__link[for]:focus,.md-nav__link[for]:hover,.md-nav__link[href]:focus,.md-nav__link[href]:hover{color:var(--md-accent-fg-color);cursor:pointer}.md-nav__link[for]:focus code,.md-nav__link[for]:hover code,.md-nav__link[href]:focus code,.md-nav__link[href]:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-nav__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-nav--primary .md-nav__link[for=__toc]{display:none}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{background-color:currentcolor;display:block;height:100%;-webkit-mask-image:var(--md-toc-icon);mask-image:var(--md-toc-icon);width:100%}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:none}.md-nav__container>.md-nav__link{margin-top:0}.md-nav__container>.md-nav__link:first-child{flex-grow:1;min-width:0}.md-nav__icon{flex-shrink:0}.md-nav__source{display:none}@media screen and (max-width:76.234375em){.md-nav--primary,.md-nav--primary .md-nav{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;height:100%;left:0;position:absolute;right:0;top:0;z-index:1}.md-nav--primary .md-nav__item,.md-nav--primary .md-nav__title{font-size:.8rem;line-height:1.5}.md-nav--primary .md-nav__title{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);cursor:pointer;height:5.6rem;line-height:2.4rem;padding:3rem .8rem .2rem;position:relative;white-space:nowrap}[dir=ltr] .md-nav--primary .md-nav__title .md-nav__icon{left:.4rem}[dir=rtl] .md-nav--primary .md-nav__title .md-nav__icon{right:.4rem}.md-nav--primary .md-nav__title .md-nav__icon{display:block;height:1.2rem;margin:.2rem;position:absolute;top:.4rem;width:1.2rem}.md-nav--primary .md-nav__title .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--prev);mask-image:var(--md-nav-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}.md-nav--primary .md-nav__title~.md-nav__list{background-color:var(--md-default-bg-color);box-shadow:0 .05rem 0 var(--md-default-fg-color--lightest) inset;overflow-y:auto;overscroll-behavior-y:contain;scroll-snap-type:y mandatory;touch-action:pan-y}.md-nav--primary .md-nav__title~.md-nav__list>:first-child{border-top:0}.md-nav--primary .md-nav__title[for=__drawer]{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);font-weight:700}.md-nav--primary .md-nav__title .md-logo{display:block;left:.2rem;margin:.2rem;padding:.4rem;position:absolute;right:.2rem;top:.2rem}.md-nav--primary .md-nav__list{flex:1}.md-nav--primary .md-nav__item{border-top:.05rem solid var(--md-default-fg-color--lightest)}.md-nav--primary .md-nav__item--active>.md-nav__link{color:var(--md-typeset-a-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:focus,.md-nav--primary .md-nav__item--active>.md-nav__link:hover{color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__link{margin-top:0;padding:.6rem .8rem}.md-nav--primary .md-nav__link svg{margin-top:.1em}.md-nav--primary .md-nav__link>.md-nav__link{padding:0}[dir=ltr] .md-nav--primary .md-nav__link .md-nav__icon{margin-right:-.2rem}[dir=rtl] .md-nav--primary .md-nav__link .md-nav__icon{margin-left:-.2rem}.md-nav--primary .md-nav__link .md-nav__icon{font-size:1.2rem;height:1.2rem;width:1.2rem}.md-nav--primary .md-nav__link .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-nav--primary .md-nav__icon:after{transform:scale(-1)}.md-nav--primary .md-nav--secondary .md-nav{background-color:initial;position:static}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:1.4rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-right:1.4rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-right:2rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:2.6rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-right:2.6rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:3.2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-right:3.2rem}.md-nav--secondary{background-color:initial}.md-nav__toggle~.md-nav{display:flex;opacity:0;transform:translateX(100%);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity 125ms 50ms}[dir=rtl] .md-nav__toggle~.md-nav{transform:translateX(-100%)}.md-nav__toggle:checked~.md-nav{opacity:1;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 125ms 125ms}.md-nav__toggle:checked~.md-nav>.md-nav__list{backface-visibility:hidden}}@media screen and (max-width:59.984375em){.md-nav--primary .md-nav__link[for=__toc]{display:flex}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--primary .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:flex}.md-nav__source{background-color:var(--md-primary-fg-color--dark);color:var(--md-primary-bg-color);display:block;padding:0 .2rem}}@media screen and (min-width:60em) and (max-width:76.234375em){.md-nav--integrated .md-nav__link[for=__toc]{display:flex}.md-nav--integrated .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--integrated .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--integrated .md-nav__link[for=__toc]~.md-nav{display:flex}}@media screen and (min-width:60em){.md-nav{margin-bottom:-.4rem}.md-nav--secondary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--secondary .md-nav__title[for=__toc]{scroll-snap-align:start}.md-nav--secondary .md-nav__title .md-nav__icon{display:none}[dir=ltr] .md-nav--secondary .md-nav__list{padding-left:.6rem}[dir=rtl] .md-nav--secondary .md-nav__list{padding-right:.6rem}.md-nav--secondary .md-nav__list{padding-bottom:.4rem}[dir=ltr] .md-nav--secondary .md-nav__item>.md-nav__link{margin-right:.4rem}[dir=rtl] .md-nav--secondary .md-nav__item>.md-nav__link{margin-left:.4rem}}@media screen and (min-width:76.25em){.md-nav{margin-bottom:-.4rem;transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav--primary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--primary .md-nav__title[for=__drawer]{scroll-snap-align:start}.md-nav--primary .md-nav__title .md-nav__icon{display:none}[dir=ltr] .md-nav--primary .md-nav__list{padding-left:.6rem}[dir=rtl] .md-nav--primary .md-nav__list{padding-right:.6rem}.md-nav--primary .md-nav__list{padding-bottom:.4rem}[dir=ltr] .md-nav--primary .md-nav__item>.md-nav__link{margin-right:.4rem}[dir=rtl] .md-nav--primary .md-nav__item>.md-nav__link{margin-left:.4rem}.md-nav__toggle~.md-nav{display:grid;grid-template-rows:minmax(.4rem,0fr);opacity:0;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .25s,visibility 0ms .25s;visibility:collapse}.md-nav__toggle~.md-nav>.md-nav__list{overflow:hidden}.md-nav__toggle.md-toggle--indeterminate~.md-nav,.md-nav__toggle:checked~.md-nav{grid-template-rows:minmax(.4rem,1fr);opacity:1;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .15s .1s,visibility 0ms;visibility:visible}.md-nav__toggle.md-toggle--indeterminate~.md-nav{transition:none}.md-nav__item--nested>.md-nav>.md-nav__title{display:none}.md-nav__item--section{display:block;margin:1.25em 0}.md-nav__item--section:last-child{margin-bottom:0}.md-nav__item--section>.md-nav__link{font-weight:700}.md-nav__item--section>.md-nav__link[for]{color:var(--md-default-fg-color--light)}.md-nav__item--section>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav__item--section>.md-nav__link .md-icon,.md-nav__item--section>.md-nav__link>[for]{display:none}[dir=ltr] .md-nav__item--section>.md-nav{margin-left:-.6rem}[dir=rtl] .md-nav__item--section>.md-nav{margin-right:-.6rem}.md-nav__item--section>.md-nav{display:block;opacity:1;visibility:visible}.md-nav__item--section>.md-nav>.md-nav__list>.md-nav__item{padding:0}.md-nav__icon{border-radius:100%;height:.9rem;transition:background-color .25s;width:.9rem}.md-nav__icon:hover{background-color:var(--md-accent-fg-color--transparent)}.md-nav__icon:after{background-color:currentcolor;border-radius:100%;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:transform .25s;vertical-align:-.1rem;width:100%}[dir=rtl] .md-nav__icon:after{transform:rotate(180deg)}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link .md-nav__icon:after,.md-nav__item--nested .md-toggle--indeterminate~.md-nav__link .md-nav__icon:after{transform:rotate(90deg)}.md-nav--lifted>.md-nav__list>.md-nav__item,.md-nav--lifted>.md-nav__title{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active{display:block}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);margin-top:0;position:sticky;top:0;z-index:1}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active.md-nav__item--section{margin:0}[dir=ltr] .md-nav--lifted>.md-nav__list>.md-nav__item>.md-nav:not(.md-nav--secondary){margin-left:-.6rem}[dir=rtl] .md-nav--lifted>.md-nav__list>.md-nav__item>.md-nav:not(.md-nav--secondary){margin-right:-.6rem}.md-nav--lifted>.md-nav__list>.md-nav__item>[for]{color:var(--md-default-fg-color--light)}.md-nav--lifted .md-nav[data-md-level="1"]{grid-template-rows:minmax(.4rem,1fr);opacity:1;visibility:visible}[dir=ltr] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-left:.05rem solid var(--md-primary-fg-color)}[dir=rtl] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-right:.05rem solid var(--md-primary-fg-color)}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{display:block;margin-bottom:1.25em;opacity:1;visibility:visible}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__list{overflow:visible;padding-bottom:0}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__title{display:none}}.md-pagination{font-size:.8rem;font-weight:700;gap:.4rem}.md-pagination,.md-pagination>*{align-items:center;display:flex;justify-content:center}.md-pagination>*{border-radius:.2rem;height:1.8rem;min-width:1.8rem;text-align:center}.md-pagination__current{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light)}.md-pagination__link{transition:color 125ms,background-color 125ms}.md-pagination__link:focus,.md-pagination__link:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-pagination__link:focus svg,.md-pagination__link:hover svg{color:var(--md-accent-fg-color)}.md-pagination__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-pagination__link svg{fill:currentcolor;color:var(--md-default-fg-color--lighter);display:block;max-height:100%;width:1.2rem}:root{--md-path-icon:url('data:image/svg+xml;charset=utf-8,')}.md-path{font-size:.7rem;margin:0 .8rem;overflow:auto;padding-top:1.2rem}.md-path:not([hidden]){display:block}@media screen and (min-width:76.25em){.md-path{margin:0 1.2rem}}.md-path__list{align-items:center;display:flex;gap:.2rem;list-style:none;margin:0;padding:0}.md-path__item:not(:first-child){display:inline-flex;gap:.2rem;white-space:nowrap}.md-path__item:not(:first-child):before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline;height:.8rem;-webkit-mask-image:var(--md-path-icon);mask-image:var(--md-path-icon);width:.8rem}.md-path__link{align-items:center;color:var(--md-default-fg-color--light);display:flex}.md-path__link:focus,.md-path__link:hover{color:var(--md-accent-fg-color)}:root{--md-post-pin-icon:url('data:image/svg+xml;charset=utf-8,')}.md-post__back{border-bottom:.05rem solid var(--md-default-fg-color--lightest);margin-bottom:1.2rem;padding-bottom:1.2rem}@media screen and (max-width:76.234375em){.md-post__back{display:none}}[dir=rtl] .md-post__back svg{transform:scaleX(-1)}.md-post__authors{display:flex;flex-direction:column;gap:.6rem;margin:0 .6rem 1.2rem}.md-post .md-post__meta a{transition:color 125ms}.md-post .md-post__meta a:focus,.md-post .md-post__meta a:hover{color:var(--md-accent-fg-color)}.md-post__title{color:var(--md-default-fg-color--light);font-weight:700}.md-post--excerpt{margin-bottom:3.2rem}.md-post--excerpt .md-post__header{align-items:center;display:flex;gap:.6rem;min-height:1.6rem}.md-post--excerpt .md-post__authors{align-items:center;display:inline-flex;flex-direction:row;gap:.2rem;margin:0;min-height:2.4rem}[dir=ltr] .md-post--excerpt .md-post__meta .md-meta__list{margin-right:.4rem}[dir=rtl] .md-post--excerpt .md-post__meta .md-meta__list{margin-left:.4rem}.md-post--excerpt .md-post__content>:first-child{--md-scroll-margin:6rem;margin-top:0}.md-post>.md-nav--secondary{margin:1em 0}.md-pin{background:var(--md-default-fg-color--lightest);border-radius:1rem;margin-top:-.05rem;padding:.2rem}.md-pin:after{background-color:currentcolor;content:"";display:block;height:.6rem;margin:0 auto;-webkit-mask-image:var(--md-post-pin-icon);mask-image:var(--md-post-pin-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.6rem}.md-profile{align-items:center;display:flex;font-size:.7rem;gap:.6rem;line-height:1.4;width:100%}.md-profile__description{flex-grow:1}.md-content--post{display:flex}@media screen and (max-width:76.234375em){.md-content--post{flex-flow:column-reverse}}.md-content--post>.md-content__inner{flex-grow:1;min-width:0}@media screen and (min-width:76.25em){[dir=ltr] .md-content--post>.md-content__inner{margin-left:1.2rem}[dir=rtl] .md-content--post>.md-content__inner{margin-right:1.2rem}}@media screen and (max-width:76.234375em){.md-sidebar.md-sidebar--post{padding:0;position:static;width:100%}.md-sidebar.md-sidebar--post .md-sidebar__scrollwrap{overflow:visible}.md-sidebar.md-sidebar--post .md-sidebar__inner{padding:0}.md-sidebar.md-sidebar--post .md-post__meta{margin-left:.6rem;margin-right:.6rem}.md-sidebar.md-sidebar--post .md-nav__item{border:none;display:inline}.md-sidebar.md-sidebar--post .md-nav__list{display:inline-flex;flex-wrap:wrap;gap:.6rem;padding-bottom:.6rem;padding-top:.6rem}.md-sidebar.md-sidebar--post .md-nav__link{padding:0}.md-sidebar.md-sidebar--post .md-nav{height:auto;margin-bottom:0;position:static}}:root{--md-progress-value:0;--md-progress-delay:400ms}.md-progress{background:var(--md-primary-bg-color);height:.075rem;opacity:min(clamp(0,var(--md-progress-value),1),clamp(0,100 - var(--md-progress-value),1));position:fixed;top:0;transform:scaleX(calc(var(--md-progress-value)*1%));transform-origin:left;transition:transform .5s cubic-bezier(.19,1,.22,1),opacity .25s var(--md-progress-delay);width:100%;z-index:4}:root{--md-search-icon:url('data:image/svg+xml;charset=utf-8,')}.md-search{position:relative}@media screen and (min-width:60em){.md-search{padding:.2rem 0}}@media screen and (max-width:59.984375em){.md-search{display:none}}.no-js .md-search{display:none}[dir=ltr] .md-search__button{padding-left:1.9rem;padding-right:2.2rem}[dir=rtl] .md-search__button{padding-left:2.2rem;padding-right:1.9rem}.md-search__button{background:var(--md-primary-fg-color);color:var(--md-primary-bg-color);cursor:pointer;font-size:.7rem;position:relative;text-align:left}@media screen and (min-width:45em){.md-search__button{background-color:#00000042;border-radius:.2rem;height:1.6rem;transition:background-color .4s,color .4s;width:8.9rem}.md-search__button:focus,.md-search__button:hover{background-color:#ffffff1f;color:var(--md-primary-bg-color)}}[dir=ltr] .md-search__button:before{left:0}[dir=rtl] .md-search__button:before{right:0}.md-search__button:before{background-color:var(--md-primary-bg-color);content:"";height:1rem;margin-left:.5rem;-webkit-mask-image:var(--md-search-icon);mask-image:var(--md-search-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.3rem;width:1rem}.md-search__button:after{background:#00000042;border-radius:.1rem;content:"Ctrl+K";display:block;font-size:.6rem;padding:.1rem .2rem;position:absolute;right:.6rem;top:.35rem}[data-platform^=Mac] .md-search__button:after{content:"⌘K"}.md-select{position:relative;z-index:1}.md-select__inner{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);left:50%;margin-top:.2rem;max-height:0;opacity:0;position:absolute;top:calc(100% - .2rem);transform:translate3d(-50%,.3rem,0);transition:transform .25s 375ms,opacity .25s .25s,max-height 0ms .5s}@media screen and (max-width:59.984375em){.md-select__inner{left:100%;transform:translate3d(-100%,.3rem,0)}}.md-select:focus-within .md-select__inner,.md-select:hover .md-select__inner{max-height:min(75vh,28rem);opacity:1;transform:translate3d(-50%,0,0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}@media screen and (max-width:59.984375em){.md-select:focus-within .md-select__inner,.md-select:hover .md-select__inner{transform:translate3d(-100%,0,0)}}.md-select__inner:after{border-bottom:.2rem solid #0000;border-bottom-color:var(--md-default-bg-color);border-left:.2rem solid #0000;border-right:.2rem solid #0000;border-top:0;content:"";filter:drop-shadow(0 -1px 0 var(--md-default-fg-color--lightest));height:0;left:50%;margin-left:-.2rem;margin-top:-.2rem;position:absolute;top:0;width:0}@media screen and (max-width:59.984375em){.md-select__inner:after{left:auto;right:1rem}}.md-select__list{border-radius:.1rem;font-size:.8rem;list-style-type:none;margin:0;max-height:inherit;overflow:auto;padding:0}.md-select__item{line-height:1.8rem}[dir=ltr] .md-select__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-select__link{padding-left:1.2rem;padding-right:.6rem}.md-select__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:background-color .25s,color .25s;width:100%}.md-select__link:focus,.md-select__link:hover{color:var(--md-accent-fg-color)}.md-select__link:focus{background-color:var(--md-default-fg-color--lightest)}.md-sidebar{align-self:flex-start;flex-shrink:0;padding:1.2rem 0;position:sticky;top:2.4rem;width:12.1rem}@media print{.md-sidebar{display:none}}@media screen and (max-width:76.234375em){[dir=ltr] .md-sidebar--primary{left:-12.1rem}[dir=rtl] .md-sidebar--primary{right:-12.1rem}.md-sidebar--primary{background-color:var(--md-default-bg-color);display:block;height:100%;position:fixed;top:0;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;width:12.1rem;z-index:5}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:var(--md-shadow-z3);transform:translateX(12.1rem)}[dir=rtl] [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{transform:translateX(-12.1rem)}.md-sidebar--primary .md-sidebar__scrollwrap{bottom:0;left:0;margin:0;overflow:hidden;overscroll-behavior-y:contain;position:absolute;right:0;scroll-snap-type:none;top:0}}@media screen and (min-width:76.25em){.md-sidebar{height:0}.no-js .md-sidebar{height:auto}.md-header--lifted~.md-container .md-sidebar{top:4.8rem}}.md-sidebar--secondary{display:none;order:2}@media screen and (min-width:60em){.md-sidebar--secondary{height:0}.no-js .md-sidebar--secondary{height:auto}.md-sidebar--secondary:not([hidden]){display:block}.md-sidebar--secondary .md-sidebar__scrollwrap{touch-action:pan-y}}.md-sidebar__scrollwrap{backface-visibility:hidden;margin:0 .2rem;overflow-y:auto;scrollbar-color:var(--md-default-fg-color--lighter) #0000}@media screen and (min-width:60em){.md-sidebar__scrollwrap{scrollbar-gutter:stable;scrollbar-width:thin}}.md-sidebar__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-sidebar__scrollwrap:focus-within,.md-sidebar__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb:hover,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@supports selector(::-webkit-scrollbar){.md-sidebar__scrollwrap{scrollbar-gutter:auto}[dir=ltr] .md-sidebar__inner{padding-right:calc(100% - 11.5rem)}[dir=rtl] .md-sidebar__inner{padding-left:calc(100% - 11.5rem)}}@media screen and (max-width:76.234375em){.md-overlay{background-color:#0000008a;height:0;opacity:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0;z-index:5}[data-md-toggle=drawer]:checked~.md-overlay{height:100%;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@keyframes facts{0%{height:0}to{height:.65rem}}@keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}:root{--md-source-forks-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-repositories-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-stars-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-source{backface-visibility:hidden;display:block;font-size:.65rem;line-height:1.2;outline-color:var(--md-accent-fg-color);transition:opacity .25s;white-space:nowrap}.md-source:hover{opacity:.7}.md-source__icon{display:inline-block;height:2.4rem;vertical-align:middle;width:2rem}[dir=ltr] .md-source__icon svg{margin-left:.6rem}[dir=rtl] .md-source__icon svg{margin-right:.6rem}.md-source__icon svg{margin-top:.6rem}[dir=ltr] .md-source__icon+.md-source__repository{padding-left:2rem}[dir=rtl] .md-source__icon+.md-source__repository{padding-right:2rem}[dir=ltr] .md-source__icon+.md-source__repository{margin-left:-2rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-right:-2rem}[dir=ltr] .md-source__repository{margin-left:.6rem}[dir=rtl] .md-source__repository{margin-right:.6rem}.md-source__repository{display:inline-block;max-width:calc(100% - 1.2rem);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}.md-source__facts{display:flex;font-size:.55rem;gap:.4rem;list-style-type:none;margin:.1rem 0 0;opacity:.75;overflow:hidden;padding:0;width:100%}.md-source__repository--active .md-source__facts{animation:facts .25s ease-in}.md-source__fact{overflow:hidden;text-overflow:ellipsis}.md-source__repository--active .md-source__fact{animation:fact .4s ease-out}[dir=ltr] .md-source__fact:before{margin-right:.1rem}[dir=rtl] .md-source__fact:before{margin-left:.1rem}.md-source__fact:before{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-top;width:.6rem}.md-source__fact:nth-child(1n+2){flex-shrink:0}.md-source__fact--version:before{-webkit-mask-image:var(--md-source-version-icon);mask-image:var(--md-source-version-icon)}.md-source__fact--stars:before{-webkit-mask-image:var(--md-source-stars-icon);mask-image:var(--md-source-stars-icon)}.md-source__fact--forks:before{-webkit-mask-image:var(--md-source-forks-icon);mask-image:var(--md-source-forks-icon)}.md-source__fact--repositories:before{-webkit-mask-image:var(--md-source-repositories-icon);mask-image:var(--md-source-repositories-icon)}.md-source-file{margin:1em 0}[dir=ltr] .md-source-file__fact{margin-right:.6rem}[dir=rtl] .md-source-file__fact{margin-left:.6rem}.md-source-file__fact{align-items:center;color:var(--md-default-fg-color--light);display:inline-flex;font-size:.68rem;gap:.3rem}.md-source-file__fact .md-icon{flex-shrink:0;margin-bottom:.05rem}[dir=ltr] .md-source-file__fact .md-author{float:left}[dir=rtl] .md-source-file__fact .md-author{float:right}.md-source-file__fact .md-author{margin-right:.2rem}.md-source-file__fact svg{width:.9rem}:root{--md-status:url('data:image/svg+xml;charset=utf-8,');--md-status--new:url('data:image/svg+xml;charset=utf-8,');--md-status--deprecated:url('data:image/svg+xml;charset=utf-8,');--md-status--encrypted:url('data:image/svg+xml;charset=utf-8,')}.md-status:after{background-color:var(--md-default-fg-color--light);content:"";display:inline-block;height:1.125em;-webkit-mask-image:var(--md-status);mask-image:var(--md-status);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-bottom;width:1.125em}.md-status:hover:after{background-color:currentcolor}.md-status--new:after{-webkit-mask-image:var(--md-status--new);mask-image:var(--md-status--new)}.md-status--deprecated:after{-webkit-mask-image:var(--md-status--deprecated);mask-image:var(--md-status--deprecated)}.md-status--encrypted:after{-webkit-mask-image:var(--md-status--encrypted);mask-image:var(--md-status--encrypted)}.md-tabs{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);display:block;line-height:1.3;overflow:auto;width:100%;z-index:3}@media print{.md-tabs{display:none}}@media screen and (max-width:76.234375em){.md-tabs{display:none}}.md-tabs[hidden]{pointer-events:none}[dir=ltr] .md-tabs__list{margin-left:.2rem}[dir=rtl] .md-tabs__list{margin-right:.2rem}.md-tabs__list{contain:content;display:flex;list-style:none;margin:0;overflow:auto;padding:0;scrollbar-width:none;white-space:nowrap}.md-tabs__list::-webkit-scrollbar{display:none}.md-tabs__item{height:2.4rem;padding-left:.6rem;padding-right:.6rem}.md-tabs__item--active .md-tabs__link{color:inherit;opacity:1}.md-tabs__link{backface-visibility:hidden;display:flex;font-size:.7rem;margin-top:.8rem;opacity:.7;outline-color:var(--md-accent-fg-color);outline-offset:.2rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s}.md-tabs__link:focus,.md-tabs__link:hover{color:inherit;opacity:1}[dir=ltr] .md-tabs__link svg{margin-right:.4rem}[dir=rtl] .md-tabs__link svg{margin-left:.4rem}.md-tabs__link svg{fill:currentcolor;height:1.3em}.md-tabs__item:nth-child(2) .md-tabs__link{transition-delay:20ms}.md-tabs__item:nth-child(3) .md-tabs__link{transition-delay:40ms}.md-tabs__item:nth-child(4) .md-tabs__link{transition-delay:60ms}.md-tabs__item:nth-child(5) .md-tabs__link{transition-delay:80ms}.md-tabs__item:nth-child(6) .md-tabs__link{transition-delay:.1s}.md-tabs__item:nth-child(7) .md-tabs__link{transition-delay:.12s}.md-tabs__item:nth-child(8) .md-tabs__link{transition-delay:.14s}.md-tabs__item:nth-child(9) .md-tabs__link{transition-delay:.16s}.md-tabs__item:nth-child(10) .md-tabs__link{transition-delay:.18s}.md-tabs__item:nth-child(11) .md-tabs__link{transition-delay:.2s}.md-tabs__item:nth-child(12) .md-tabs__link{transition-delay:.22s}.md-tabs__item:nth-child(13) .md-tabs__link{transition-delay:.24s}.md-tabs__item:nth-child(14) .md-tabs__link{transition-delay:.26s}.md-tabs__item:nth-child(15) .md-tabs__link{transition-delay:.28s}.md-tabs__item:nth-child(16) .md-tabs__link{transition-delay:.3s}.md-tabs[hidden] .md-tabs__link{opacity:0;transform:translateY(50%);transition:transform 0ms .1s,opacity .1s}:root{--md-tag-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-tags:not([hidden]){display:inline-flex;flex-wrap:wrap;gap:.5em;margin-bottom:.75em;margin-top:-.125em}.md-typeset .md-tag{align-items:center;background:var(--md-default-fg-color--lightest);border-radius:2.4rem;display:inline-flex;font-size:.64rem;font-size:min(.8em,.64rem);font-weight:700;gap:.5em;letter-spacing:normal;line-height:1.6;padding:.3125em .78125em}.md-typeset .md-tag[href]{-webkit-tap-highlight-color:transparent;color:inherit;outline:none;transition:color 125ms,background-color 125ms}.md-typeset .md-tag[href]:focus,.md-typeset .md-tag[href]:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[id]>.md-typeset .md-tag{vertical-align:text-top}.md-typeset .md-tag-shadow{opacity:.5}.md-typeset .md-tag-icon:before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-tag-icon);mask-image:var(--md-tag-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset .md-tag-icon[href]:focus:before,.md-typeset .md-tag-icon[href]:hover:before{background-color:var(--md-accent-bg-color)}@keyframes pulse{0%{transform:scale(.95)}75%{transform:scale(1)}to{transform:scale(.95)}}:root{--md-annotation-bg-icon:url('data:image/svg+xml;charset=utf-8,');--md-annotation-icon:url('data:image/svg+xml;charset=utf-8,')}.md-tooltip{backface-visibility:hidden;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);font-family:var(--md-text-font-family);left:clamp(var(--md-tooltip-0,0rem) + .8rem,var(--md-tooltip-x),100vw + var(--md-tooltip-0,0rem) + .8rem - var(--md-tooltip-width) - 2 * .8rem);max-width:calc(100vw - 1.6rem);opacity:0;position:absolute;top:var(--md-tooltip-y);transform:translateY(-.4rem);transition:transform 0ms .25s,opacity .25s,z-index .25s;width:var(--md-tooltip-width);z-index:0}.md-tooltip--active{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,z-index 0ms;z-index:2}.md-tooltip--inline{font-weight:700;-webkit-user-select:none;user-select:none;width:auto}.md-tooltip--inline:not(.md-tooltip--active){transform:translateY(.2rem) scale(.9)}.md-tooltip--inline .md-tooltip__inner{font-size:.5rem;padding:.2rem .4rem}[hidden]+.md-tooltip--inline{display:none}.focus-visible>.md-tooltip,.md-tooltip:target{outline:var(--md-accent-fg-color) auto}.md-tooltip__inner{font-size:.64rem;padding:.8rem}.md-tooltip__inner.md-typeset>:first-child{margin-top:0}.md-tooltip__inner.md-typeset>:last-child{margin-bottom:0}.md-annotation{font-style:normal;font-weight:400;outline:none;text-align:initial;vertical-align:text-bottom;white-space:normal}[dir=rtl] .md-annotation{direction:rtl}code .md-annotation{font-family:var(--md-code-font-family);font-size:inherit}.md-annotation:not([hidden]){display:inline-block;line-height:1.25}.md-annotation__index{border-radius:.01px;cursor:pointer;display:inline-block;margin-left:.4ch;margin-right:.4ch;outline:none;overflow:hidden;position:relative;-webkit-user-select:none;user-select:none;vertical-align:text-top;z-index:0}.md-annotation .md-annotation__index{transition:z-index .25s}@media screen{.md-annotation__index{width:2.2ch}[data-md-visible]>.md-annotation__index{animation:pulse 2s infinite}.md-annotation__index:before{background:var(--md-default-bg-color);-webkit-mask-image:var(--md-annotation-bg-icon);mask-image:var(--md-annotation-bg-icon)}.md-annotation__index:after,.md-annotation__index:before{content:"";height:2.2ch;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:-.1ch;width:2.2ch;z-index:-1}.md-annotation__index:after{background-color:var(--md-default-fg-color--lighter);-webkit-mask-image:var(--md-annotation-icon);mask-image:var(--md-annotation-icon);transform:scale(1.0001);transition:background-color .25s,transform .25s}.md-tooltip--active+.md-annotation__index:after{transform:rotate(45deg)}.md-tooltip--active+.md-annotation__index:after,:hover>.md-annotation__index:after{background-color:var(--md-accent-fg-color)}}.md-tooltip--active+.md-annotation__index{animation-play-state:paused;transition-duration:0ms;z-index:2}.md-annotation__index [data-md-annotation-id]{display:inline-block}@media print{.md-annotation__index [data-md-annotation-id]{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);font-weight:700;padding:0 .6ch;white-space:nowrap}.md-annotation__index [data-md-annotation-id]:after{content:attr(data-md-annotation-id)}}.md-typeset .md-annotation-list{counter-reset:annotation;list-style:none!important}.md-typeset .md-annotation-list li{position:relative}[dir=ltr] .md-typeset .md-annotation-list li:before{left:-2.125em}[dir=rtl] .md-typeset .md-annotation-list li:before{right:-2.125em}.md-typeset .md-annotation-list li:before{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);content:counter(annotation);counter-increment:annotation;font-size:.8875em;font-weight:700;height:2ch;line-height:1.25;min-width:2ch;padding:0 .6ch;position:absolute;text-align:center;top:.25em}:root{--md-tooltip-width:20rem;--md-tooltip-tail:0.3rem}.md-tooltip2{backface-visibility:hidden;color:var(--md-default-fg-color);font-family:var(--md-text-font-family);opacity:0;pointer-events:none;position:absolute;top:calc(var(--md-tooltip-host-y) + var(--md-tooltip-y));transform:translateY(-.4rem);transform-origin:calc(var(--md-tooltip-host-x) + var(--md-tooltip-x)) 0;transition:transform 0ms .25s,opacity .25s,z-index .25s;width:100%;z-index:0}.md-tooltip2:before{border-left:var(--md-tooltip-tail) solid #0000;border-right:var(--md-tooltip-tail) solid #0000;content:"";display:block;left:clamp(1.5 * .8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-tail),100vw - 2 * var(--md-tooltip-tail) - 1.5 * .8rem);position:absolute;z-index:1}.md-tooltip2--top:before{border-top:var(--md-tooltip-tail) solid var(--md-default-bg-color);bottom:calc(var(--md-tooltip-tail)*-1 + .025rem);filter:drop-shadow(0 1px 0 hsla(0,0%,0%,.05))}.md-tooltip2--bottom:before{border-bottom:var(--md-tooltip-tail) solid var(--md-default-bg-color);filter:drop-shadow(0 -1px 0 hsla(0,0%,0%,.05));top:calc(var(--md-tooltip-tail)*-1 + .025rem)}.md-tooltip2--active{opacity:1;transform:translateY(0);transition:transform .4s cubic-bezier(0,1,.5,1),opacity .25s,z-index 0ms;z-index:4}.md-tooltip2__inner{scrollbar-gutter:stable;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);left:clamp(.8rem,var(--md-tooltip-host-x) - .8rem,100vw - var(--md-tooltip-width) - .8rem);max-height:40vh;max-width:calc(100vw - 1.6rem);position:relative;scrollbar-width:thin}.md-tooltip2__inner::-webkit-scrollbar{height:.2rem;width:.2rem}.md-tooltip2__inner::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-tooltip2__inner::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}[role=dialog]>.md-tooltip2__inner{font-size:.64rem;overflow:auto;padding:0 .8rem;pointer-events:auto;width:var(--md-tooltip-width)}[role=dialog]>.md-tooltip2__inner:after,[role=dialog]>.md-tooltip2__inner:before{content:"";display:block;height:.8rem;position:sticky;width:100%;z-index:10}[role=dialog]>.md-tooltip2__inner:before{background:linear-gradient(var(--md-default-bg-color),#0000 75%);top:0}[role=dialog]>.md-tooltip2__inner:after{background:linear-gradient(#0000,var(--md-default-bg-color) 75%);bottom:0}[role=tooltip]>.md-tooltip2__inner{font-size:.5rem;font-weight:700;left:clamp(.8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-width)/2,100vw - var(--md-tooltip-width) - .8rem);max-width:min(100vw - 2 * .8rem,400px);padding:.2rem .4rem;-webkit-user-select:none;user-select:none;width:fit-content}.md-tooltip2__inner.md-typeset>:first-child{margin-top:0}.md-tooltip2__inner.md-typeset>:last-child{margin-bottom:0}[dir=ltr] .md-top{margin-left:50%}[dir=rtl] .md-top{margin-right:50%}.md-top{background-color:var(--md-default-bg-color);border-radius:1.6rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);cursor:pointer;display:block;font-size:.7rem;outline:none;padding:.4rem .8rem;position:fixed;top:3.2rem;transform:translate(-50%);transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms;z-index:2}@media print{.md-top{display:none}}[dir=rtl] .md-top{transform:translate(50%)}.md-top[hidden]{opacity:0;pointer-events:none;transform:translate(-50%,.2rem);transition-duration:0ms}[dir=rtl] .md-top[hidden]{transform:translate(50%,.2rem)}.md-top:focus,.md-top:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top svg{display:inline-block;vertical-align:-.5em}.md-top.lucide{fill:#0000;stroke:currentcolor}@keyframes hoverfix{0%{pointer-events:none}}:root{--md-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-version{flex-shrink:0;font-size:.8rem;height:2.4rem}[dir=ltr] .md-version__current{margin-left:1.4rem;margin-right:.4rem}[dir=rtl] .md-version__current{margin-left:.4rem;margin-right:1.4rem}.md-version__current{color:inherit;cursor:pointer;outline:none;position:relative;top:.05rem}[dir=ltr] .md-version__current:after{margin-left:.4rem}[dir=rtl] .md-version__current:after{margin-right:.4rem}.md-version__current:after{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-image:var(--md-version-icon);mask-image:var(--md-version-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.4rem}.md-version__alias{margin-left:.3rem;opacity:.7}.md-version__list{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);list-style-type:none;margin:.2rem .8rem;max-height:0;opacity:0;overflow:auto;padding:0;position:absolute;scroll-snap-type:y mandatory;top:.15rem;transition:max-height 0ms .5s,opacity .25s .25s;z-index:3}.md-version:focus-within .md-version__list,.md-version:hover .md-version__list{max-height:10rem;opacity:1;transition:max-height 0ms,opacity .25s}@media (hover:none),(pointer:coarse){.md-version:hover .md-version__list{animation:hoverfix .25s forwards}.md-version:focus-within .md-version__list{animation:none}}.md-version__item{line-height:1.8rem}[dir=ltr] .md-version__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-version__link{padding-left:1.2rem;padding-right:.6rem}.md-version__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:color .25s,background-color .25s;white-space:nowrap;width:100%}.md-version__link:focus,.md-version__link:hover{color:var(--md-accent-fg-color)}.md-version__link:focus{background-color:var(--md-default-fg-color--lightest)}:root{--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .admonition,.md-typeset details{background-color:var(--md-admonition-bg-color);border:.075rem solid #448aff;border-radius:.2rem;box-shadow:var(--md-shadow-z1);color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .6rem;page-break-inside:avoid;transition:box-shadow 125ms}@media print{.md-typeset .admonition,.md-typeset details{box-shadow:none}}.md-typeset .admonition:focus-within,.md-typeset details:focus-within{box-shadow:0 0 0 .2rem #448aff1a}.md-typeset .admonition>*,.md-typeset details>*{box-sizing:border-box}.md-typeset .admonition .admonition,.md-typeset .admonition details,.md-typeset details .admonition,.md-typeset details details{margin-bottom:1em;margin-top:1em}.md-typeset .admonition .md-typeset__scrollwrap,.md-typeset details .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset .admonition .md-typeset__table,.md-typeset details .md-typeset__table{padding:0 .6rem}.md-typeset .admonition>.tabbed-set:only-child,.md-typeset details>.tabbed-set:only-child{margin-top:0}html .md-typeset .admonition>:last-child,html .md-typeset details>:last-child{margin-bottom:.6rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{padding-left:2rem;padding-right:.6rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{padding-left:.6rem;padding-right:2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-left-width:.2rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-right-width:.2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset .admonition-title,.md-typeset summary{background-color:#448aff1a;border:none;font-weight:700;margin:0 -.6rem;padding-bottom:.4rem;padding-top:.4rem;position:relative}html .md-typeset .admonition-title:last-child,html .md-typeset summary:last-child{margin-bottom:0}[dir=ltr] .md-typeset .admonition-title:before,[dir=ltr] .md-typeset summary:before{left:.6rem}[dir=rtl] .md-typeset .admonition-title:before,[dir=rtl] .md-typeset summary:before{right:.6rem}.md-typeset .admonition-title:before,.md-typeset summary:before{background-color:#448aff;content:"";height:1rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;width:1rem}.md-typeset .admonition-title code,.md-typeset summary code{box-shadow:0 0 0 .05rem var(--md-default-fg-color--lightest)}.md-typeset .admonition.note,.md-typeset details.note{border-color:#448aff}.md-typeset .admonition.note:focus-within,.md-typeset details.note:focus-within{box-shadow:0 0 0 .2rem #448aff1a}.md-typeset .note>.admonition-title,.md-typeset .note>summary{background-color:#448aff1a}.md-typeset .note>.admonition-title:before,.md-typeset .note>summary:before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note)}.md-typeset .note>.admonition-title:after,.md-typeset .note>summary:after{color:#448aff}.md-typeset .admonition.abstract,.md-typeset details.abstract{border-color:#00b0ff}.md-typeset .admonition.abstract:focus-within,.md-typeset details.abstract:focus-within{box-shadow:0 0 0 .2rem #00b0ff1a}.md-typeset .abstract>.admonition-title,.md-typeset .abstract>summary{background-color:#00b0ff1a}.md-typeset .abstract>.admonition-title:before,.md-typeset .abstract>summary:before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract)}.md-typeset .abstract>.admonition-title:after,.md-typeset .abstract>summary:after{color:#00b0ff}.md-typeset .admonition.info,.md-typeset details.info{border-color:#00b8d4}.md-typeset .admonition.info:focus-within,.md-typeset details.info:focus-within{box-shadow:0 0 0 .2rem #00b8d41a}.md-typeset .info>.admonition-title,.md-typeset .info>summary{background-color:#00b8d41a}.md-typeset .info>.admonition-title:before,.md-typeset .info>summary:before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info)}.md-typeset .info>.admonition-title:after,.md-typeset .info>summary:after{color:#00b8d4}.md-typeset .admonition.tip,.md-typeset details.tip{border-color:#00bfa5}.md-typeset .admonition.tip:focus-within,.md-typeset details.tip:focus-within{box-shadow:0 0 0 .2rem #00bfa51a}.md-typeset .tip>.admonition-title,.md-typeset .tip>summary{background-color:#00bfa51a}.md-typeset .tip>.admonition-title:before,.md-typeset .tip>summary:before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip)}.md-typeset .tip>.admonition-title:after,.md-typeset .tip>summary:after{color:#00bfa5}.md-typeset .admonition.success,.md-typeset details.success{border-color:#00c853}.md-typeset .admonition.success:focus-within,.md-typeset details.success:focus-within{box-shadow:0 0 0 .2rem #00c8531a}.md-typeset .success>.admonition-title,.md-typeset .success>summary{background-color:#00c8531a}.md-typeset .success>.admonition-title:before,.md-typeset .success>summary:before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success)}.md-typeset .success>.admonition-title:after,.md-typeset .success>summary:after{color:#00c853}.md-typeset .admonition.question,.md-typeset details.question{border-color:#64dd17}.md-typeset .admonition.question:focus-within,.md-typeset details.question:focus-within{box-shadow:0 0 0 .2rem #64dd171a}.md-typeset .question>.admonition-title,.md-typeset .question>summary{background-color:#64dd171a}.md-typeset .question>.admonition-title:before,.md-typeset .question>summary:before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question)}.md-typeset .question>.admonition-title:after,.md-typeset .question>summary:after{color:#64dd17}.md-typeset .admonition.warning,.md-typeset details.warning{border-color:#ff9100}.md-typeset .admonition.warning:focus-within,.md-typeset details.warning:focus-within{box-shadow:0 0 0 .2rem #ff91001a}.md-typeset .warning>.admonition-title,.md-typeset .warning>summary{background-color:#ff91001a}.md-typeset .warning>.admonition-title:before,.md-typeset .warning>summary:before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning)}.md-typeset .warning>.admonition-title:after,.md-typeset .warning>summary:after{color:#ff9100}.md-typeset .admonition.failure,.md-typeset details.failure{border-color:#ff5252}.md-typeset .admonition.failure:focus-within,.md-typeset details.failure:focus-within{box-shadow:0 0 0 .2rem #ff52521a}.md-typeset .failure>.admonition-title,.md-typeset .failure>summary{background-color:#ff52521a}.md-typeset .failure>.admonition-title:before,.md-typeset .failure>summary:before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure)}.md-typeset .failure>.admonition-title:after,.md-typeset .failure>summary:after{color:#ff5252}.md-typeset .admonition.danger,.md-typeset details.danger{border-color:#ff1744}.md-typeset .admonition.danger:focus-within,.md-typeset details.danger:focus-within{box-shadow:0 0 0 .2rem #ff17441a}.md-typeset .danger>.admonition-title,.md-typeset .danger>summary{background-color:#ff17441a}.md-typeset .danger>.admonition-title:before,.md-typeset .danger>summary:before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger)}.md-typeset .danger>.admonition-title:after,.md-typeset .danger>summary:after{color:#ff1744}.md-typeset .admonition.bug,.md-typeset details.bug{border-color:#f50057}.md-typeset .admonition.bug:focus-within,.md-typeset details.bug:focus-within{box-shadow:0 0 0 .2rem #f500571a}.md-typeset .bug>.admonition-title,.md-typeset .bug>summary{background-color:#f500571a}.md-typeset .bug>.admonition-title:before,.md-typeset .bug>summary:before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug)}.md-typeset .bug>.admonition-title:after,.md-typeset .bug>summary:after{color:#f50057}.md-typeset .admonition.example,.md-typeset details.example{border-color:#7c4dff}.md-typeset .admonition.example:focus-within,.md-typeset details.example:focus-within{box-shadow:0 0 0 .2rem #7c4dff1a}.md-typeset .example>.admonition-title,.md-typeset .example>summary{background-color:#7c4dff1a}.md-typeset .example>.admonition-title:before,.md-typeset .example>summary:before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example)}.md-typeset .example>.admonition-title:after,.md-typeset .example>summary:after{color:#7c4dff}.md-typeset .admonition.quote,.md-typeset details.quote{border-color:#9e9e9e}.md-typeset .admonition.quote:focus-within,.md-typeset details.quote:focus-within{box-shadow:0 0 0 .2rem #9e9e9e1a}.md-typeset .quote>.admonition-title,.md-typeset .quote>summary{background-color:#9e9e9e1a}.md-typeset .quote>.admonition-title:before,.md-typeset .quote>summary:before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote)}.md-typeset .quote>.admonition-title:after,.md-typeset .quote>summary:after{color:#9e9e9e}:root{--md-footnotes-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .footnote{color:var(--md-default-fg-color--light);font-size:.64rem}[dir=ltr] .md-typeset .footnote>ol{margin-left:0}[dir=rtl] .md-typeset .footnote>ol{margin-right:0}.md-typeset .footnote>ol>li{transition:color 125ms}.md-typeset .footnote>ol>li:target{color:var(--md-default-fg-color)}.md-typeset .footnote>ol>li:focus-within .footnote-backref{opacity:1;transform:translateX(0);transition:none}.md-typeset .footnote>ol>li:hover .footnote-backref,.md-typeset .footnote>ol>li:target .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li>:first-child{margin-top:0}.md-typeset .footnote-ref{font-size:.75em;font-weight:700}html .md-typeset .footnote-ref{outline-offset:.1rem}.md-typeset [id^="fnref:"]:target>.footnote-ref{outline:auto}.md-typeset .footnote-backref{color:var(--md-typeset-a-color);display:inline-block;font-size:0;opacity:0;transform:translateX(.25rem);transition:color .25s,transform .25s .25s,opacity 125ms .25s;vertical-align:text-bottom}@media print{.md-typeset .footnote-backref{color:var(--md-typeset-a-color);opacity:1;transform:translateX(0)}}[dir=rtl] .md-typeset .footnote-backref{transform:translateX(-.25rem)}.md-typeset .footnote-backref:hover{color:var(--md-accent-fg-color)}.md-typeset .footnote-backref:before{background-color:currentcolor;content:"";display:inline-block;height:.8rem;-webkit-mask-image:var(--md-footnotes-icon);mask-image:var(--md-footnotes-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.8rem}[dir=rtl] .md-typeset .footnote-backref:before{transform:scaleX(-1)}[dir=ltr] .md-typeset .headerlink{margin-left:.5rem}[dir=rtl] .md-typeset .headerlink{margin-right:.5rem}.md-typeset .headerlink{color:var(--md-default-fg-color--lighter);display:inline-block;opacity:0;transition:color .25s,opacity 125ms}@media print{.md-typeset .headerlink{display:none}}.md-typeset .headerlink:focus,.md-typeset :hover>.headerlink,.md-typeset :target>.headerlink{opacity:1;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset .headerlink:hover,.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset :target{--md-scroll-margin:3.6rem;--md-scroll-offset:0rem;scroll-margin-top:calc(var(--md-scroll-margin) - var(--md-scroll-offset))}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset :target{--md-scroll-margin:6rem}}.md-typeset h1:target,.md-typeset h2:target,.md-typeset h3:target{--md-scroll-offset:0.2rem}.md-typeset h4:target{--md-scroll-offset:0.15rem}.doc-contents td code{word-break:normal!important}.doc-md-description,.doc-md-description>p:first-child{display:inline}.md-typeset h5 .doc-object-name{text-transform:none}.doc .md-typeset__table,.doc .md-typeset__table table{display:table!important;width:100%}.doc .md-typeset__table tr{display:table-row}.doc-param-default,.doc-type_param-default{float:right}.doc-heading-parameter,.doc-heading-type_parameter{display:inline}.md-typeset .doc-heading-parameter{font-size:inherit}.doc-heading-parameter .headerlink,.doc-heading-type_parameter .headerlink{margin-left:0!important;margin-right:.2rem}.doc-section-title{font-weight:700}.doc-signature .autorefs{color:inherit;text-decoration-style:dotted}:host,:root,[data-md-color-scheme=default]{--doc-symbol-parameter-fg-color:#829bd1;--doc-symbol-type_parameter-fg-color:#829bd1;--doc-symbol-attribute-fg-color:#953800;--doc-symbol-function-fg-color:#8250df;--doc-symbol-method-fg-color:#8250df;--doc-symbol-class-fg-color:#0550ae;--doc-symbol-type_alias-fg-color:#0550ae;--doc-symbol-module-fg-color:#5cad0f;--doc-symbol-parameter-bg-color:#829bd11a;--doc-symbol-type_parameter-bg-color:#829bd11a;--doc-symbol-attribute-bg-color:#9538001a;--doc-symbol-function-bg-color:#8250df1a;--doc-symbol-method-bg-color:#8250df1a;--doc-symbol-class-bg-color:#0550ae1a;--doc-symbol-type_alias-bg-color:#0550ae1a;--doc-symbol-module-bg-color:#5cad0f1a}[data-md-color-scheme=slate]{--doc-symbol-parameter-fg-color:#829bd1;--doc-symbol-type_parameter-fg-color:#829bd1;--doc-symbol-attribute-fg-color:#ffa657;--doc-symbol-function-fg-color:#d2a8ff;--doc-symbol-method-fg-color:#d2a8ff;--doc-symbol-class-fg-color:#79c0ff;--doc-symbol-type_alias-fg-color:#79c0ff;--doc-symbol-module-fg-color:#baff79;--doc-symbol-parameter-bg-color:#829bd11a;--doc-symbol-type_parameter-bg-color:#829bd11a;--doc-symbol-attribute-bg-color:#ffa6571a;--doc-symbol-function-bg-color:#d2a8ff1a;--doc-symbol-method-bg-color:#d2a8ff1a;--doc-symbol-class-bg-color:#79c0ff1a;--doc-symbol-type_alias-bg-color:#79c0ff1a;--doc-symbol-module-bg-color:#baff791a}code.doc-symbol{border-radius:.1rem;font-size:.85em;font-weight:700;padding:0 .3em}a code.doc-symbol-parameter,code.doc-symbol-parameter{background-color:var(--doc-symbol-parameter-bg-color);color:var(--doc-symbol-parameter-fg-color)}code.doc-symbol-parameter:after{content:"param"}a code.doc-symbol-type_parameter,code.doc-symbol-type_parameter{background-color:var(--doc-symbol-type_parameter-bg-color);color:var(--doc-symbol-type_parameter-fg-color)}code.doc-symbol-type_parameter:after{content:"type-param"}a code.doc-symbol-attribute,code.doc-symbol-attribute{background-color:var(--doc-symbol-attribute-bg-color);color:var(--doc-symbol-attribute-fg-color)}code.doc-symbol-attribute:after{content:"attr"}a code.doc-symbol-function,code.doc-symbol-function{background-color:var(--doc-symbol-function-bg-color);color:var(--doc-symbol-function-fg-color)}code.doc-symbol-function:after{content:"func"}a code.doc-symbol-method,code.doc-symbol-method{background-color:var(--doc-symbol-method-bg-color);color:var(--doc-symbol-method-fg-color)}code.doc-symbol-method:after{content:"meth"}a code.doc-symbol-class,code.doc-symbol-class{background-color:var(--doc-symbol-class-bg-color);color:var(--doc-symbol-class-fg-color)}code.doc-symbol-class:after{content:"class"}a code.doc-symbol-type_alias,code.doc-symbol-type_alias{background-color:var(--doc-symbol-type_alias-bg-color);color:var(--doc-symbol-type_alias-fg-color)}code.doc-symbol-type_alias:after{content:"type"}a code.doc-symbol-module,code.doc-symbol-module{background-color:var(--doc-symbol-module-bg-color);color:var(--doc-symbol-module-fg-color)}code.doc-symbol-module:after{content:"mod"}:root{--md-admonition-icon--mkdocstrings-source:url('data:image/svg+xml;charset=utf-8,') }.md-typeset .admonition.mkdocstrings-source,.md-typeset details.mkdocstrings-source{border:none;padding:0}.md-typeset .admonition.mkdocstrings-source:focus-within,.md-typeset details.mkdocstrings-source:focus-within{box-shadow:none}.md-typeset .mkdocstrings-source>.admonition-title,.md-typeset .mkdocstrings-source>summary{background-color:inherit}.md-typeset .mkdocstrings-source>.admonition-title:before,.md-typeset .mkdocstrings-source>summary:before{background-color:var(--md-default-fg-color);-webkit-mask-image:var(--md-admonition-icon--mkdocstrings-source);mask-image:var(--md-admonition-icon--mkdocstrings-source)}.md-typeset div.arithmatex{overflow:auto}@media screen and (max-width:44.984375em){.md-typeset div.arithmatex{margin:0 -.8rem}.md-typeset div.arithmatex>*{width:min-content}}.md-typeset div.arithmatex>*{margin-left:auto!important;margin-right:auto!important;padding:0 .8rem;touch-action:auto}.md-typeset div.arithmatex>* mjx-container{margin:0!important}.md-typeset div.arithmatex mjx-assistive-mml{height:0}.md-typeset del.critic{background-color:var(--md-typeset-del-color)}.md-typeset del.critic,.md-typeset ins.critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset ins.critic{background-color:var(--md-typeset-ins-color)}.md-typeset .critic.comment{-webkit-box-decoration-break:clone;box-decoration-break:clone;color:var(--md-code-hl-comment-color)}.md-typeset .critic.comment:before{content:"/* "}.md-typeset .critic.comment:after{content:" */"}.md-typeset .critic.block{box-shadow:none;display:block;margin:1em 0;overflow:auto;padding-left:.8rem;padding-right:.8rem}.md-typeset .critic.block>:first-child{margin-top:.5em}.md-typeset .critic.block>:last-child{margin-bottom:.5em}:root{--md-details-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset details{display:flow-root;overflow:visible;padding-top:0}.md-typeset details[open]>summary:after{transform:rotate(90deg)}.md-typeset details:not([open]){box-shadow:none;padding-bottom:0}.md-typeset details:not([open])>summary{border-radius:.1rem}[dir=ltr] .md-typeset summary{padding-right:1.8rem}[dir=rtl] .md-typeset summary{padding-left:1.8rem}[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset summary{cursor:pointer;display:block;min-height:1rem;overflow:hidden}.md-typeset summary.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset summary:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[dir=ltr] .md-typeset summary:after{right:.4rem}[dir=rtl] .md-typeset summary:after{left:.4rem}.md-typeset summary:after{background-color:currentcolor;content:"";height:1rem;-webkit-mask-image:var(--md-details-icon);mask-image:var(--md-details-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;transform:rotate(0deg);transition:transform .25s;width:1rem}[dir=rtl] .md-typeset summary:after{transform:rotate(180deg)}.md-typeset summary::marker{display:none}.md-typeset summary::-webkit-details-marker{display:none}.md-typeset .emojione,.md-typeset .gemoji,.md-typeset .twemoji{--md-icon-size:1.125em;display:inline-flex;height:var(--md-icon-size);vertical-align:text-top}.md-typeset .emojione svg,.md-typeset .gemoji svg,.md-typeset .twemoji svg{fill:currentcolor;max-height:100%;width:var(--md-icon-size)}.md-typeset .emojione svg.lucide,.md-typeset .gemoji svg.lucide,.md-typeset .twemoji svg.lucide{fill:#0000;stroke:currentcolor}.md-typeset .lg,.md-typeset .xl,.md-typeset .xxl,.md-typeset .xxxl{vertical-align:text-bottom}.md-typeset .middle{vertical-align:middle}.md-typeset .lg{--md-icon-size:1.5em}.md-typeset .xl{--md-icon-size:2.25em}.md-typeset .xxl{--md-icon-size:3em}.md-typeset .xxxl{--md-icon-size:4em}.highlight .o,.highlight .ow{color:var(--md-code-hl-operator-color)}.highlight .p{color:var(--md-code-hl-punctuation-color)}.highlight .cpf,.highlight .l,.highlight .s,.highlight .s1,.highlight .s2,.highlight .sb,.highlight .sc,.highlight .si,.highlight .ss{color:var(--md-code-hl-string-color)}.highlight .cp,.highlight .se,.highlight .sh,.highlight .sr,.highlight .sx{color:var(--md-code-hl-special-color)}.highlight .il,.highlight .m,.highlight .mb,.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:var(--md-code-hl-number-color)}.highlight .k,.highlight .kd,.highlight .kn,.highlight .kp,.highlight .kr,.highlight .kt{color:var(--md-code-hl-keyword-color)}.highlight .kc,.highlight .n{color:var(--md-code-hl-name-color)}.highlight .bp,.highlight .nb,.highlight .no{color:var(--md-code-hl-constant-color)}.highlight .nc,.highlight .ne,.highlight .nf,.highlight .nn{color:var(--md-code-hl-function-color)}.highlight .nd,.highlight .ni,.highlight .nl,.highlight .nt{color:var(--md-code-hl-keyword-color)}.highlight .c,.highlight .c1,.highlight .ch,.highlight .cm,.highlight .cs,.highlight .sd{color:var(--md-code-hl-comment-color)}.highlight .na,.highlight .nv,.highlight .vc,.highlight .vg,.highlight .vi{color:var(--md-code-hl-variable-color)}.highlight .ge,.highlight .gh,.highlight .go,.highlight .gp,.highlight .gr,.highlight .gs,.highlight .gt,.highlight .gu{color:var(--md-code-hl-generic-color)}.highlight .gd,.highlight .gi{border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight .gd{background-color:var(--md-typeset-del-color)}.highlight .gi{background-color:var(--md-typeset-ins-color)}.highlight .hll{background-color:var(--md-code-hl-color--light);box-shadow:2px 0 0 0 var(--md-code-hl-color) inset;display:block;margin:0 -1.1764705882em;padding:0 1.1764705882em}.highlight span.filename{background-color:var(--md-code-bg-color);border-bottom:.05rem solid var(--md-default-fg-color--lightest);border-top-left-radius:.1rem;border-top-right-radius:.1rem;display:flow-root;font-size:.85em;font-weight:700;margin-top:1em;padding:.6617647059em 1.1764705882em;position:relative}.highlight span.filename+pre{margin-top:0}.highlight span.filename+pre>code{border-top-left-radius:0;border-top-right-radius:0}.highlight [data-linenos]:before{background-color:var(--md-code-bg-color);box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;color:var(--md-default-fg-color--light);content:attr(data-linenos);float:left;left:-1.1764705882em;margin-left:-1.1764705882em;margin-right:1.1764705882em;padding-left:1.1764705882em;position:sticky;-webkit-user-select:none;user-select:none;z-index:3}.highlight code>span[id^=__span]>:last-child .md-annotation{margin-right:2.4rem}.highlight code[data-md-copying]{display:initial}.highlight code[data-md-copying] .hll{display:contents}.highlight code[data-md-copying] .md-annotation{display:none}.highlighttable{display:flow-root}.highlighttable tbody,.highlighttable td{display:block;padding:0}.highlighttable tr{display:flex}.highlighttable pre{margin:0}.highlighttable th.filename{flex-grow:1;padding:0;text-align:left}.highlighttable th.filename span.filename{margin-top:0}.highlighttable .linenos{background-color:var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-top-left-radius:.1rem;font-size:.85em;padding:.7720588235em 0 .7720588235em 1.1764705882em;-webkit-user-select:none;user-select:none}.highlighttable .linenodiv{box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset}.highlighttable .linenodiv pre{color:var(--md-default-fg-color--light);text-align:right}.highlighttable .linenodiv span[class]{padding-right:.5882352941em}.highlighttable .code{flex:1;min-width:0}.linenodiv a{color:inherit}.md-typeset .highlighttable{direction:ltr;margin:1em 0}.md-typeset .highlighttable>tbody>tr>.code>div>pre>code{border-bottom-left-radius:0;border-top-left-radius:0}.md-typeset .highlight+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset .highlight+.result:after{clear:both;content:"";display:block}@media screen and (max-width:44.984375em){.md-content__inner>.highlight{margin:1em -.8rem}.md-content__inner>.highlight>.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.code>div>pre>code,.md-content__inner>.highlight>.highlighttable>tbody>tr>.filename span.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.linenos,.md-content__inner>.highlight>pre>code{border-radius:0}.md-content__inner>.highlight+.result{border-left-width:0;border-radius:0;border-right-width:0;margin-left:-.8rem;margin-right:-.8rem}}.md-typeset .keys kbd:after,.md-typeset .keys kbd:before{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys span{color:var(--md-default-fg-color--light);padding:0 .2em}.md-typeset .keys .key-alt:before,.md-typeset .keys .key-left-alt:before,.md-typeset .keys .key-right-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-command:before,.md-typeset .keys .key-left-command:before,.md-typeset .keys .key-right-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-control:before,.md-typeset .keys .key-left-control:before,.md-typeset .keys .key-right-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-left-meta:before,.md-typeset .keys .key-meta:before,.md-typeset .keys .key-right-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-left-option:before,.md-typeset .keys .key-option:before,.md-typeset .keys .key-right-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-left-shift:before,.md-typeset .keys .key-right-shift:before,.md-typeset .keys .key-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-left-super:before,.md-typeset .keys .key-right-super:before,.md-typeset .keys .key-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-left-windows:before,.md-typeset .keys .key-right-windows:before,.md-typeset .keys .key-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-arrow-down:before{content:"↓";padding-right:.4em}.md-typeset .keys .key-arrow-left:before{content:"←";padding-right:.4em}.md-typeset .keys .key-arrow-right:before{content:"→";padding-right:.4em}.md-typeset .keys .key-arrow-up:before{content:"↑";padding-right:.4em}.md-typeset .keys .key-backspace:before{content:"⌫";padding-right:.4em}.md-typeset .keys .key-backtab:before{content:"⇤";padding-right:.4em}.md-typeset .keys .key-caps-lock:before{content:"⇪";padding-right:.4em}.md-typeset .keys .key-clear:before{content:"⌧";padding-right:.4em}.md-typeset .keys .key-context-menu:before{content:"☰";padding-right:.4em}.md-typeset .keys .key-delete:before{content:"⌦";padding-right:.4em}.md-typeset .keys .key-eject:before{content:"⏏";padding-right:.4em}.md-typeset .keys .key-end:before{content:"⤓";padding-right:.4em}.md-typeset .keys .key-escape:before{content:"⎋";padding-right:.4em}.md-typeset .keys .key-home:before{content:"⤒";padding-right:.4em}.md-typeset .keys .key-insert:before{content:"⎀";padding-right:.4em}.md-typeset .keys .key-page-down:before{content:"⇟";padding-right:.4em}.md-typeset .keys .key-page-up:before{content:"⇞";padding-right:.4em}.md-typeset .keys .key-print-screen:before{content:"⎙";padding-right:.4em}.md-typeset .keys .key-tab:after{content:"⇥";padding-left:.4em}.md-typeset .keys .key-num-enter:after{content:"⌤";padding-left:.4em}.md-typeset .keys .key-enter:after{content:"⏎";padding-left:.4em}:root{--md-tabbed-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-tabbed-icon--next:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .tabbed-set{border-radius:.1rem;display:flex;flex-flow:column wrap;margin:1em 0;position:relative}.md-typeset .tabbed-set>input{height:0;opacity:0;position:absolute;width:0}.md-typeset .tabbed-set>input:target{--md-scroll-offset:0.625em}.md-typeset .tabbed-set>input.focus-visible~.tabbed-labels:before{background-color:var(--md-accent-fg-color)}.md-typeset .tabbed-labels{-ms-overflow-style:none;box-shadow:0 -.05rem var(--md-default-fg-color--lightest) inset;display:flex;max-width:100%;overflow:auto;scrollbar-width:none}@media print{.md-typeset .tabbed-labels{display:contents}}@media screen{.js .md-typeset .tabbed-labels{position:relative}.js .md-typeset .tabbed-labels:before{background:var(--md-default-fg-color);bottom:0;content:"";display:block;height:2px;left:0;position:absolute;transform:translateX(var(--md-indicator-x));transition:width 225ms,background-color .25s,transform .25s;transition-timing-function:cubic-bezier(.4,0,.2,1);width:var(--md-indicator-width)}}.md-typeset .tabbed-labels::-webkit-scrollbar{display:none}.md-typeset .tabbed-labels>label{border-bottom:.1rem solid #0000;border-radius:.1rem .1rem 0 0;color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;font-size:.64rem;font-weight:700;padding:.78125em 1.25em .625em;scroll-margin-inline-start:1rem;transition:background-color .25s,color .25s;white-space:nowrap;width:auto}@media print{.md-typeset .tabbed-labels>label:first-child{order:1}.md-typeset .tabbed-labels>label:nth-child(2){order:2}.md-typeset .tabbed-labels>label:nth-child(3){order:3}.md-typeset .tabbed-labels>label:nth-child(4){order:4}.md-typeset .tabbed-labels>label:nth-child(5){order:5}.md-typeset .tabbed-labels>label:nth-child(6){order:6}.md-typeset .tabbed-labels>label:nth-child(7){order:7}.md-typeset .tabbed-labels>label:nth-child(8){order:8}.md-typeset .tabbed-labels>label:nth-child(9){order:9}.md-typeset .tabbed-labels>label:nth-child(10){order:10}.md-typeset .tabbed-labels>label:nth-child(11){order:11}.md-typeset .tabbed-labels>label:nth-child(12){order:12}.md-typeset .tabbed-labels>label:nth-child(13){order:13}.md-typeset .tabbed-labels>label:nth-child(14){order:14}.md-typeset .tabbed-labels>label:nth-child(15){order:15}.md-typeset .tabbed-labels>label:nth-child(16){order:16}.md-typeset .tabbed-labels>label:nth-child(17){order:17}.md-typeset .tabbed-labels>label:nth-child(18){order:18}.md-typeset .tabbed-labels>label:nth-child(19){order:19}.md-typeset .tabbed-labels>label:nth-child(20){order:20}}.md-typeset .tabbed-labels>label:hover{color:var(--md-default-fg-color)}.md-typeset .tabbed-labels>label>[href]:first-child{color:inherit}.md-typeset .tabbed-labels--linked>label{padding:0}.md-typeset .tabbed-labels--linked>label>a{display:block;padding:.78125em 1.25em .625em}.md-typeset .tabbed-content{width:100%}@media print{.md-typeset .tabbed-content{display:contents}}.md-typeset .tabbed-block{display:none}@media print{.md-typeset .tabbed-block{display:block}.md-typeset .tabbed-block:first-child{order:1}.md-typeset .tabbed-block:nth-child(2){order:2}.md-typeset .tabbed-block:nth-child(3){order:3}.md-typeset .tabbed-block:nth-child(4){order:4}.md-typeset .tabbed-block:nth-child(5){order:5}.md-typeset .tabbed-block:nth-child(6){order:6}.md-typeset .tabbed-block:nth-child(7){order:7}.md-typeset .tabbed-block:nth-child(8){order:8}.md-typeset .tabbed-block:nth-child(9){order:9}.md-typeset .tabbed-block:nth-child(10){order:10}.md-typeset .tabbed-block:nth-child(11){order:11}.md-typeset .tabbed-block:nth-child(12){order:12}.md-typeset .tabbed-block:nth-child(13){order:13}.md-typeset .tabbed-block:nth-child(14){order:14}.md-typeset .tabbed-block:nth-child(15){order:15}.md-typeset .tabbed-block:nth-child(16){order:16}.md-typeset .tabbed-block:nth-child(17){order:17}.md-typeset .tabbed-block:nth-child(18){order:18}.md-typeset .tabbed-block:nth-child(19){order:19}.md-typeset .tabbed-block:nth-child(20){order:20}}.md-typeset .tabbed-block>.highlight:first-child>pre,.md-typeset .tabbed-block>pre:first-child{margin:0}.md-typeset .tabbed-block>.highlight:first-child>pre>code,.md-typeset .tabbed-block>pre:first-child>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child>.filename{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable{margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.filename span.filename,.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.linenos{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.code>div>pre>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child+.result{margin-top:-.125em}.md-typeset .tabbed-block>.tabbed-set{margin:0}.md-typeset .tabbed-button{align-self:center;border-radius:100%;color:var(--md-default-fg-color--light);cursor:pointer;display:block;height:.9rem;margin-top:.1rem;pointer-events:auto;transition:background-color .25s;width:.9rem}.md-typeset .tabbed-button:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset .tabbed-button:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-tabbed-icon--prev);mask-image:var(--md-tabbed-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color .25s,transform .25s;width:100%}.md-typeset .tabbed-control{background:linear-gradient(to right,var(--md-default-bg-color) 60%,#0000);display:flex;height:1.9rem;justify-content:start;pointer-events:none;position:absolute;transition:opacity 125ms;width:1.2rem}[dir=rtl] .md-typeset .tabbed-control{transform:rotate(180deg)}.md-typeset .tabbed-control[hidden]{opacity:0}.md-typeset .tabbed-control--next{background:linear-gradient(to left,var(--md-default-bg-color) 60%,#0000);justify-content:end;right:0}.md-typeset .tabbed-control--next .tabbed-button:after{-webkit-mask-image:var(--md-tabbed-icon--next);mask-image:var(--md-tabbed-icon--next)}@media screen and (max-width:44.984375em){[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels{margin:0 -.8rem;max-width:100vw;scroll-padding-inline-start:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels:after{content:""}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-right:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-left:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-right:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{width:2rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-left:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-right:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-left:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{width:2rem}}@media screen{.md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){color:var(--md-default-fg-color)}.md-typeset .no-js .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .no-js .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .no-js .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .no-js .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .no-js .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .no-js .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .no-js .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .no-js .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .no-js .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .no-js .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .no-js .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .no-js .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .no-js .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .no-js .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .no-js .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .no-js .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .no-js .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .no-js .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .no-js .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .no-js .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.md-typeset [role=dialog] .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset [role=dialog] .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset [role=dialog] .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset [role=dialog] .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset [role=dialog] .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset [role=dialog] .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset [role=dialog] .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset [role=dialog] .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset [role=dialog] .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset [role=dialog] .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset [role=dialog] .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset [role=dialog] .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset [role=dialog] .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset [role=dialog] .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset [role=dialog] .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset [role=dialog] .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset [role=dialog] .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset [role=dialog] .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset [role=dialog] .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset [role=dialog] .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.no-js .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.no-js .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.no-js .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.no-js .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.no-js .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.no-js .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.no-js .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.no-js .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.no-js .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.no-js .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.no-js .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.no-js .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.no-js .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.no-js .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.no-js .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.no-js .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.no-js .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.no-js .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.no-js .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.no-js .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),[role=dialog] .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,[role=dialog] .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),[role=dialog] .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),[role=dialog] .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),[role=dialog] .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),[role=dialog] .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),[role=dialog] .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),[role=dialog] .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),[role=dialog] .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),[role=dialog] .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),[role=dialog] .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),[role=dialog] .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),[role=dialog] .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),[role=dialog] .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),[role=dialog] .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),[role=dialog] .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),[role=dialog] .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),[role=dialog] .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),[role=dialog] .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),[role=dialog] .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){border-color:var(--md-default-fg-color)}}.md-typeset .tabbed-set>input:first-child.focus-visible~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10).focus-visible~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11).focus-visible~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12).focus-visible~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13).focus-visible~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14).focus-visible~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15).focus-visible~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16).focus-visible~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17).focus-visible~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18).focus-visible~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19).focus-visible~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2).focus-visible~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20).focus-visible~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3).focus-visible~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4).focus-visible~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5).focus-visible~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6).focus-visible~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7).focus-visible~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8).focus-visible~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9).focus-visible~.tabbed-labels>:nth-child(9){color:var(--md-accent-fg-color)}.md-typeset .tabbed-set>input:first-child:checked~.tabbed-content>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-content>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-content>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-content>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-content>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-content>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-content>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-content>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-content>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-content>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-content>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-content>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-content>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-content>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-content>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-content>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-content>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-content>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-content>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-content>:nth-child(9){display:block}:root{--md-tasklist-icon:url('data:image/svg+xml;charset=utf-8,');--md-tasklist-icon--checked:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .task-list-item{list-style-type:none;position:relative}[dir=ltr] .md-typeset .task-list-item [type=checkbox]{left:-2em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{right:-2em}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}[dir=ltr] .md-typeset .task-list-indicator:before{left:-1.5em}[dir=rtl] .md-typeset .task-list-indicator:before{right:-1.5em}.md-typeset .task-list-indicator:before{background-color:var(--md-default-fg-color--lightest);content:"";height:1.25em;-webkit-mask-image:var(--md-tasklist-icon);mask-image:var(--md-tasklist-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.15em;width:1.25em}.md-typeset [type=checkbox]:checked+.task-list-indicator:before{background-color:#00e676;-webkit-mask-image:var(--md-tasklist-icon--checked);mask-image:var(--md-tasklist-icon--checked)}@media print{.giscus,[id=__comments]{display:none}}:root>*{--md-mermaid-font-family:var(--md-text-font-family),sans-serif;--md-mermaid-edge-color:var(--md-code-fg-color);--md-mermaid-node-bg-color:var(--md-accent-fg-color--transparent);--md-mermaid-node-fg-color:var(--md-accent-fg-color);--md-mermaid-label-bg-color:var(--md-default-bg-color);--md-mermaid-label-fg-color:var(--md-code-fg-color);--md-mermaid-sequence-actor-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actor-fg-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-actor-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-actor-line-color:var(--md-default-fg-color--lighter);--md-mermaid-sequence-actorman-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actorman-line-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-box-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-box-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-label-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-label-fg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-loop-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-loop-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-loop-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-message-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-message-line-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-note-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-border-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-number-bg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-number-fg-color:var(--md-accent-bg-color)}.mermaid{line-height:normal;margin:1em 0}.md-typeset .grid{grid-gap:.4rem;display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,16rem),1fr));margin:1em 0}.md-typeset .grid.cards>ol,.md-typeset .grid.cards>ul{display:contents}.md-typeset .grid.cards>ol>li,.md-typeset .grid.cards>ul>li,.md-typeset .grid>.card{border:.05rem solid var(--md-default-fg-color--lightest);border-radius:.1rem;display:block;margin:0;padding:.8rem;transition:border .25s,box-shadow .25s}.md-typeset .grid.cards>ol>li:focus-within,.md-typeset .grid.cards>ol>li:hover,.md-typeset .grid.cards>ul>li:focus-within,.md-typeset .grid.cards>ul>li:hover,.md-typeset .grid>.card:focus-within,.md-typeset .grid>.card:hover{border-color:#0000;box-shadow:var(--md-shadow-z2)}.md-typeset .grid.cards>ol>li>hr,.md-typeset .grid.cards>ul>li>hr,.md-typeset .grid>.card>hr{margin-bottom:1em;margin-top:1em}.md-typeset .grid.cards>ol>li>:first-child,.md-typeset .grid.cards>ul>li>:first-child,.md-typeset .grid>.card>:first-child{margin-top:0}.md-typeset .grid.cards>ol>li>:last-child,.md-typeset .grid.cards>ul>li>:last-child,.md-typeset .grid>.card>:last-child{margin-bottom:0}.md-typeset .grid>*,.md-typeset .grid>.admonition,.md-typeset .grid>.highlight>*,.md-typeset .grid>.highlighttable,.md-typeset .grid>.md-typeset details,.md-typeset .grid>details,.md-typeset .grid>pre{margin-bottom:0;margin-top:0}.md-typeset .grid>.highlight>pre:only-child,.md-typeset .grid>.highlight>pre>code,.md-typeset .grid>.highlighttable,.md-typeset .grid>.highlighttable>tbody,.md-typeset .grid>.highlighttable>tbody>tr,.md-typeset .grid>.highlighttable>tbody>tr>.code,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre>code{height:100%}.md-typeset .grid>.tabbed-set{margin-bottom:0;margin-top:0}@media screen and (min-width:45em){[dir=ltr] .md-typeset .inline{float:left}[dir=rtl] .md-typeset .inline{float:right}[dir=ltr] .md-typeset .inline{margin-right:.8rem}[dir=rtl] .md-typeset .inline{margin-left:.8rem}.md-typeset .inline{margin-bottom:.8rem;margin-top:0;width:11.7rem}[dir=ltr] .md-typeset .inline.end{float:right}[dir=rtl] .md-typeset .inline.end{float:left}[dir=ltr] .md-typeset .inline.end{margin-left:.8rem;margin-right:0}[dir=rtl] .md-typeset .inline.end{margin-left:0;margin-right:.8rem}} \ No newline at end of file diff --git a/site/assets/stylesheets/modern/main.19d3147f.min.css b/site/assets/stylesheets/modern/main.19d3147f.min.css deleted file mode 100644 index d4d48163c..000000000 --- a/site/assets/stylesheets/modern/main.19d3147f.min.css +++ /dev/null @@ -1 +0,0 @@ -@charset "UTF-8";html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;box-sizing:border-box}*,:after,:before{box-sizing:inherit}@media (prefers-reduced-motion){*,:after,:before{transition:none!important}}body{margin:0}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}hr{border:0;box-sizing:initial;display:block;height:.05rem;overflow:visible;padding:0}small{font-size:80%}sub,sup{line-height:1em}img{border-style:none}table{border-collapse:initial;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{background:#0000;border:0;font-family:inherit;font-size:inherit;margin:0;padding:0}input{border:0;outline:none}:root{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3;--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:#526cfe1a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-scheme=default]{color-scheme:light}[data-md-color-scheme=default] img[src$="#gh-dark-mode-only"],[data-md-color-scheme=default] img[src$="#only-dark"]{display:none}:root,[data-md-color-scheme=default]{--md-hue:225deg;--md-default-fg-color:#000000de;--md-default-fg-color--light:#0000008c;--md-default-fg-color--lighter:#00000052;--md-default-fg-color--lightest:#0000000d;--md-default-bg-color:#fff;--md-default-bg-color--light:#ffffffb3;--md-default-bg-color--lighter:#ffffff4d;--md-default-bg-color--lightest:#ffffff1f;--md-code-fg-color:#36464e;--md-code-bg-color:#f5f5f5;--md-code-bg-color--light:#f5f5f5b3;--md-code-bg-color--lighter:#f5f5f54d;--md-code-hl-color:#4287ff;--md-code-hl-color--light:#4287ff1a;--md-code-hl-number-color:#d52a2a;--md-code-hl-special-color:#db1457;--md-code-hl-function-color:#a846b9;--md-code-hl-constant-color:#6e59d9;--md-code-hl-keyword-color:#3f6ec6;--md-code-hl-string-color:#1c7d4d;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-del-color:#f5503d26;--md-typeset-ins-color:#0bd57026;--md-typeset-kbd-color:#fafafa;--md-typeset-kbd-accent-color:#fff;--md-typeset-kbd-border-color:#b8b8b8;--md-typeset-mark-color:#ffff0080;--md-typeset-table-color:#0000001f;--md-typeset-table-color--light:rgba(0,0,0,.035);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-warning-fg-color:#000000de;--md-warning-bg-color:#ff9;--md-shadow-z1:0 0.2rem 0.5rem #0000000d,0 0 0.05rem #0000001a;--md-shadow-z2:0 0.2rem 0.5rem #0000001a,0 0 0.05rem #00000040;--md-shadow-z3:0 0.2rem 0.5rem #0003,0 0 0.05rem #00000059;--color-foreground:0 0 0;--color-background:255 255 255;--color-background-subtle:240 240 240;--color-backdrop:255 255 255}.md-icon svg{fill:currentcolor;display:block;height:1.2rem;width:1.2rem}.md-icon svg.lucide{fill:#0000;stroke:currentcolor}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--md-text-font-family:var(--md-text-font,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif;--md-code-font-family:var(--md-code-font,_),SFMono-Regular,Consolas,Menlo,monospace}aside,body,input{font-feature-settings:"kern","liga";color:var(--md-typeset-color);font-family:var(--md-text-font-family)}code,kbd,pre{font-feature-settings:"kern";font-family:var(--md-code-font-family)}:root{--md-typeset-table-sort-icon:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--asc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--desc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-preview-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset{-webkit-print-color-adjust:exact;color-adjust:exact;font-size:.75rem;letter-spacing:-.01em;line-height:1.8;overflow-wrap:break-word}@media print{.md-typeset{font-size:.68rem}}.md-typeset blockquote,.md-typeset dl,.md-typeset figure,.md-typeset ol,.md-typeset pre,.md-typeset ul{margin-bottom:1em;margin-top:1em}.md-typeset h1{color:var(--md-default-fg-color);font-size:1.875em;line-height:1.3;margin:0 0 1.25em}.md-typeset h1,.md-typeset h2{font-weight:700;letter-spacing:-.025em}.md-typeset h2{font-size:1.5em;line-height:1.4;margin:1.6em 0 .64em}.md-typeset h3{font-size:1.25em;font-weight:700;letter-spacing:-.01em;line-height:1.5;margin:1.6em 0 .8em}.md-typeset h2+h3{margin-top:.8em}.md-typeset h4{font-weight:700;letter-spacing:-.01em;margin:1em 0}.md-typeset h5,.md-typeset h6{color:var(--md-default-fg-color--light);font-size:.8em;font-weight:700;letter-spacing:-.01em;margin:1.25em 0}.md-typeset h5{text-transform:uppercase}.md-typeset h5 code{text-transform:none}.md-typeset hr{border-bottom:.05rem solid var(--md-default-fg-color--lightest);display:flow-root;margin:1.5em 0}.md-typeset a{color:var(--md-typeset-a-color);text-decoration:underline;word-break:break-word}.md-typeset a,.md-typeset a:before{transition:color 125ms}.md-typeset a:focus,.md-typeset a:hover{color:var(--md-accent-fg-color)}.md-typeset a:focus code,.md-typeset a:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset a code{color:var(--md-typeset-a-color)}.md-typeset a.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset code,.md-typeset kbd,.md-typeset pre{color:var(--md-code-fg-color);direction:ltr;font-variant-ligatures:none;transition:background-color 125ms}@media print{.md-typeset code,.md-typeset kbd,.md-typeset pre{white-space:pre-wrap}}.md-typeset code{background-color:var(--md-code-bg-color);border-radius:.2rem;-webkit-box-decoration-break:clone;box-decoration-break:clone;font-size:.85em;padding:.25em .4em;transition:color 125ms,background-color 125ms;word-break:break-word}.md-typeset code:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset pre{display:flow-root;line-height:1.4;position:relative}.md-typeset pre>code{border-radius:.4rem;-webkit-box-decoration-break:slice;box-decoration-break:slice;box-shadow:none;display:block;margin:0;outline-color:var(--md-accent-fg-color);overflow:auto;padding:.7720588235em 1.1764705882em;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin;touch-action:auto;word-break:normal}.md-typeset pre>code:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-typeset pre>code::-webkit-scrollbar{height:.2rem;width:.2rem}.md-typeset pre>code::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset pre>code::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}.md-typeset kbd{border-radius:.2rem;box-shadow:0 0 0 .05rem var(--md-typeset-kbd-border-color),0 .15rem 0 var(--md-typeset-kbd-border-color);color:var(--md-default-fg-color);display:inline-block;font-size:.75em;padding:0 .6666666667em;vertical-align:text-top;word-break:break-word}.md-typeset mark{background-color:var(--md-typeset-mark-color);-webkit-box-decoration-break:clone;box-decoration-break:clone;color:inherit;word-break:break-word}.md-typeset abbr{border-bottom:.05rem dotted var(--md-default-fg-color--light);cursor:help;text-decoration:none}.md-typeset [data-preview]{position:relative}[dir=ltr] .md-typeset [data-preview]:after{margin-left:.125em}[dir=rtl] .md-typeset [data-preview]:after{margin-right:.125em}.md-typeset [data-preview]:after{background-color:currentcolor;content:"";display:inline-block;height:.8em;-webkit-mask-image:var(--md-typeset-preview-icon);mask-image:var(--md-typeset-preview-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-top;width:.8em}.md-typeset small{opacity:.75}[dir=ltr] .md-typeset sub,[dir=ltr] .md-typeset sup{margin-left:.078125em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-right:.078125em}[dir=ltr] .md-typeset blockquote{padding-left:.6rem}[dir=rtl] .md-typeset blockquote{padding-right:.6rem}[dir=ltr] .md-typeset blockquote{border-left:.2rem solid var(--md-default-fg-color--lighter)}[dir=rtl] .md-typeset blockquote{border-right:.2rem solid var(--md-default-fg-color--lighter)}.md-typeset blockquote{color:var(--md-default-fg-color--light);margin-left:0;margin-right:0}.md-typeset ul{list-style-type:disc}.md-typeset ul[type]{list-style-type:revert-layer}[dir=ltr] .md-typeset ol,[dir=ltr] .md-typeset ul{margin-left:.625em}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-right:.625em}.md-typeset ol,.md-typeset ul{padding:0}.md-typeset ol:not([hidden]),.md-typeset ul:not([hidden]){display:flow-root}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}.md-typeset ol ol ol ol,.md-typeset ul ol ol ol{list-style-type:upper-alpha}.md-typeset ol ol ol ol ol,.md-typeset ul ol ol ol ol{list-style-type:upper-roman}.md-typeset ol[type],.md-typeset ul[type]{list-style-type:revert-layer}[dir=ltr] .md-typeset ol li,[dir=ltr] .md-typeset ul li{margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-right:1.25em}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}[dir=ltr] .md-typeset ol li ol,[dir=ltr] .md-typeset ol li ul,[dir=ltr] .md-typeset ul li ol,[dir=ltr] .md-typeset ul li ul{margin-left:.625em}[dir=rtl] .md-typeset ol li ol,[dir=rtl] .md-typeset ol li ul,[dir=rtl] .md-typeset ul li ol,[dir=rtl] .md-typeset ul li ul{margin-right:.625em}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset dd{margin-left:1.875em}[dir=rtl] .md-typeset dd{margin-right:1.875em}.md-typeset dd{margin-bottom:1.5em;margin-top:1em}.md-typeset img,.md-typeset svg,.md-typeset video{height:auto;max-width:100%}.md-typeset img[align=left]{margin:1em 1em 1em 0}.md-typeset img[align=right]{margin:1em 0 1em 1em}.md-typeset img[align]:only-child{margin-top:0}.md-typeset figure{display:flow-root;margin:1em auto;max-width:100%;text-align:center;width:fit-content}.md-typeset figure img{display:block;margin:0 auto}.md-typeset figcaption{font-style:italic;margin:1em auto;max-width:24rem}.md-typeset iframe{max-width:100%}.md-typeset table:not([class]){background-color:var(--md-default-bg-color);border:.05rem solid var(--md-typeset-table-color);border-radius:.1rem;display:inline-block;font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto}@media print{.md-typeset table:not([class]){display:table}}.md-typeset table:not([class])+*{margin-top:1.5em}.md-typeset table:not([class]) td>:first-child,.md-typeset table:not([class]) th>:first-child{margin-top:0}.md-typeset table:not([class]) td>:last-child,.md-typeset table:not([class]) th>:last-child{margin-bottom:0}.md-typeset table:not([class]) td:not([align]),.md-typeset table:not([class]) th:not([align]){text-align:left}[dir=rtl] .md-typeset table:not([class]) td:not([align]),[dir=rtl] .md-typeset table:not([class]) th:not([align]){text-align:right}.md-typeset table:not([class]) th{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) td{border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) tbody tr{transition:background-color 125ms}.md-typeset table:not([class]) tbody tr:hover{background-color:var(--md-typeset-table-color--light);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset}.md-typeset table:not([class]) a{word-break:normal}.md-typeset table th[role=columnheader]{cursor:pointer}[dir=ltr] .md-typeset table th[role=columnheader]:after{margin-left:.5em}[dir=rtl] .md-typeset table th[role=columnheader]:after{margin-right:.5em}.md-typeset table th[role=columnheader]:after{content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-typeset-table-sort-icon);mask-image:var(--md-typeset-table-sort-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset table th[role=columnheader]:hover:after{background-color:var(--md-default-fg-color--lighter)}.md-typeset table th[role=columnheader][aria-sort=ascending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--asc);mask-image:var(--md-typeset-table-sort-icon--asc)}.md-typeset table th[role=columnheader][aria-sort=descending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--desc);mask-image:var(--md-typeset-table-sort-icon--desc)}.md-typeset__scrollwrap{margin:1em -.8rem;overflow-x:auto;touch-action:auto}.md-typeset__table{display:inline-block;margin-bottom:.5em;padding:0 .8rem}@media print{.md-typeset__table{display:block}}html .md-typeset__table table{display:table;margin:0;overflow:hidden;width:100%}@media screen and (max-width:44.984375em){.md-content__inner>pre{margin:1em -.8rem}.md-content__inner>pre code{border-radius:0}}.md-banner{background-color:var(--md-accent-fg-color--transparent);color:var(--md-default-fg-color);overflow:auto}@media print{.md-banner{display:none}}.md-banner--warning{background-color:var(--md-warning-bg-color);color:var(--md-warning-fg-color)}.md-banner__inner{font-size:.7rem;margin:.6rem auto;padding:0 .8rem}[dir=ltr] .md-banner__button{float:right}[dir=rtl] .md-banner__button{float:left}.md-banner__button{color:inherit;cursor:pointer;transition:opacity .25s}.no-js .md-banner__button{display:none}.md-banner__button:hover{opacity:.7}html{scrollbar-gutter:stable;font-size:125%;height:100%;overflow-x:hidden}@media screen and (min-width:100em){html{font-size:137.5%}}@media screen and (min-width:125em){html{font-size:150%}}body{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;font-size:.5rem;min-height:100%;position:relative;width:100%}@media print{body{display:block}}@media screen and (max-width:59.984375em){body[data-md-scrolllock]{position:fixed}}.md-grid{margin-left:auto;margin-right:auto;max-width:61rem}.md-container{display:flex;flex-direction:column;flex-grow:1}@media print{.md-container{display:block}}.md-main{flex-grow:1}.md-main__inner{display:flex;height:100%;margin-top:1.5rem}.md-ellipsis{overflow:hidden;text-overflow:ellipsis}.md-toggle{display:none}.md-option{height:0;opacity:0;position:absolute;width:0}.md-option:checked+label:not([hidden]){display:block}.md-option.focus-visible+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-skip{background-color:var(--md-default-fg-color);border-radius:.1rem;color:var(--md-default-bg-color);font-size:.64rem;margin:.5rem;opacity:0;outline-color:var(--md-accent-fg-color);padding:.3rem .5rem;position:fixed;transform:translateY(.4rem);z-index:-1}.md-skip:focus{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 175ms 75ms;z-index:10}@page{margin:25mm}:root{--md-clipboard-icon:url('data:image/svg+xml;charset=utf-8,')}.md-clipboard{border-radius:.1rem;color:var(--md-default-fg-color--lightest);cursor:pointer;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em;z-index:1}@media print{.md-clipboard{display:none}}.md-clipboard:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}:hover>.md-clipboard{color:var(--md-default-fg-color--light)}.md-clipboard:focus,.md-clipboard:hover{color:var(--md-accent-fg-color)}.md-clipboard:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-image:var(--md-clipboard-icon);mask-image:var(--md-clipboard-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-clipboard--inline{cursor:pointer}.md-clipboard--inline code{transition:color .25s,background-color .25s}.md-clipboard--inline:focus code,.md-clipboard--inline:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}:root{--md-code-select-icon:url('data:image/svg+xml;charset=utf-8,');--md-code-copy-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-code__content{display:grid}.md-code__nav{background-color:var(--md-code-bg-color--lighter);border-radius:.1rem;display:flex;gap:.2rem;padding:.2rem;position:absolute;right:.25em;top:.25em;transition:background-color .25s;z-index:1}:hover>.md-code__nav{background-color:var(--md-code-bg-color--light)}.md-code__button{color:var(--md-default-fg-color--lightest);cursor:pointer;display:block;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em}:hover>*>.md-code__button{color:var(--md-default-fg-color--light)}.md-code__button.focus-visible,.md-code__button:hover{color:var(--md-accent-fg-color)}.md-code__button--active{color:var(--md-default-fg-color)!important}.md-code__button:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-code__button[data-md-type=select]:after{-webkit-mask-image:var(--md-code-select-icon);mask-image:var(--md-code-select-icon)}.md-code__button[data-md-type=copy]:after{-webkit-mask-image:var(--md-code-copy-icon);mask-image:var(--md-code-copy-icon)}@keyframes consent{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@keyframes overlay{0%{opacity:0}to{opacity:1}}.md-consent__overlay{animation:overlay .35s both;-webkit-backdrop-filter:blur(.2rem);backdrop-filter:blur(.2rem);background-color:var(--md-default-bg-color--light);height:100%;opacity:1;position:fixed;top:0;width:100%;z-index:5}.md-consent__inner{bottom:0;display:flex;justify-content:center;max-height:100%;padding:0;position:fixed;width:100%;z-index:5}.md-consent__form{animation:consent .5s cubic-bezier(.1,.7,.1,1) both;background-color:var(--md-default-bg-color);border:0;border-radius:.8rem;box-shadow:var(--md-shadow-z3);margin:.4rem;overflow:auto;padding-left:1.2rem;padding-right:1.2rem}.md-consent__settings{display:none;margin:1em 0}input:checked+.md-consent__settings{display:block}.md-consent__controls{line-height:1.2;margin-bottom:.8rem}.md-typeset .md-consent__controls .md-button{display:inline}@media screen and (max-width:44.984375em){.md-typeset .md-consent__controls .md-button{display:block;margin-top:.4rem;text-align:center;width:100%}}.md-consent label{cursor:pointer}.md-content{flex-grow:1;min-width:0}.md-content__inner{margin:0 .8rem 1.2rem;padding-top:.7rem}@media screen and (min-width:76.25em){[dir=ltr] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}[dir=ltr] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner,[dir=rtl] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=rtl] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}}.md-content__inner:before{content:"";display:block;height:.4rem}.md-content__inner>:last-child{margin-bottom:0}[dir=ltr] .md-content__button{float:right}[dir=rtl] .md-content__button{float:left}[dir=ltr] .md-content__button{margin-left:.4rem}[dir=rtl] .md-content__button{margin-right:.4rem}.md-content__button{background-color:var(--md-default-fg-color--lightest);border-radius:.4rem;display:flex;margin-top:.2rem;padding:.3rem}@media print{.md-content__button{display:none}}.md-typeset .md-content__button{color:var(--md-default-fg-color);transition:color .25s,background-color .25s}.md-typeset .md-content__button svg{opacity:.5;transition:opacity .25s}.md-typeset .md-content__button:focus,.md-typeset .md-content__button:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset .md-content__button:focus svg,.md-typeset .md-content__button:hover svg{opacity:1}.md-content__button svg{height:.9rem;width:.9rem}[dir=rtl] .md-content__button svg{transform:scaleX(-1)}.md-content__button svg.lucide{fill:#0000;stroke:currentcolor}[dir=ltr] .md-dialog{right:.8rem}[dir=rtl] .md-dialog{left:.8rem}.md-dialog{background-color:var(--md-accent-fg-color);border-radius:1.2rem;bottom:.8rem;box-shadow:var(--md-shadow-z3);min-width:11.1rem;opacity:0;padding:.4rem 1.2rem;pointer-events:none;position:fixed;transform:translateY(100%);transition:transform 0ms .4s,opacity .4s;z-index:4}@media print{.md-dialog{display:none}}.md-dialog--active{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(.075,.85,.175,1),opacity .4s}.md-dialog__inner{color:var(--md-default-bg-color);font-size:.7rem}.md-feedback{margin:2em 0 1em;text-align:center}.md-feedback fieldset{border:none;margin:0;padding:0}.md-feedback__title{font-weight:700;margin:1em auto}.md-feedback__inner{position:relative}.md-feedback__list{display:flex;flex-wrap:wrap;place-content:baseline center;position:relative}.md-feedback__list:hover .md-icon:not(:disabled){color:var(--md-default-fg-color--lighter)}:disabled .md-feedback__list{min-height:1.8rem}.md-feedback__icon{color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;margin:0 .1rem;transition:color 125ms}.md-feedback__icon:not(:disabled).md-icon:hover{color:var(--md-accent-fg-color)}.md-feedback__icon:disabled{color:var(--md-default-fg-color--lightest);pointer-events:none}.md-feedback__note{opacity:0;position:relative;transform:translateY(.4rem);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-feedback__note>*{margin:0 auto;max-width:16rem}:disabled .md-feedback__note{opacity:1;transform:translateY(0)}@media print{.md-feedback{display:none}}.md-footer{background-color:var(--md-default-bg-color);border-top:.05rem solid var(--md-default-fg-color--lightest);color:var(--md-default-fg-color)}@media print{.md-footer{display:none}}.md-footer__inner{justify-content:space-between;overflow:auto;padding:.2rem}.md-footer__inner:not([hidden]){display:flex}.md-footer__link{align-items:end;display:flex;flex-grow:0.01;margin-bottom:.4rem;margin-top:1rem;max-width:100%;outline-color:var(--md-accent-fg-color);overflow:hidden;transition:opacity .25s}.md-footer__link:focus,.md-footer__link:hover{opacity:.7}[dir=rtl] .md-footer__link svg{transform:scaleX(-1)}@media screen and (max-width:44.984375em){.md-footer__link--prev{flex-shrink:0}.md-footer__link--prev .md-footer__title{display:none}}[dir=ltr] .md-footer__link--next{margin-left:auto}[dir=rtl] .md-footer__link--next{margin-right:auto}.md-footer__link--next{text-align:right}[dir=rtl] .md-footer__link--next{text-align:left}.md-footer__title{flex-grow:1;font-size:.8rem;margin-bottom:.7rem;max-width:calc(100% - 2.4rem);padding:0 1rem;white-space:nowrap}.md-footer__button{margin:.2rem;padding:.4rem}.md-footer__direction{font-size:.6rem;opacity:.7}.md-footer-meta{background-color:var(--md-default-fg-color--lightest)}.md-footer-meta__inner{display:flex;flex-wrap:wrap;justify-content:space-between;padding:.2rem}html .md-footer-meta.md-typeset a:not(:focus,:hover){color:var(--md-default-fg-color)}.md-copyright{color:var(--md-default-fg-color--light);font-size:.64rem;margin:auto .6rem;padding:.4rem 0;width:100%}@media screen and (min-width:45em){.md-copyright{width:auto}}.md-copyright__highlight{color:var(--md-default-fg-color)}.md-social{display:inline-flex;gap:.2rem;margin:0 .4rem;padding:.2rem 0 .6rem}@media screen and (min-width:45em){.md-social{padding:.6rem 0}}.md-social__link{display:inline-block;height:1.6rem;text-align:center;width:1.6rem}.md-social__link:before{line-height:1.9}.md-social__link svg{fill:currentcolor;max-height:.8rem;vertical-align:-25%}.md-social__link svg.lucide{fill:#0000;stroke:currentcolor}.md-typeset .md-button{background-color:var(--md-default-fg-color--lightest);border-radius:1.2rem;color:var(--md-default-fg-color--light);cursor:pointer;display:inline-block;font-size:.875em;font-weight:700;padding:.625em 2em;text-decoration:none;transition:color 125ms,background-color 125ms,opacity 125ms}.md-typeset .md-button.focus-visible{outline-offset:0}.md-typeset .md-button:focus,.md-typeset .md-button:hover{color:var(--md-default-fg-color--light);opacity:.8}.md-typeset .md-button--primary{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color)}.md-typeset .md-button--primary:focus,.md-typeset .md-button--primary:hover{color:var(--md-primary-bg-color);opacity:.8}[dir=ltr] .md-typeset .md-input{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .md-input,[dir=rtl] .md-typeset .md-input{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .md-input{border-top-left-radius:.1rem}.md-typeset .md-input{border-bottom:.1rem solid var(--md-default-fg-color--lighter);box-shadow:var(--md-shadow-z1);font-size:.8rem;height:1.8rem;padding:0 .6rem;transition:border .25s,box-shadow .25s}.md-typeset .md-input:focus,.md-typeset .md-input:hover{border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input--stretch{width:100%}.md-header{-webkit-backdrop-filter:blur(.4rem);backdrop-filter:blur(.4rem);background-color:var(--md-default-bg-color--light);color:var(--md-default-fg-color);display:block;left:0;position:sticky;right:0;top:0;z-index:4}@media print{.md-header{display:none}}.md-header[hidden]{transform:translateY(-100%);transition:transform .25s cubic-bezier(.8,0,.6,1)}.md-header--shadow{box-shadow:0 .05rem 0 var(--md-default-fg-color--lightest);transition:transform .25s cubic-bezier(.1,.7,.1,1)}.md-header__inner{align-items:center;display:flex;padding:0 .4rem}.md-header__button{color:currentcolor;cursor:pointer;margin:.2rem;outline-color:var(--md-accent-fg-color);padding:.4rem;position:relative;transition:opacity .25s;vertical-align:middle;z-index:1}.md-header__button:hover{opacity:.7}.md-header__button:not([hidden]){display:inline-block}.md-header__button:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-header__button.md-logo{margin:.2rem;padding:.4rem}@media screen and (max-width:76.234375em){.md-header__button.md-logo{display:none}}.md-header__button.md-logo img,.md-header__button.md-logo svg{fill:currentcolor;display:block;height:1.2rem;width:auto}.md-header__button.md-logo img.lucide,.md-header__button.md-logo svg.lucide{fill:#0000;stroke:currentcolor}@media screen and (min-width:60em){.md-header__button[for=__search]{display:none}}.no-js .md-header__button[for=__search]{display:none}[dir=rtl] .md-header__button[for=__search] svg{transform:scaleX(-1)}@media screen and (min-width:76.25em){.md-header__button[for=__drawer]{display:none}}.md-header__topic{display:flex;max-width:100%;position:absolute;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;white-space:nowrap}.md-header__topic+.md-header__topic{opacity:0;pointer-events:none;transform:translateX(1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__topic+.md-header__topic{transform:translateX(-1.25rem)}.md-header__topic:first-child{font-weight:700}.md-header__title{flex-grow:1;font-size:.9rem;height:2.4rem;letter-spacing:-.025em;line-height:2.4rem;margin-left:.4rem;margin-right:.4rem}.md-header__title--active .md-header__topic{opacity:0;pointer-events:none;transform:translateX(-1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__title--active .md-header__topic{transform:translateX(1.25rem)}.md-header__title--active .md-header__topic+.md-header__topic{opacity:1;pointer-events:auto;transform:translateX(0);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;z-index:0}.md-header__title>.md-header__ellipsis{height:100%;position:relative;width:100%}.md-header__option{display:flex;flex-shrink:0;max-width:100%;white-space:nowrap}.md-header__option>input{bottom:0}.md-header__source{display:none}@media screen and (min-width:60em){[dir=ltr] .md-header__source{margin-left:1rem}[dir=rtl] .md-header__source{margin-right:1rem}.md-header__source{display:block;max-width:11.5rem;width:11.5rem}}@media screen and (min-width:76.25em){[dir=ltr] .md-header__source{margin-left:1.4rem}[dir=rtl] .md-header__source{margin-right:1.4rem}}.md-header .md-icon svg{height:1rem;width:1rem}:root{--md-nav-icon--next:url('data:image/svg+xml;charset=utf-8,')}.md-nav{font-size:.7rem;line-height:1.3;transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav .md-nav__title{display:none}.md-nav__list{display:flex;flex-direction:column;gap:.2rem;list-style:none;margin:0;padding:0}[dir=ltr] .md-nav__list .md-nav__list{margin-left:.6rem}[dir=rtl] .md-nav__list .md-nav__list{margin-right:.6rem}.md-nav__item--nested .md-nav__list:after,.md-nav__item--nested .md-nav__list:before{content:" ";display:block;height:0}.md-nav__link{align-items:flex-start;border-radius:.4rem;cursor:pointer;display:flex;gap:.6rem;margin-left:.2rem;margin-right:.2rem;padding:.35rem .8rem;transition:color .25s,background-color .25s}.md-nav__link .md-nav__link{margin:0}.md-nav__link--passed,.md-nav__link--passed code{color:var(--md-default-fg-color--light)}.md-nav__item .md-nav__link--active{font-weight:500}.md-nav--primary .md-nav__item .md-nav__link--active{background:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-nav__item .md-nav__link--active,.md-nav__item .md-nav__link--active code{color:var(--md-typeset-a-color)}.md-nav__item .md-nav__link--active code svg,.md-nav__item .md-nav__link--active svg{opacity:1}[dir=ltr] .md-nav__item--nested>.md-nav__link:not(.md-nav__container){padding-right:.35rem}[dir=rtl] .md-nav__item--nested>.md-nav__link:not(.md-nav__container){padding-left:.35rem}.md-nav__link .md-ellipsis{flex-grow:1;position:relative}.md-nav__link .md-ellipsis code{word-break:normal}.md-nav__link .md-typeset{font-size:.7rem;line-height:1.3}.md-nav__link svg{fill:currentcolor;flex-shrink:0;height:1.3em;opacity:.5;position:relative;width:1.3em}.md-nav__link svg.lucide{fill:#0000;stroke:currentcolor}.md-nav--primary .md-nav__link[for]:focus:not(.md-nav__link--active),.md-nav--primary .md-nav__link[for]:hover:not(.md-nav__link--active),.md-nav--primary .md-nav__link[href]:focus:not(.md-nav__link--active),.md-nav--primary .md-nav__link[href]:hover:not(.md-nav__link--active){background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color)}.md-nav--secondary .md-nav__link{margin-left:.2rem;margin-right:.2rem;overflow-wrap:normal;padding:.35rem .8rem}.md-nav--secondary .md-nav__link[for]:focus,.md-nav--secondary .md-nav__link[for]:hover,.md-nav--secondary .md-nav__link[href]:focus,.md-nav--secondary .md-nav__link[href]:hover{background-color:initial;color:var(--md-accent-fg-color)}.md-nav__link.focus-visible{outline-color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__link[for=__toc],.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:none}.md-nav__icon{font-size:.9rem;height:.9rem;width:.9rem}[dir=rtl] .md-nav__icon:after{transform:rotate(180deg)}.md-nav__item--nested .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:transform .25s;width:100%}@media screen and (min-width:76.25em){.md-nav__item--nested.md-nav__item--section>.md-nav__link .md-nav__icon:after{display:none}}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link .md-nav__icon:after,.md-nav__item--nested .md-toggle--indeterminate~.md-nav__link .md-nav__icon:after{transform:rotate(90deg)}.md-nav__container{background:#0000;gap:.2rem;padding:0}.md-nav__container>:first-child{flex-grow:1;min-width:0}.md-nav__container>:nth-child(2){padding:.35rem}@media screen and (min-width:76.25em){.md-nav__item--section>.md-nav__container>:nth-child(2){display:none}}.md-nav__container__icon{flex-shrink:0}.md-nav__toggle~.md-nav{display:grid;grid-template-rows:minmax(.005rem,0fr);opacity:0;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .25s,visibility 0ms .25s;visibility:collapse}.md-nav__toggle~.md-nav>.md-nav__list{overflow:hidden}.md-nav__toggle.md-toggle--indeterminate~.md-nav,.md-nav__toggle:checked~.md-nav{grid-template-rows:minmax(.4rem,1fr);opacity:1;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .15s .1s,visibility 0ms;visibility:visible}.md-nav__toggle.md-toggle--indeterminate~.md-nav{transition:none}.md-nav--secondary{margin-bottom:.1rem;margin-top:.1rem}.md-nav--secondary .md-nav{margin-top:.2rem}.md-nav--secondary .md-nav__title{background:var(--md-default-bg-color);display:flex;font-weight:700;margin-left:.2rem;margin-right:.2rem;padding:.35rem .6rem;position:sticky;top:0;z-index:1}.md-nav--secondary .md-nav__title .md-nav__icon{display:none}.md-nav--secondary .md-nav__link{padding:.2rem .6rem}@media screen and (max-width:76.234375em){.md-nav--primary{margin-bottom:.4rem;margin-left:.2rem;margin-right:.2rem}.md-nav .md-nav__title[for=__drawer]{align-items:center;border-bottom:.05rem solid var(--md-default-fg-color-lightest);display:flex;font-size:.8rem;font-weight:700;gap:.4rem;padding:.8rem}.md-nav .md-nav__title[for=__drawer] .md-logo{height:1.6rem;width:1.6rem}.md-nav .md-nav__title[for=__drawer] .md-logo img,.md-nav .md-nav__title[for=__drawer] .md-logo svg{fill:currentcolor;display:block;height:100%;max-width:100%;object-fit:contain;width:auto}.md-nav .md-nav__title[for=__drawer] .md-logo img.lucide,.md-nav .md-nav__title[for=__drawer] .md-logo svg.lucide{fill:#0000;stroke:currentcolor}}.md-nav__source{border:.05rem solid var(--md-default-fg-color--lightest);border-radius:.4rem;margin:.2rem .2rem .6rem;transition:background-color .25s,border-color .25s}.md-nav__source:focus,.md-nav__source:hover{background-color:var(--md-default-fg-color--lightest);border-color:#0000}[dir=ltr] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{margin-left:1.1rem}[dir=rtl] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{margin-right:1.1rem}[dir=ltr] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-left:.05rem solid var(--md-default-fg-color--lightest)}[dir=rtl] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-right:.05rem solid var(--md-default-fg-color--lightest)}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{display:block;margin-bottom:.5em;margin-top:.5em;opacity:1;visibility:visible}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary .md-nav__link{background:#0000}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary .md-nav__link--active{font-weight:500}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary .md-nav__link:focus,.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary .md-nav__link:hover{color:var(--md-accent-fg-color)}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__list{margin-left:0;overflow:visible;padding-bottom:0}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__title{display:none}@media screen and (min-width:76.25em){.md-nav--primary{margin-bottom:.1rem;margin-top:.1rem}.md-nav__source{display:none}[dir=ltr] .md-nav__list .md-nav__item--section>.md-nav>.md-nav__list{margin-left:0}[dir=rtl] .md-nav__list .md-nav__item--section>.md-nav>.md-nav__list{margin-right:0}.md-nav__item--section>.md-nav__link--active,.md-nav__item--section>.md-nav__link>.md-nav__link--active{font-weight:700}.md-nav__item--section{margin-top:.4rem}.md-nav__item--section:first-child{margin-top:0}.md-nav__item--section:last-child{margin-bottom:0}.md-nav__item--section>.md-nav__link{font-weight:700}.md-nav__item--section>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav__item--section>.md-nav{display:block;opacity:1;visibility:visible}.md-nav__item--section>.md-nav>.md-nav__list>.md-nav__item{padding:0}.md-nav--lifted{margin-top:0}.md-nav--lifted>.md-nav__list>.md-nav__item{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active{display:block}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav{margin-top:.1rem}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav>.md-nav__list:before,.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active.md-nav__item--section{margin:0}.md-nav--lifted .md-nav[data-md-level="1"]{grid-template-rows:minmax(.4rem,1fr);opacity:1;visibility:visible}}:root{--md-path-icon:url('data:image/svg+xml;charset=utf-8,')}.md-path{font-size:.7rem;margin:.4rem .8rem 0;overflow:auto;padding-top:1.2rem}.md-path:not([hidden]){display:block}@media screen and (min-width:76.25em){.md-path{margin:.4rem 1.2rem 0}}.md-path__list{align-items:center;display:flex;gap:.2rem;list-style:none;margin:0;padding:0}.md-path__item:not(:first-child){align-items:center;display:inline-flex;gap:.2rem;white-space:nowrap}.md-path__item:not(:first-child):before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline;height:.6rem;-webkit-mask-image:var(--md-path-icon);mask-image:var(--md-path-icon);width:.6rem}.md-path__link{align-items:center;color:var(--md-default-fg-color--light);display:flex;transition:color .25s}.md-path__link:focus,.md-path__link:hover{color:var(--md-accent-fg-color)}:root{--md-progress-value:0;--md-progress-delay:400ms}.md-progress{background:var(--md-primary-bg-color);height:.075rem;opacity:min(clamp(0,var(--md-progress-value),1),clamp(0,100 - var(--md-progress-value),1));position:fixed;top:0;transform:scaleX(calc(var(--md-progress-value)*1%));transform-origin:left;transition:transform .5s cubic-bezier(.19,1,.22,1),opacity .25s var(--md-progress-delay);width:100%;z-index:4}:root{--md-search-icon:url('data:image/svg+xml;charset=utf-8,')}.md-search{position:relative}@media screen and (min-width:45em){.md-search{padding:.2rem 0}}@media screen and (max-width:59.984375em){.md-search{display:none}}.no-js .md-search{display:none}[dir=ltr] .md-search__button{padding-left:1.9rem;padding-right:2.2rem}[dir=rtl] .md-search__button{padding-left:2.2rem;padding-right:1.9rem}.md-search__button{background:var(--md-default-bg-color);color:var(--md-default-fg-color);cursor:pointer;font-size:.7rem;position:relative;text-align:left}@media screen and (min-width:45em){.md-search__button{background-color:var(--md-default-fg-color--lightest);border-radius:.4rem;height:1.6rem;transition:background-color .4s,color .4s;width:8.9rem}.md-search__button:focus,.md-search__button:hover{background-color:var(--md-default-fg-color--lighter);color:var(--md-default-fg-color)}}[dir=ltr] .md-search__button:before{left:0}[dir=rtl] .md-search__button:before{right:0}.md-search__button:before{background-color:var(--md-default-fg-color);content:"";height:1rem;margin-left:.5rem;-webkit-mask-image:var(--md-search-icon);mask-image:var(--md-search-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.3rem;width:1rem}.md-search__button:after{background:var(--md-default-bg-color--light);border-radius:.2rem;content:"Ctrl+K";display:block;font-size:.6rem;padding:.1rem .2rem;position:absolute;right:.6rem;top:.35rem}[data-platform^=Mac] .md-search__button:after{content:"⌘K"}.md-select{position:relative;z-index:1}.md-select__inner{background-color:var(--md-default-bg-color);border-radius:.4rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);left:50%;margin-top:.2rem;max-height:0;opacity:0;position:absolute;top:calc(100% - .2rem);transform:translate3d(-50%,.3rem,0);transition:transform .25s 375ms,opacity .25s .25s,max-height 0ms .5s}@media screen and (max-width:59.984375em){.md-select__inner{left:100%;transform:translate3d(-100%,.3rem,0)}}.md-select:focus-within .md-select__inner,.md-select:hover .md-select__inner{max-height:min(75vh,28rem);opacity:1;transform:translate3d(-50%,0,0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}@media screen and (max-width:59.984375em){.md-select:focus-within .md-select__inner,.md-select:hover .md-select__inner{transform:translate3d(-100%,0,0)}}.md-select__inner:after{border-bottom:.2rem solid #0000;border-bottom-color:var(--md-default-bg-color);border-left:.2rem solid #0000;border-right:.2rem solid #0000;border-top:0;content:"";filter:drop-shadow(0 -1px 0 var(--md-default-fg-color--lightest));height:0;left:50%;margin-left:-.2rem;margin-top:-.2rem;position:absolute;top:0;width:0}@media screen and (max-width:59.984375em){.md-select__inner:after{left:auto;right:1rem}}.md-select__list{border-radius:.1rem;font-size:.8rem;list-style-type:none;margin:0;max-height:inherit;overflow:auto;padding:0}.md-select__item{line-height:1.8rem}[dir=ltr] .md-select__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-select__link{padding-left:1.2rem;padding-right:.6rem}.md-select__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:background-color .25s,color .25s;width:100%}.md-select__link:focus,.md-select__link:hover{color:var(--md-accent-fg-color)}.md-select__link:focus{background-color:var(--md-default-fg-color--lightest)}:root{--md-toc-icon:url('data:image/svg+xml;charset=utf-8,')}.md-sidebar{align-self:flex-start;flex-shrink:0;padding:1.1rem 0;position:sticky;top:2.4rem;width:12.1rem}@media print{.md-sidebar{display:none}}@media screen and (max-width:76.234375em){[dir=ltr] .md-sidebar--primary{left:-12.1rem}[dir=rtl] .md-sidebar--primary{right:-12.1rem}.md-sidebar--primary{-webkit-backdrop-filter:blur(.4rem);backdrop-filter:blur(.4rem);background-color:var(--md-default-bg-color--light);border-radius:.8rem;display:block;height:calc(100% - .8rem);position:fixed;top:.4rem;transform:translateX(0);transition:transform .2s cubic-bezier(.5,0,.5,0),box-shadow .2s;width:12.1rem;z-index:5}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:var(--md-shadow-z3);transform:translateX(12.5rem);transition:transform .25s cubic-bezier(.7,.7,.1,1),box-shadow .25s}[dir=rtl] [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{transform:translateX(-12.5rem)}.md-sidebar--primary .md-sidebar__scrollwrap{bottom:0;left:0;margin:0;overscroll-behavior-y:contain;position:absolute;right:0;top:0}}@media screen and (min-width:76.25em){.md-sidebar{height:0}.no-js .md-sidebar{height:auto}.md-header--lifted~.md-container .md-sidebar{top:4.8rem}}.md-sidebar--secondary{order:2}@media screen and (max-width:59.984375em){.md-sidebar--secondary{bottom:1.6rem;padding:0;position:fixed;right:.8rem;top:auto;width:auto;z-index:2}.md-sidebar--secondary .md-nav--secondary{margin-top:0}.md-sidebar--secondary .md-nav__title{padding:.55rem .6rem .35rem}.md-sidebar--secondary .md-sidebar__scrollwrap{display:flex;flex-direction:column-reverse;overflow-y:visible;position:relative}.md-sidebar--secondary .md-sidebar__inner{background-color:var(--md-default-bg-color);border-radius:.4rem;bottom:2.7rem;box-shadow:var(--md-shadow-z2);max-height:50vh;opacity:0;overflow-y:auto;padding-bottom:.4rem;pointer-events:none;position:absolute;right:0;transform:translateY(.4rem);transition:transform 0ms .25s,opacity .25s;width:11.7rem}.md-sidebar--secondary [type=checkbox]:checked~.md-sidebar__inner{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(0,1,.35,1),opacity .25s,z-index 0ms}.md-sidebar--secondary .md-sidebar-button{-webkit-backdrop-filter:blur(.4rem);backdrop-filter:blur(.4rem);background-color:var(--md-default-bg-color--light);border-radius:1.6rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);cursor:pointer;display:inline-flex;font-size:.7rem;gap:.4rem;outline:none;padding:.5rem;transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms}.md-sidebar--secondary .md-sidebar-button:after{background-color:currentcolor;content:"";display:block;height:.9rem;-webkit-mask-image:var(--md-toc-icon);mask-image:var(--md-toc-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:transform .25s;width:.9rem}.md-sidebar--secondary .md-sidebar-button:focus,.md-sidebar--secondary .md-sidebar-button:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-sidebar--secondary .md-sidebar-button__wrapper{text-align:right}}@media screen and (min-width:60em){.md-sidebar--secondary{height:0}.md-sidebar--secondary .md-sidebar-button{display:none}.no-js .md-sidebar--secondary{height:auto}.md-sidebar--secondary:not([hidden]){display:block}.md-sidebar--secondary .md-sidebar__scrollwrap{touch-action:pan-y}}.md-sidebar__scrollwrap{backface-visibility:hidden;overflow-y:auto;scrollbar-color:var(--md-default-fg-color--lighter) #0000}@media screen and (min-width:60em){.md-sidebar__scrollwrap{scrollbar-gutter:stable;scrollbar-width:thin}}.md-sidebar__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-sidebar__scrollwrap:focus-within,.md-sidebar__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb:hover,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@supports selector(::-webkit-scrollbar){.md-sidebar__scrollwrap{scrollbar-gutter:auto}[dir=ltr] .md-sidebar__inner{padding-right:calc(100% - 11.5rem)}[dir=rtl] .md-sidebar__inner{padding-left:calc(100% - 11.5rem)}@media screen and (max-width:76.234375em){[dir=ltr] .md-sidebar__inner{padding-right:0}[dir=rtl] .md-sidebar__inner{padding-left:0}}}@media screen and (max-width:76.234375em){.md-overlay{-webkit-backdrop-filter:blur(.2rem);backdrop-filter:blur(.2rem);background-color:var(--md-default-bg-color--light);height:0;opacity:0;position:fixed;top:0;transition:width 0ms .5s,height 0ms .5s,opacity .25s 125ms;width:0;z-index:5}[data-md-toggle=drawer]:checked~.md-overlay{height:100%;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@keyframes facts{0%{height:0}to{height:.65rem}}@keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}:root{--md-source-forks-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-repositories-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-stars-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-source{backface-visibility:hidden;display:block;font-size:.55rem;line-height:1.2;outline-color:var(--md-accent-fg-color);transition:opacity .25s;white-space:nowrap}.md-source:hover{opacity:.7}.md-source__icon{display:inline-block;height:2.4rem;vertical-align:middle;width:2rem}[dir=ltr] .md-source__icon svg{margin-left:.6rem}[dir=rtl] .md-source__icon svg{margin-right:.6rem}.md-source__icon svg{margin-top:.6rem}.md-header .md-source__icon svg{height:1.2rem;width:1.2rem}[dir=ltr] .md-source__icon+.md-source__repository{padding-left:2rem}[dir=rtl] .md-source__icon+.md-source__repository{padding-right:2rem}[dir=ltr] .md-source__icon+.md-source__repository{margin-left:-2rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-right:-2rem}[dir=ltr] .md-source__repository{margin-left:.6rem}[dir=rtl] .md-source__repository{margin-right:.6rem}.md-source__repository{display:inline-block;max-width:calc(100% - 1.2rem);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}.md-source__facts{display:flex;font-size:.55rem;gap:.4rem;list-style-type:none;margin:.1rem 0 0;opacity:.75;overflow:hidden;padding:0;width:100%}.md-source__repository--active .md-source__facts{animation:facts 0ms ease-in}.md-source__fact{overflow:hidden;text-overflow:ellipsis}.md-source__repository--active .md-source__fact{animation:fact 0ms ease-out}[dir=ltr] .md-source__fact:before{margin-right:.1rem}[dir=rtl] .md-source__fact:before{margin-left:.1rem}.md-source__fact:before{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-top;width:.6rem}.md-source__fact:nth-child(1n+2){flex-shrink:0}.md-source__fact--version:before{-webkit-mask-image:var(--md-source-version-icon);mask-image:var(--md-source-version-icon)}.md-source__fact--stars:before{-webkit-mask-image:var(--md-source-stars-icon);mask-image:var(--md-source-stars-icon)}.md-source__fact--forks:before{-webkit-mask-image:var(--md-source-forks-icon);mask-image:var(--md-source-forks-icon)}.md-source__fact--repositories:before{-webkit-mask-image:var(--md-source-repositories-icon);mask-image:var(--md-source-repositories-icon)}.md-source-file{margin:1em 0}[dir=ltr] .md-source-file__fact{margin-right:.6rem}[dir=rtl] .md-source-file__fact{margin-left:.6rem}.md-source-file__fact{align-items:center;color:var(--md-default-fg-color--light);display:inline-flex;font-size:.68rem;gap:.3rem}.md-source-file__fact .md-icon{flex-shrink:0;margin-bottom:.05rem}[dir=ltr] .md-source-file__fact .md-author{float:left}[dir=rtl] .md-source-file__fact .md-author{float:right}.md-source-file__fact .md-author{margin-right:.2rem}.md-source-file__fact svg{width:.9rem}:root{--md-status:url('data:image/svg+xml;charset=utf-8,');--md-status--new:url('data:image/svg+xml;charset=utf-8,');--md-status--deprecated:url('data:image/svg+xml;charset=utf-8,')}.md-status:after{background-color:var(--md-default-fg-color--light);content:"";display:inline-block;height:1.125em;-webkit-mask-image:var(--md-status);mask-image:var(--md-status);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-bottom;width:1.125em}.md-status:hover:after{background-color:currentcolor}.md-status--new:after{-webkit-mask-image:var(--md-status--new);mask-image:var(--md-status--new)}.md-status--deprecated:after{-webkit-mask-image:var(--md-status--deprecated);mask-image:var(--md-status--deprecated)}.md-tabs{box-shadow:0 -.05rem 0 inset var(--md-default-fg-color--lightest);color:var(--md-default-fg-color);display:block;line-height:1.3;overflow:auto;width:100%;z-index:2}@media print{.md-tabs{display:none}}@media screen and (max-width:76.234375em){.md-tabs{display:none}}.md-header--lifted .md-tabs{box-shadow:none;margin-bottom:-.05rem}.md-tabs[hidden]{pointer-events:none}[dir=ltr] .md-tabs__list{margin-left:.4rem}[dir=rtl] .md-tabs__list{margin-right:.4rem}.md-tabs__list{contain:content;display:flex;list-style:none;margin:0;overflow:auto;padding:0;scrollbar-width:none;white-space:nowrap}.md-tabs__list::-webkit-scrollbar{display:none}.md-tabs__item{height:2.4rem;padding-left:.6rem;padding-right:.6rem}.md-tabs__item--active{border-bottom:.05rem solid var(--md-default-fg-color);font-weight:500;position:relative;transition:border-bottom .25s}.md-tabs[hidden] .md-tabs__item--active{border-bottom:.05rem solid #0000}.md-tabs__item--active .md-tabs__link{color:inherit;opacity:1}.md-tabs__link{backface-visibility:hidden;display:flex;font-size:.7rem;margin-top:.8rem;opacity:.7;outline-color:var(--md-accent-fg-color);outline-offset:.2rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s}.md-tabs__link:focus,.md-tabs__link:hover{color:inherit;opacity:1}[dir=ltr] .md-tabs__link svg{margin-right:.4rem}[dir=rtl] .md-tabs__link svg{margin-left:.4rem}.md-tabs__link svg{fill:currentcolor;height:1.3em}.md-tabs__item:nth-child(2) .md-tabs__link{transition-delay:20ms}.md-tabs__item:nth-child(3) .md-tabs__link{transition-delay:40ms}.md-tabs__item:nth-child(4) .md-tabs__link{transition-delay:60ms}.md-tabs__item:nth-child(5) .md-tabs__link{transition-delay:80ms}.md-tabs__item:nth-child(6) .md-tabs__link{transition-delay:.1s}.md-tabs__item:nth-child(7) .md-tabs__link{transition-delay:.12s}.md-tabs__item:nth-child(8) .md-tabs__link{transition-delay:.14s}.md-tabs__item:nth-child(9) .md-tabs__link{transition-delay:.16s}.md-tabs__item:nth-child(10) .md-tabs__link{transition-delay:.18s}.md-tabs__item:nth-child(11) .md-tabs__link{transition-delay:.2s}.md-tabs__item:nth-child(12) .md-tabs__link{transition-delay:.22s}.md-tabs__item:nth-child(13) .md-tabs__link{transition-delay:.24s}.md-tabs__item:nth-child(14) .md-tabs__link{transition-delay:.26s}.md-tabs__item:nth-child(15) .md-tabs__link{transition-delay:.28s}.md-tabs__item:nth-child(16) .md-tabs__link{transition-delay:.3s}.md-tabs[hidden] .md-tabs__link{opacity:0;transform:translateY(50%);transition:transform 0ms .1s,opacity .1s}:root{--md-tag-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-tags:not([hidden]){display:flex;flex-wrap:wrap;gap:.5em;margin-bottom:1.2rem;margin-top:.8rem;padding-top:1.2rem}.md-typeset .md-tag{align-items:center;background:var(--md-default-fg-color--lightest);border-radius:.4rem;display:inline-flex;font-size:.64rem;font-size:min(.8em,.64rem);font-weight:700;gap:.5em;letter-spacing:normal;line-height:1.6;padding:.3125em .78125em}.md-typeset .md-tag[href]{-webkit-tap-highlight-color:transparent;color:inherit;outline:none;transition:color 125ms,background-color 125ms}.md-typeset .md-tag[href]:focus,.md-typeset .md-tag[href]:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[id]>.md-typeset .md-tag{vertical-align:text-top}.md-typeset .md-tag-shadow{opacity:.5}.md-typeset .md-tag-icon:before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-tag-icon);mask-image:var(--md-tag-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset .md-tag-icon[href]:focus:before,.md-typeset .md-tag-icon[href]:hover:before{background-color:var(--md-accent-bg-color)}@keyframes pulse{0%{transform:scale(.95)}75%{transform:scale(1)}to{transform:scale(.95)}}:root{--md-annotation-bg-icon:url('data:image/svg+xml;charset=utf-8,');--md-annotation-icon:url('data:image/svg+xml;charset=utf-8,')}.md-tooltip{backface-visibility:hidden;background-color:var(--md-default-bg-color);border-radius:.4rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);font-family:var(--md-text-font-family);left:clamp(var(--md-tooltip-0,0rem) + .8rem,var(--md-tooltip-x) - .1rem,100vw + var(--md-tooltip-0,0rem) + .8rem - var(--md-tooltip-width) - 2 * .8rem);max-width:calc(100vw - 1.6rem);opacity:0;position:absolute;top:calc(var(--md-tooltip-y) - .1rem);transform:translateY(-.4rem);transition:transform 0ms .25s,opacity .25s,z-index .25s;width:var(--md-tooltip-width);z-index:0}.md-tooltip--active{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,z-index 0ms;z-index:2}.md-tooltip--inline{font-weight:400;-webkit-user-select:none;user-select:none;width:auto}.md-tooltip--inline:not(.md-tooltip--active){transform:translateY(.2rem) scale(.9)}.md-tooltip--inline .md-tooltip__inner{font-size:.55rem;padding:.2rem .4rem}[hidden]+.md-tooltip--inline{display:none}.focus-visible>.md-tooltip,.md-tooltip:target{outline:var(--md-accent-fg-color) auto}.md-tooltip__inner{font-size:.64rem;padding:.8rem}.md-tooltip__inner.md-typeset>:first-child{margin-top:0}.md-tooltip__inner.md-typeset>:last-child{margin-bottom:0}.md-annotation{font-style:normal;font-weight:400;outline:none;text-align:initial;vertical-align:text-bottom;white-space:normal}[dir=rtl] .md-annotation{direction:rtl}code .md-annotation{font-family:var(--md-code-font-family);font-size:inherit}.md-annotation:not([hidden]){display:inline-block;line-height:1.25}.md-annotation__index{border-radius:.01px;cursor:pointer;display:inline-block;margin-left:.4ch;margin-right:.4ch;outline:none;overflow:hidden;position:relative;-webkit-user-select:none;user-select:none;vertical-align:text-top;z-index:0}.md-annotation .md-annotation__index{transition:z-index .25s}@media screen{.md-annotation__index{width:2.2ch}[data-md-visible]>.md-annotation__index{animation:pulse 2s infinite}.md-annotation__index:before{background:var(--md-default-bg-color);-webkit-mask-image:var(--md-annotation-bg-icon);mask-image:var(--md-annotation-bg-icon)}.md-annotation__index:after,.md-annotation__index:before{content:"";height:2.2ch;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:-.1ch;width:2.2ch;z-index:-1}.md-annotation__index:after{background-color:var(--md-default-fg-color--lighter);-webkit-mask-image:var(--md-annotation-icon);mask-image:var(--md-annotation-icon);transform:scale(1.0001);transition:background-color .25s,transform .25s}.md-tooltip--active+.md-annotation__index:after{transform:rotate(45deg)}.md-tooltip--active+.md-annotation__index:after,:hover>.md-annotation__index:after{background-color:var(--md-accent-fg-color)}}.md-tooltip--active+.md-annotation__index{animation-play-state:paused;transition-duration:0ms;z-index:2}.md-annotation__index [data-md-annotation-id]{display:inline-block}@media print{.md-annotation__index [data-md-annotation-id]{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);font-weight:700;padding:0 .6ch;white-space:nowrap}.md-annotation__index [data-md-annotation-id]:after{content:attr(data-md-annotation-id)}}.md-typeset .md-annotation-list{counter-reset:annotation;list-style:none!important}.md-typeset .md-annotation-list li{position:relative}[dir=ltr] .md-typeset .md-annotation-list li:before{left:-2.125em}[dir=rtl] .md-typeset .md-annotation-list li:before{right:-2.125em}.md-typeset .md-annotation-list li:before{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);content:counter(annotation);counter-increment:annotation;font-size:.8875em;font-weight:700;height:2ch;line-height:1.25;min-width:2ch;padding:0 .6ch;position:absolute;text-align:center;top:.25em}:root{--md-tooltip-width:20rem;--md-tooltip-tail:0.3rem}.md-tooltip2{backface-visibility:hidden;color:var(--md-default-fg-color);font-family:var(--md-text-font-family);opacity:0;pointer-events:none;position:absolute;top:calc(var(--md-tooltip-host-y) + var(--md-tooltip-y));transform:translateY(.4rem);transform-origin:calc(var(--md-tooltip-host-x) + var(--md-tooltip-x)) 0;transition:transform 0ms .25s,opacity .25s,z-index .25s;width:100%;z-index:0}.md-tooltip2:before{border-left:var(--md-tooltip-tail) solid #0000;border-right:var(--md-tooltip-tail) solid #0000;content:"";display:block;left:clamp(1.5 * .8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-tail),100vw - 2 * var(--md-tooltip-tail) - 1.5 * .8rem);position:absolute;z-index:1}.md-tooltip2--top:before{border-top:var(--md-tooltip-tail) solid var(--md-default-bg-color);bottom:calc(var(--md-tooltip-tail)*-1 + .025rem);filter:drop-shadow(0 1px 0 var(--md-default-fg-color--lightest))}.md-tooltip2--bottom:before{border-bottom:var(--md-tooltip-tail) solid var(--md-default-bg-color);filter:drop-shadow(0 -1px 0 var(--md-default-fg-color--lightest));top:calc(var(--md-tooltip-tail)*-1 + .025rem)}.md-tooltip2[role=dialog]:after{content:"";display:block;height:.8rem;left:clamp(.8rem,var(--md-tooltip-host-x) - .8rem,100vw - var(--md-tooltip-width) - .8rem);pointer-events:auto;position:absolute;width:var(--md-tooltip-width);z-index:1}.md-tooltip2[role=dialog].md-tooltip2--top:after{top:100%}.md-tooltip2[role=dialog].md-tooltip2--bottom:after{bottom:100%}.md-tooltip2--active{opacity:1;transform:translateY(0);transition:transform .4s cubic-bezier(0,1,.35,1),opacity .25s,z-index 0ms;z-index:4}.md-tooltip2__inner{scrollbar-gutter:stable;background-color:var(--md-default-bg-color);border-radius:.4rem;box-shadow:var(--md-shadow-z2);left:clamp(.8rem,var(--md-tooltip-host-x) - .8rem,100vw - var(--md-tooltip-width) - .8rem);max-height:40vh;max-width:calc(100vw - 1.6rem);position:relative;scrollbar-width:thin}.md-tooltip2__inner::-webkit-scrollbar{height:.2rem;width:.2rem}.md-tooltip2__inner::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-tooltip2__inner::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}[role=dialog]>.md-tooltip2__inner{font-size:.64rem;overflow:auto;padding:0 .8rem;pointer-events:auto;width:var(--md-tooltip-width)}[role=dialog]>.md-tooltip2__inner:after,[role=dialog]>.md-tooltip2__inner:before{content:"";display:block;height:.8rem;position:sticky;width:100%;z-index:10}[role=dialog]>.md-tooltip2__inner:before{background:linear-gradient(var(--md-default-bg-color),#0000 75%);top:0}[role=dialog]>.md-tooltip2__inner:after{background:linear-gradient(#0000,var(--md-default-bg-color) 75%);bottom:0}[role=tooltip]>.md-tooltip2__inner{font-size:.55rem;font-weight:400;left:clamp(.8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-width)/2,100vw - var(--md-tooltip-width) - .8rem);max-width:min(100vw - 2 * .8rem,400px);padding:.2rem .4rem;-webkit-user-select:none;user-select:none;width:fit-content}.md-tooltip2__inner.md-typeset>:first-child{margin-top:0}.md-tooltip2__inner.md-typeset>:last-child{margin-bottom:0}[dir=ltr] .md-top{margin-left:50%}[dir=rtl] .md-top{margin-right:50%}.md-top{-webkit-backdrop-filter:blur(.4rem);backdrop-filter:blur(.4rem);background-color:var(--md-default-bg-color--light);border-radius:1.6rem;bottom:1.6rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);cursor:pointer;display:flex;font-size:.7rem;gap:.4rem;outline:none;padding:.5rem .9rem .5rem .7rem;position:fixed;top:auto!important;transform:translate(-50%);transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms;z-index:2}@media print{.md-top{display:none}}[dir=rtl] .md-top{transform:translate(50%)}.md-top[hidden]{opacity:0;pointer-events:none;transform:translate(-50%,.2rem);transition-duration:0ms}[dir=rtl] .md-top[hidden]{transform:translate(50%,.2rem)}.md-top:focus,.md-top:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top svg{display:inline-block;height:.9rem;vertical-align:-.5em;width:.9rem}.md-top svg.lucide{fill:#0000;stroke:currentcolor}@keyframes hoverfix{0%{pointer-events:none}}:root{--md-version-icon:url('data:image/svg+xml;charset=utf-8,\3c !--! Font Awesome Free 7.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2026 Fonticons, Inc.-->')}.md-version{flex-shrink:0;font-size:.8rem;height:2.4rem}[dir=ltr] .md-version__current{margin-left:1.4rem;margin-right:.4rem}[dir=rtl] .md-version__current{margin-left:.4rem;margin-right:1.4rem}.md-version__current{color:inherit;cursor:pointer;outline:none;position:relative;top:.05rem}[dir=ltr] .md-version__current:after{margin-left:.4rem}[dir=rtl] .md-version__current:after{margin-right:.4rem}.md-version__current:after{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-image:var(--md-version-icon);mask-image:var(--md-version-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.4rem}.md-version__alias{margin-left:.3rem;opacity:.7}.md-version__list{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);list-style-type:none;margin:.2rem .8rem;max-height:0;opacity:0;overflow:auto;padding:0;position:absolute;scroll-snap-type:y mandatory;top:.15rem;transition:max-height 0ms .5s,opacity .25s .25s;z-index:3}.md-version:focus-within .md-version__list,.md-version:hover .md-version__list{max-height:10rem;opacity:1;transition:max-height 0ms,opacity .25s}@media (hover:none),(pointer:coarse){.md-version:hover .md-version__list{animation:hoverfix .25s forwards}.md-version:focus-within .md-version__list{animation:none}}.md-version__item{line-height:1.8rem}[dir=ltr] .md-version__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-version__link{padding-left:1.2rem;padding-right:.6rem}.md-version__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:color .25s,background-color .25s;white-space:nowrap;width:100%}.md-version__link:focus,.md-version__link:hover{color:var(--md-accent-fg-color)}.md-version__link:focus{background-color:var(--md-default-fg-color--lightest)}html.glightbox-open{height:100%;overflow:initial}html .gslide .gslide-description,html .gslide .gslide-image img{background:var(--md-default-bg-color)}html .gslide .gslide-description{-webkit-user-select:text;user-select:text}html .gslide .gslide-title{color:var(--md-default-fg-color);font-size:.8rem;margin-bottom:.4rem;margin-top:0}html .gslide .gslide-desc{color:var(--md-default-fg-color--light);font-size:.7rem}:root{--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .admonition,.md-typeset details{background-color:#448aff1a;border-radius:.4rem;color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .8rem;page-break-inside:avoid}.md-typeset .admonition>*,.md-typeset details>*{box-sizing:border-box}.md-typeset .admonition .admonition,.md-typeset .admonition details,.md-typeset details .admonition,.md-typeset details details{margin-bottom:1em;margin-top:1em}.md-typeset .admonition .md-typeset__scrollwrap,.md-typeset details .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset .admonition .md-typeset__table,.md-typeset details .md-typeset__table{padding:0 .6rem}.md-typeset .admonition>.tabbed-set:only-child,.md-typeset details>.tabbed-set:only-child{margin-top:0}html .md-typeset .admonition>:last-child,html .md-typeset details>:last-child{margin-bottom:.6rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{padding-left:1.6rem;padding-right:.8rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{padding-left:.8rem;padding-right:1.6rem}.md-typeset .admonition-title,.md-typeset summary{font-weight:700;margin-bottom:1em;margin-top:.6rem;position:relative}[dir=ltr] .md-typeset .admonition-title:before,[dir=ltr] .md-typeset summary:before{left:0}[dir=rtl] .md-typeset .admonition-title:before,[dir=rtl] .md-typeset summary:before{right:0}.md-typeset .admonition-title:before,.md-typeset summary:before{background-color:#448aff;content:"";height:1rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.125em;width:1rem}.md-typeset .admonition.note,.md-typeset details.note{background-color:#448aff1a}.md-typeset .note>.admonition-title:before,.md-typeset .note>summary:before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note)}.md-typeset .note>.admonition-title:after,.md-typeset .note>summary:after{color:#448aff}.md-typeset .admonition.abstract,.md-typeset details.abstract{background-color:#00b0ff1a}.md-typeset .abstract>.admonition-title:before,.md-typeset .abstract>summary:before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract)}.md-typeset .abstract>.admonition-title:after,.md-typeset .abstract>summary:after{color:#00b0ff}.md-typeset .admonition.info,.md-typeset details.info{background-color:#00b8d41a}.md-typeset .info>.admonition-title:before,.md-typeset .info>summary:before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info)}.md-typeset .info>.admonition-title:after,.md-typeset .info>summary:after{color:#00b8d4}.md-typeset .admonition.tip,.md-typeset details.tip{background-color:#00bfa51a}.md-typeset .tip>.admonition-title:before,.md-typeset .tip>summary:before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip)}.md-typeset .tip>.admonition-title:after,.md-typeset .tip>summary:after{color:#00bfa5}.md-typeset .admonition.success,.md-typeset details.success{background-color:#00c8531a}.md-typeset .success>.admonition-title:before,.md-typeset .success>summary:before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success)}.md-typeset .success>.admonition-title:after,.md-typeset .success>summary:after{color:#00c853}.md-typeset .admonition.question,.md-typeset details.question{background-color:#64dd171a}.md-typeset .question>.admonition-title:before,.md-typeset .question>summary:before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question)}.md-typeset .question>.admonition-title:after,.md-typeset .question>summary:after{color:#64dd17}.md-typeset .admonition.warning,.md-typeset details.warning{background-color:#ff91001a}.md-typeset .warning>.admonition-title:before,.md-typeset .warning>summary:before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning)}.md-typeset .warning>.admonition-title:after,.md-typeset .warning>summary:after{color:#ff9100}.md-typeset .admonition.failure,.md-typeset details.failure{background-color:#ff52521a}.md-typeset .failure>.admonition-title:before,.md-typeset .failure>summary:before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure)}.md-typeset .failure>.admonition-title:after,.md-typeset .failure>summary:after{color:#ff5252}.md-typeset .admonition.danger,.md-typeset details.danger{background-color:#ff17441a}.md-typeset .danger>.admonition-title:before,.md-typeset .danger>summary:before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger)}.md-typeset .danger>.admonition-title:after,.md-typeset .danger>summary:after{color:#ff1744}.md-typeset .admonition.bug,.md-typeset details.bug{background-color:#f500571a}.md-typeset .bug>.admonition-title:before,.md-typeset .bug>summary:before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug)}.md-typeset .bug>.admonition-title:after,.md-typeset .bug>summary:after{color:#f50057}.md-typeset .admonition.example,.md-typeset details.example{background-color:#7c4dff1a}.md-typeset .example>.admonition-title:before,.md-typeset .example>summary:before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example)}.md-typeset .example>.admonition-title:after,.md-typeset .example>summary:after{color:#7c4dff}.md-typeset .admonition.quote,.md-typeset details.quote{background-color:#9e9e9e1a}.md-typeset .quote>.admonition-title:before,.md-typeset .quote>summary:before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote)}.md-typeset .quote>.admonition-title:after,.md-typeset .quote>summary:after{color:#9e9e9e}:root{--md-footnotes-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .footnote{color:var(--md-default-fg-color--light);font-size:.64rem}[dir=ltr] .md-typeset .footnote>ol{margin-left:0}[dir=rtl] .md-typeset .footnote>ol{margin-right:0}.md-typeset .footnote>ol>li{transition:color 125ms}.md-typeset .footnote>ol>li:target{color:var(--md-default-fg-color)}.md-typeset .footnote>ol>li:focus-within .footnote-backref{opacity:1;transform:translateY(0);transition:none}.md-typeset .footnote>ol>li:hover .footnote-backref,.md-typeset .footnote>ol>li:target .footnote-backref{opacity:1;transform:translateY(0)}.md-typeset .footnote>ol>li>:first-child{margin-top:0}.md-typeset .footnote-ref{font-size:.75em;font-weight:700;text-decoration:none}html .md-typeset .footnote-ref{outline-offset:.1rem}.md-typeset [id^="fnref:"]:target>.footnote-ref{outline:auto}.md-typeset .footnote-backref{color:var(--md-typeset-a-color);display:inline-block;font-size:0;opacity:0;transform:translateY(.25rem);transition:color .25s,transform .25s .25s,opacity 125ms .25s;vertical-align:text-bottom}@media print{.md-typeset .footnote-backref{color:var(--md-typeset-a-color);opacity:1;transform:translateY(0)}}[dir=rtl] .md-typeset .footnote-backref{transform:translateY(-.25rem)}.md-typeset .footnote-backref:hover{color:var(--md-accent-fg-color)}.md-typeset .footnote-backref:before{background-color:currentcolor;content:"";display:inline-block;height:.8rem;-webkit-mask-image:var(--md-footnotes-icon);mask-image:var(--md-footnotes-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.8rem}[dir=rtl] .md-typeset .footnote-backref:before{transform:scaleX(-1)}[dir=ltr] .md-typeset .headerlink{margin-left:.5rem}[dir=rtl] .md-typeset .headerlink{margin-right:.5rem}.md-typeset .headerlink{color:var(--md-default-fg-color--lighter);display:inline-block;opacity:0;text-decoration:none;transition:color .25s,opacity 125ms}@media print{.md-typeset .headerlink{display:none}}.md-typeset .headerlink:focus,.md-typeset :hover>.headerlink,.md-typeset :target>.headerlink{opacity:1;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset .headerlink:hover,.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset :target{--md-scroll-margin:3.6rem;--md-scroll-offset:0rem;scroll-margin-top:calc(var(--md-scroll-margin) - var(--md-scroll-offset))}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset :target{--md-scroll-margin:6rem}}.md-typeset h1:target{--md-scroll-offset:0.1rem}.md-typeset h3:target,.md-typeset h4:target{--md-scroll-offset:-0.1rem}:root{--md-admonition-icon--mkdocstrings:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--mkdocstrings-open:url('data:image/svg+xml;charset=utf-8,')}.doc-object-name{font-family:var(--md-code-font-family)}code.doc-symbol-heading{margin-right:.4rem;padding:0}[dir=ltr] .doc-labels{margin-left:.4rem}[dir=rtl] .doc-labels{margin-right:.4rem}.doc-label code{background:#0000;border:1px solid var(--md-default-fg-color--lightest);border-radius:.5rem;color:var(--md-default-fg-color--light);font-weight:400;padding-left:.3rem;padding-right:.3rem;vertical-align:text-bottom}.doc-contents td code{word-break:normal!important}.doc-md-description,.doc-md-description>p:first-child{display:inline}.md-typeset h5 .doc-object-name{text-transform:none}.doc .md-typeset__table,.doc .md-typeset__table table{display:table!important;width:100%}.doc .md-typeset__table tr{display:table-row}.doc-param-default,.doc-type_param-default{float:right}.doc-heading-parameter,.doc-heading-type_parameter{display:inline}.md-typeset .doc-heading-parameter{font-size:inherit}.doc-heading-parameter .headerlink,.doc-heading-type_parameter .headerlink{margin-left:0!important;margin-right:.2rem}.doc-section-title{font-weight:700}.doc-signature .autorefs{color:inherit;text-decoration-style:dotted}div.doc-contents:not(.first){border-left:.05rem solid var(--md-code-bg-color);margin-left:.4rem;padding-left:.8rem}:host,:root,[data-md-color-scheme=default]{--doc-symbol-parameter-fg-color:#829bd1;--doc-symbol-type_parameter-fg-color:#829bd1;--doc-symbol-attribute-fg-color:#953800;--doc-symbol-function-fg-color:#8250df;--doc-symbol-method-fg-color:#8250df;--doc-symbol-class-fg-color:#0550ae;--doc-symbol-type_alias-fg-color:#0550ae;--doc-symbol-module-fg-color:#5cad0f}[data-md-color-scheme=slate]{--doc-symbol-parameter-fg-color:#829bd1;--doc-symbol-type_parameter-fg-color:#829bd1;--doc-symbol-attribute-fg-color:#ffa657;--doc-symbol-function-fg-color:#d2a8ff;--doc-symbol-method-fg-color:#d2a8ff;--doc-symbol-class-fg-color:#79c0ff;--doc-symbol-type_alias-fg-color:#79c0ff;--doc-symbol-module-fg-color:#baff79}.md-ellipsis:has(.doc-symbol){font-family:var(--md-code-font-family);font-size:.95em}code.doc-symbol{background-color:initial;border-radius:.1rem;font-size:1em;font-weight:400}a code.doc-symbol-parameter,code.doc-symbol-parameter{color:var(--doc-symbol-parameter-fg-color)}.md-content code.doc-symbol-parameter:after{content:"param"}.md-sidebar code.doc-symbol-parameter:after{content:"p"}a code.doc-symbol-type_parameter,code.doc-symbol-type_parameter{color:var(--doc-symbol-type_parameter-fg-color)}.md-content code.doc-symbol-type_parameter:after{content:"type-param"}.md-sidebar code.doc-symbol-type_parameter:after{content:"t"}a code.doc-symbol-attribute,code.doc-symbol-attribute{color:var(--doc-symbol-attribute-fg-color)}.md-content code.doc-symbol-attribute:after{content:"attribute"}.md-sidebar code.doc-symbol-attribute:after{content:"a"}a code.doc-symbol-function,code.doc-symbol-function{color:var(--doc-symbol-function-fg-color)}.md-content code.doc-symbol-function:after{content:"function"}.md-sidebar code.doc-symbol-function:after{content:"f"}a code.doc-symbol-method,code.doc-symbol-method{color:var(--doc-symbol-method-fg-color)}.md-content code.doc-symbol-method:after{content:"method"}.md-sidebar code.doc-symbol-method:after{content:"m"}a code.doc-symbol-class,code.doc-symbol-class{color:var(--doc-symbol-class-fg-color)}.md-content code.doc-symbol-class:after{content:"class"}.md-sidebar code.doc-symbol-class:after{content:"c"}a code.doc-symbol-type_alias,code.doc-symbol-type_alias{color:var(--doc-symbol-type_alias-fg-color)}.md-content code.doc-symbol-type_alias:after{content:"type"}.md-sidebar code.doc-symbol-type_alias:after{content:"t"}a code.doc-symbol-module,code.doc-symbol-module{color:var(--doc-symbol-module-fg-color)}.md-content code.doc-symbol-module:after{content:"module"}.md-sidebar code.doc-symbol-module:after{content:"mod"}.md-typeset details.mkdocstrings-source{background:#0000;border:.05rem solid var(--md-code-bg-color)}.md-typeset details.mkdocstrings-source>summary:before{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-admonition-icon--mkdocstrings);mask-image:var(--md-admonition-icon--mkdocstrings)}.md-typeset details.mkdocstrings-source[open]>summary:before{-webkit-mask-image:var(--md-admonition-icon--mkdocstrings-open);mask-image:var(--md-admonition-icon--mkdocstrings-open)}.md-typeset details.mkdocstrings-source>summary:after{background-color:var(--md-default-fg-color--light)}.md-typeset div.arithmatex{overflow:auto}@media screen and (max-width:44.984375em){.md-typeset div.arithmatex{margin:0 -.8rem}.md-typeset div.arithmatex>*{width:min-content}}.md-typeset div.arithmatex>*{margin-left:auto!important;margin-right:auto!important;padding:0 .8rem;touch-action:auto}.md-typeset div.arithmatex>* mjx-container{margin:0!important}.md-typeset div.arithmatex mjx-assistive-mml{height:0}.md-typeset del.critic{background-color:var(--md-typeset-del-color)}.md-typeset del.critic,.md-typeset ins.critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset ins.critic{background-color:var(--md-typeset-ins-color)}.md-typeset .critic.comment{-webkit-box-decoration-break:clone;box-decoration-break:clone;color:var(--md-code-hl-comment-color)}.md-typeset .critic.comment:before{content:"/* "}.md-typeset .critic.comment:after{content:" */"}.md-typeset .critic.block{box-shadow:none;display:block;margin:1em 0;overflow:auto;padding-left:.8rem;padding-right:.8rem}.md-typeset .critic.block>:first-child{margin-top:.5em}.md-typeset .critic.block>:last-child{margin-bottom:.5em}:root{--md-details-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset details{display:flow-root;overflow:visible;padding-top:0}.md-typeset details[open]>summary:after{transform:rotate(90deg)}.md-typeset details:not([open]){box-shadow:none;padding-bottom:0}.md-typeset details:not([open])>summary{border-radius:.1rem;margin-bottom:.6rem}[dir=ltr] .md-typeset summary{padding-right:1.6rem}[dir=rtl] .md-typeset summary{padding-left:1.6rem}[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset summary{cursor:pointer;display:block;min-height:1rem;overflow:hidden}.md-typeset summary.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset summary:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[dir=ltr] .md-typeset summary:after{right:0}[dir=rtl] .md-typeset summary:after{left:0}.md-typeset summary:after{background-color:currentcolor;content:"";height:1rem;-webkit-mask-image:var(--md-details-icon);mask-image:var(--md-details-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.125em;transform:rotate(0deg);transition:transform .25s;width:1rem}[dir=rtl] .md-typeset summary:after{transform:rotate(180deg)}.md-typeset summary::marker{display:none}.md-typeset summary::-webkit-details-marker{display:none}.md-typeset .emojione,.md-typeset .gemoji,.md-typeset .twemoji{--md-icon-size:1.125em;display:inline-flex;height:var(--md-icon-size);vertical-align:text-top}.md-typeset .emojione svg,.md-typeset .gemoji svg,.md-typeset .twemoji svg{fill:currentcolor;max-height:100%;width:var(--md-icon-size)}.md-typeset .emojione svg.lucide,.md-typeset .gemoji svg.lucide,.md-typeset .twemoji svg.lucide{fill:#0000;stroke:currentcolor}.md-typeset .lg,.md-typeset .xl,.md-typeset .xxl,.md-typeset .xxxl{vertical-align:text-bottom}.md-typeset .middle{vertical-align:middle}.md-typeset .lg{--md-icon-size:1.5em}.md-typeset .xl{--md-icon-size:2.25em}.md-typeset .xxl{--md-icon-size:3em}.md-typeset .xxxl{--md-icon-size:4em}.highlight .o,.highlight .ow{color:var(--md-code-hl-operator-color)}.highlight .p{color:var(--md-code-hl-punctuation-color)}.highlight .cpf,.highlight .l,.highlight .s,.highlight .s1,.highlight .s2,.highlight .sb,.highlight .sc,.highlight .si,.highlight .ss{color:var(--md-code-hl-string-color)}.highlight .cp,.highlight .se,.highlight .sh,.highlight .sr,.highlight .sx{color:var(--md-code-hl-special-color)}.highlight .il,.highlight .m,.highlight .mb,.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:var(--md-code-hl-number-color)}.highlight .k,.highlight .kd,.highlight .kn,.highlight .kp,.highlight .kr,.highlight .kt{color:var(--md-code-hl-keyword-color)}.highlight .kc,.highlight .n{color:var(--md-code-hl-name-color)}.highlight .bp,.highlight .nb,.highlight .no{color:var(--md-code-hl-constant-color)}.highlight .nc,.highlight .ne,.highlight .nf,.highlight .nn{color:var(--md-code-hl-function-color)}.highlight .nd,.highlight .ni,.highlight .nl,.highlight .nt{color:var(--md-code-hl-keyword-color)}.highlight .c,.highlight .c1,.highlight .ch,.highlight .cm,.highlight .cs,.highlight .sd{color:var(--md-code-hl-comment-color)}.highlight .na,.highlight .nv,.highlight .vc,.highlight .vg,.highlight .vi{color:var(--md-code-hl-variable-color)}.highlight .ge,.highlight .gh,.highlight .go,.highlight .gp,.highlight .gr,.highlight .gs,.highlight .gt,.highlight .gu{color:var(--md-code-hl-generic-color)}.highlight .gd,.highlight .gi{border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight .gd{background-color:var(--md-typeset-del-color)}.highlight .gi{background-color:var(--md-typeset-ins-color)}.highlight .hll{background-color:var(--md-code-hl-color--light);box-shadow:2px 0 0 0 var(--md-code-hl-color) inset;display:block;margin:0 -1.1764705882em;padding:0 1.1764705882em}.highlight span.filename{background-color:var(--md-code-bg-color);border-bottom:.05rem solid var(--md-default-fg-color--lightest);border-top-left-radius:.4rem;border-top-right-radius:.4rem;display:flow-root;font-size:.85em;font-weight:700;margin-top:1em;padding:.6617647059em 1.1764705882em;position:relative}.highlight span.filename+pre{margin-top:0}.highlight span.filename+pre>code{border-top-left-radius:0;border-top-right-radius:0}.highlight [data-linenos]:before{background-color:var(--md-code-bg-color);box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;color:var(--md-default-fg-color--light);content:attr(data-linenos);float:left;left:-1.1764705882em;margin-left:-1.1764705882em;margin-right:1.1764705882em;padding-left:1.1764705882em;position:sticky;-webkit-user-select:none;user-select:none;z-index:3}.highlight code>span[id^=__span]>:last-child .md-annotation{margin-right:2.4rem}.highlight code[data-md-copying]{display:initial}.highlight code[data-md-copying] .hll{display:contents}.highlight code[data-md-copying] .md-annotation{display:none}.highlighttable{display:flow-root}.highlighttable tbody,.highlighttable td{display:block;padding:0}.highlighttable tr{display:flex}.highlighttable pre{margin:0}.highlighttable th.filename{flex-grow:1;padding:0;text-align:left}.highlighttable th.filename span.filename{margin-top:0}.highlighttable .linenos{background-color:var(--md-code-bg-color);border-bottom-left-radius:.4rem;border-top-left-radius:.4rem;font-size:.85em;padding:.7720588235em 0 .7720588235em 1.1764705882em;-webkit-user-select:none;user-select:none}.highlighttable .linenodiv{box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset}.highlighttable .linenodiv pre{color:var(--md-default-fg-color--light);text-align:right}.highlighttable .linenodiv span[class]{padding-right:.5882352941em}.highlighttable .code{flex:1;min-width:0}.linenodiv a{color:inherit;text-decoration:none}.md-typeset .highlighttable{direction:ltr;margin:1em 0}.md-typeset .highlighttable>tbody>tr>.code>div>pre>code{border-bottom-left-radius:0;border-top-left-radius:0}.md-typeset .highlight+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.4rem;border-bottom-right-radius:.4rem;border-top-width:.4rem;margin-top:-1.5em;overflow:visible;padding:0 1em}.md-typeset .highlight+.result:after{clear:both;content:"";display:block}@media screen and (max-width:44.984375em){.md-content__inner>.highlight{margin:1em -.8rem}.md-content__inner>.highlight>.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.code>div>pre>code,.md-content__inner>.highlight>.highlighttable>tbody>tr>.filename span.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.linenos,.md-content__inner>.highlight>pre>code{border-radius:0}.md-content__inner>.highlight+.result{border-left-width:0;border-radius:0;border-right-width:0;margin-left:-.8rem;margin-right:-.8rem}}.md-typeset .keys kbd:after,.md-typeset .keys kbd:before{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys span{color:var(--md-default-fg-color--light);padding:0 .2em}.md-typeset .keys .key-alt:before,.md-typeset .keys .key-left-alt:before,.md-typeset .keys .key-right-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-command:before,.md-typeset .keys .key-left-command:before,.md-typeset .keys .key-right-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-control:before,.md-typeset .keys .key-left-control:before,.md-typeset .keys .key-right-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-left-meta:before,.md-typeset .keys .key-meta:before,.md-typeset .keys .key-right-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-left-option:before,.md-typeset .keys .key-option:before,.md-typeset .keys .key-right-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-left-shift:before,.md-typeset .keys .key-right-shift:before,.md-typeset .keys .key-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-left-super:before,.md-typeset .keys .key-right-super:before,.md-typeset .keys .key-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-left-windows:before,.md-typeset .keys .key-right-windows:before,.md-typeset .keys .key-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-arrow-down:before{content:"↓";padding-right:.4em}.md-typeset .keys .key-arrow-left:before{content:"←";padding-right:.4em}.md-typeset .keys .key-arrow-right:before{content:"→";padding-right:.4em}.md-typeset .keys .key-arrow-up:before{content:"↑";padding-right:.4em}.md-typeset .keys .key-backspace:before{content:"⌫";padding-right:.4em}.md-typeset .keys .key-backtab:before{content:"⇤";padding-right:.4em}.md-typeset .keys .key-caps-lock:before{content:"⇪";padding-right:.4em}.md-typeset .keys .key-clear:before{content:"⌧";padding-right:.4em}.md-typeset .keys .key-context-menu:before{content:"☰";padding-right:.4em}.md-typeset .keys .key-delete:before{content:"⌦";padding-right:.4em}.md-typeset .keys .key-eject:before{content:"⏏";padding-right:.4em}.md-typeset .keys .key-end:before{content:"⤓";padding-right:.4em}.md-typeset .keys .key-escape:before{content:"⎋";padding-right:.4em}.md-typeset .keys .key-home:before{content:"⤒";padding-right:.4em}.md-typeset .keys .key-insert:before{content:"⎀";padding-right:.4em}.md-typeset .keys .key-page-down:before{content:"⇟";padding-right:.4em}.md-typeset .keys .key-page-up:before{content:"⇞";padding-right:.4em}.md-typeset .keys .key-print-screen:before{content:"⎙";padding-right:.4em}.md-typeset .keys .key-tab:after{content:"⇥";padding-left:.4em}.md-typeset .keys .key-num-enter:after{content:"⌤";padding-left:.4em}.md-typeset .keys .key-enter:after{content:"⏎";padding-left:.4em}:root{--md-tabbed-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-tabbed-icon--next:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .tabbed-set{border-radius:.075rem;display:flex;flex-flow:column wrap;margin:1em 0;position:relative}.md-typeset .tabbed-set>input{height:0;opacity:0;position:absolute;width:0}.md-typeset .tabbed-set>input:target{--md-scroll-offset:0.625em}.md-typeset .tabbed-set>input.focus-visible~.tabbed-labels:before{background-color:var(--md-accent-fg-color)}.md-typeset .tabbed-labels{-ms-overflow-style:none;box-shadow:0 -.05rem var(--md-default-fg-color--lightest) inset;display:flex;max-width:100%;overflow:auto;scrollbar-width:none}@media print{.md-typeset .tabbed-labels{display:contents}}@media screen{.js .md-typeset .tabbed-labels{position:relative}.js .md-typeset .tabbed-labels:before{background:var(--md-default-fg-color);bottom:0;content:"";display:block;height:1.5px;left:0;position:absolute;transform:translateX(var(--md-indicator-x));transition:width 225ms,background-color .25s,transform .25s;transition-timing-function:cubic-bezier(.4,0,.2,1);width:var(--md-indicator-width)}}.md-typeset .tabbed-labels::-webkit-scrollbar{display:none}.md-typeset .tabbed-labels>label{border-bottom:.1rem solid #0000;border-radius:.1rem .1rem 0 0;color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;font-size:.7rem;font-weight:400;padding:.78125em 1.25em .625em;scroll-margin-inline-start:1rem;transition:background-color .25s,color .25s;white-space:nowrap;width:auto}@media print{.md-typeset .tabbed-labels>label:first-child{order:1}.md-typeset .tabbed-labels>label:nth-child(2){order:2}.md-typeset .tabbed-labels>label:nth-child(3){order:3}.md-typeset .tabbed-labels>label:nth-child(4){order:4}.md-typeset .tabbed-labels>label:nth-child(5){order:5}.md-typeset .tabbed-labels>label:nth-child(6){order:6}.md-typeset .tabbed-labels>label:nth-child(7){order:7}.md-typeset .tabbed-labels>label:nth-child(8){order:8}.md-typeset .tabbed-labels>label:nth-child(9){order:9}.md-typeset .tabbed-labels>label:nth-child(10){order:10}.md-typeset .tabbed-labels>label:nth-child(11){order:11}.md-typeset .tabbed-labels>label:nth-child(12){order:12}.md-typeset .tabbed-labels>label:nth-child(13){order:13}.md-typeset .tabbed-labels>label:nth-child(14){order:14}.md-typeset .tabbed-labels>label:nth-child(15){order:15}.md-typeset .tabbed-labels>label:nth-child(16){order:16}.md-typeset .tabbed-labels>label:nth-child(17){order:17}.md-typeset .tabbed-labels>label:nth-child(18){order:18}.md-typeset .tabbed-labels>label:nth-child(19){order:19}.md-typeset .tabbed-labels>label:nth-child(20){order:20}}.md-typeset .tabbed-labels>label:hover{color:var(--md-default-fg-color)}.md-typeset .tabbed-labels>label>[href]:first-child{color:inherit;text-decoration:none}.md-typeset .tabbed-labels--linked>label{padding:0}.md-typeset .tabbed-labels--linked>label>a{display:block;padding:.78125em 1.25em .625em}.md-typeset .tabbed-content{width:100%}@media print{.md-typeset .tabbed-content{display:contents}}.md-typeset .tabbed-block{display:none}@media print{.md-typeset .tabbed-block{display:block}.md-typeset .tabbed-block:first-child{order:1}.md-typeset .tabbed-block:nth-child(2){order:2}.md-typeset .tabbed-block:nth-child(3){order:3}.md-typeset .tabbed-block:nth-child(4){order:4}.md-typeset .tabbed-block:nth-child(5){order:5}.md-typeset .tabbed-block:nth-child(6){order:6}.md-typeset .tabbed-block:nth-child(7){order:7}.md-typeset .tabbed-block:nth-child(8){order:8}.md-typeset .tabbed-block:nth-child(9){order:9}.md-typeset .tabbed-block:nth-child(10){order:10}.md-typeset .tabbed-block:nth-child(11){order:11}.md-typeset .tabbed-block:nth-child(12){order:12}.md-typeset .tabbed-block:nth-child(13){order:13}.md-typeset .tabbed-block:nth-child(14){order:14}.md-typeset .tabbed-block:nth-child(15){order:15}.md-typeset .tabbed-block:nth-child(16){order:16}.md-typeset .tabbed-block:nth-child(17){order:17}.md-typeset .tabbed-block:nth-child(18){order:18}.md-typeset .tabbed-block:nth-child(19){order:19}.md-typeset .tabbed-block:nth-child(20){order:20}}.md-typeset .tabbed-block>.highlight:first-child>pre,.md-typeset .tabbed-block>pre:first-child{margin:0}.md-typeset .tabbed-block>.highlight:first-child>pre>code,.md-typeset .tabbed-block>pre:first-child>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child>.filename{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable{margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.filename span.filename,.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.linenos{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.code>div>pre>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child+.result{margin-top:-.125em}.md-typeset .tabbed-block>.tabbed-set{margin:0}.md-typeset .tabbed-button{align-self:center;-webkit-backdrop-filter:blur(.4rem);backdrop-filter:blur(.4rem);background-color:var(--md-default-bg-color--light);border-radius:100%;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);cursor:pointer;display:block;height:.9rem;margin-top:.4rem;pointer-events:auto;transition:transform 125ms;width:.9rem}.md-typeset .tabbed-button:hover{transform:scale(1.125)}.md-typeset .tabbed-button:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-tabbed-icon--prev);mask-image:var(--md-tabbed-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color .25s,transform .25s;width:100%}.md-typeset .tabbed-control{display:flex;height:1.9rem;justify-content:start;pointer-events:none;position:absolute;transition:opacity 125ms;width:1.2rem}[dir=rtl] .md-typeset .tabbed-control{transform:rotate(180deg)}.md-typeset .tabbed-control[hidden]{opacity:0}.md-typeset .tabbed-control--next{justify-content:end;right:0}.md-typeset .tabbed-control--next .tabbed-button:after{-webkit-mask-image:var(--md-tabbed-icon--next);mask-image:var(--md-tabbed-icon--next)}@media screen and (max-width:44.984375em){[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels{margin:0 -.8rem;max-width:100vw;scroll-padding-inline-start:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels:after{content:""}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-right:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-left:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-right:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{width:2rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-left:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-right:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-left:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{width:2rem}}@media screen{.md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){color:var(--md-default-fg-color);font-weight:500}.md-typeset .no-js .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .no-js .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .no-js .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .no-js .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .no-js .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .no-js .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .no-js .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .no-js .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .no-js .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .no-js .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .no-js .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .no-js .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .no-js .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .no-js .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .no-js .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .no-js .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .no-js .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .no-js .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .no-js .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .no-js .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.md-typeset [role=dialog] .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset [role=dialog] .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset [role=dialog] .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset [role=dialog] .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset [role=dialog] .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset [role=dialog] .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset [role=dialog] .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset [role=dialog] .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset [role=dialog] .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset [role=dialog] .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset [role=dialog] .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset [role=dialog] .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset [role=dialog] .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset [role=dialog] .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset [role=dialog] .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset [role=dialog] .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset [role=dialog] .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset [role=dialog] .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset [role=dialog] .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset [role=dialog] .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.no-js .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.no-js .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.no-js .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.no-js .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.no-js .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.no-js .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.no-js .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.no-js .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.no-js .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.no-js .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.no-js .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.no-js .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.no-js .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.no-js .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.no-js .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.no-js .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.no-js .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.no-js .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.no-js .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.no-js .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),[role=dialog] .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,[role=dialog] .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),[role=dialog] .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),[role=dialog] .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),[role=dialog] .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),[role=dialog] .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),[role=dialog] .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),[role=dialog] .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),[role=dialog] .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),[role=dialog] .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),[role=dialog] .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),[role=dialog] .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),[role=dialog] .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),[role=dialog] .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),[role=dialog] .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),[role=dialog] .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),[role=dialog] .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),[role=dialog] .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),[role=dialog] .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),[role=dialog] .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){border-color:var(--md-default-fg-color)}}.md-typeset .tabbed-set>input:first-child.focus-visible~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10).focus-visible~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11).focus-visible~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12).focus-visible~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13).focus-visible~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14).focus-visible~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15).focus-visible~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16).focus-visible~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17).focus-visible~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18).focus-visible~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19).focus-visible~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2).focus-visible~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20).focus-visible~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3).focus-visible~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4).focus-visible~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5).focus-visible~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6).focus-visible~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7).focus-visible~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8).focus-visible~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9).focus-visible~.tabbed-labels>:nth-child(9){color:var(--md-accent-fg-color)}.md-typeset .tabbed-set>input:first-child:checked~.tabbed-content>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-content>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-content>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-content>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-content>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-content>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-content>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-content>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-content>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-content>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-content>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-content>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-content>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-content>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-content>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-content>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-content>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-content>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-content>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-content>:nth-child(9){display:block}:root{--md-tasklist-icon:url('data:image/svg+xml;charset=utf-8,');--md-tasklist-icon--checked:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .task-list-item{list-style-type:none;position:relative}[dir=ltr] .md-typeset .task-list-item [type=checkbox]{left:-2em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{right:-2em}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}[dir=ltr] .md-typeset .task-list-indicator:before{left:-1.5em}[dir=rtl] .md-typeset .task-list-indicator:before{right:-1.5em}.md-typeset .task-list-indicator:before{background-color:var(--md-default-fg-color--lighter);content:"";height:1.25em;-webkit-mask-image:var(--md-tasklist-icon);mask-image:var(--md-tasklist-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.25em;width:1.25em}.md-typeset [type=checkbox]:checked+.task-list-indicator:before{background-color:#00e676;-webkit-mask-image:var(--md-tasklist-icon--checked);mask-image:var(--md-tasklist-icon--checked)}@media print{.giscus,[id=__comments]{display:none}}:root>*{--md-mermaid-font-family:var(--md-text-font-family),sans-serif;--md-mermaid-edge-color:var(--md-code-fg-color);--md-mermaid-node-bg-color:var(--md-accent-fg-color--transparent);--md-mermaid-node-fg-color:var(--md-accent-fg-color);--md-mermaid-label-bg-color:var(--md-default-bg-color);--md-mermaid-label-fg-color:var(--md-code-fg-color);--md-mermaid-sequence-actor-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actor-fg-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-actor-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-actor-line-color:var(--md-default-fg-color--lighter);--md-mermaid-sequence-actorman-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actorman-line-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-box-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-box-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-label-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-label-fg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-loop-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-loop-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-loop-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-message-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-message-line-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-note-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-border-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-number-bg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-number-fg-color:var(--md-accent-bg-color)}.mermaid{line-height:normal;margin:1em 0}.md-typeset .grid{grid-gap:.4rem;display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,16rem),1fr));margin:1em 0}.md-typeset .grid.cards>ol,.md-typeset .grid.cards>ul{display:contents}.md-typeset .grid.cards>ol>li,.md-typeset .grid.cards>ul>li,.md-typeset .grid>.card{border:.05rem solid var(--md-default-fg-color--lightest);border-radius:.4rem;display:block;margin:0;padding:.8rem;transition:background-color .25s,border .25s,box-shadow .25s}.md-typeset .grid.cards>ol>li:focus-within,.md-typeset .grid.cards>ol>li:hover,.md-typeset .grid.cards>ul>li:focus-within,.md-typeset .grid.cards>ul>li:hover,.md-typeset .grid>.card:focus-within,.md-typeset .grid>.card:hover{border-color:#0000;box-shadow:var(--md-shadow-z2)}.md-typeset .grid.cards>ol>li>hr,.md-typeset .grid.cards>ul>li>hr,.md-typeset .grid>.card>hr{margin-bottom:1em;margin-top:1em}.md-typeset .grid.cards>ol>li>:first-child,.md-typeset .grid.cards>ul>li>:first-child,.md-typeset .grid>.card>:first-child{margin-top:0}.md-typeset .grid.cards>ol>li>:last-child,.md-typeset .grid.cards>ul>li>:last-child,.md-typeset .grid>.card>:last-child{margin-bottom:0}.md-typeset .grid>*,.md-typeset .grid>.admonition,.md-typeset .grid>.highlight>*,.md-typeset .grid>.highlighttable,.md-typeset .grid>.md-typeset details,.md-typeset .grid>details,.md-typeset .grid>pre{margin-bottom:0;margin-top:0}.md-typeset .grid>.highlight>pre:only-child,.md-typeset .grid>.highlight>pre>code,.md-typeset .grid>.highlighttable,.md-typeset .grid>.highlighttable>tbody,.md-typeset .grid>.highlighttable>tbody>tr,.md-typeset .grid>.highlighttable>tbody>tr>.code,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre>code{height:100%}.md-typeset .grid>.tabbed-set{margin-bottom:0;margin-top:0}@media screen and (min-width:45em){[dir=ltr] .md-typeset .inline{float:left}[dir=rtl] .md-typeset .inline{float:right}[dir=ltr] .md-typeset .inline{margin-right:.8rem}[dir=rtl] .md-typeset .inline{margin-left:.8rem}.md-typeset .inline{margin-bottom:.8rem;margin-top:0;width:11.7rem}[dir=ltr] .md-typeset .inline.end{float:right}[dir=rtl] .md-typeset .inline.end{float:left}[dir=ltr] .md-typeset .inline.end{margin-left:.8rem;margin-right:0}[dir=rtl] .md-typeset .inline.end{margin-left:0;margin-right:.8rem}} \ No newline at end of file diff --git a/site/assets/stylesheets/modern/main.53a7feaf.min.css b/site/assets/stylesheets/modern/main.53a7feaf.min.css new file mode 100644 index 000000000..04e34a21a --- /dev/null +++ b/site/assets/stylesheets/modern/main.53a7feaf.min.css @@ -0,0 +1 @@ +@charset "UTF-8";html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;box-sizing:border-box}*,:after,:before{box-sizing:inherit}@media (prefers-reduced-motion){*,:after,:before{transition:none!important}}body{margin:0}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}hr{border:0;box-sizing:initial;display:block;height:.05rem;overflow:visible;padding:0}small{font-size:80%}sub,sup{line-height:1em}img{border-style:none}table{border-collapse:initial;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{background:#0000;border:0;font-family:inherit;font-size:inherit;margin:0;padding:0}input{border:0;outline:none}:root{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:#ffffffb3;--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:#526cfe1a;--md-accent-bg-color:#fff;--md-accent-bg-color--light:#ffffffb3}[data-md-color-scheme=default]{color-scheme:light}[data-md-color-scheme=default] img[src$="#gh-dark-mode-only"],[data-md-color-scheme=default] img[src$="#only-dark"]{display:none}:root,[data-md-color-scheme=default]{--md-hue:225deg;--md-default-fg-color:#000000de;--md-default-fg-color--light:#0000008c;--md-default-fg-color--lighter:#00000052;--md-default-fg-color--lightest:#0000000d;--md-default-bg-color:#fff;--md-default-bg-color--light:#ffffffb3;--md-default-bg-color--lighter:#ffffff4d;--md-default-bg-color--lightest:#ffffff1f;--md-code-fg-color:#36464e;--md-code-bg-color:#f5f5f5;--md-code-bg-color--light:#f5f5f5b3;--md-code-bg-color--lighter:#f5f5f54d;--md-code-hl-color:#4287ff;--md-code-hl-color--light:#4287ff1a;--md-code-hl-number-color:#d52a2a;--md-code-hl-special-color:#db1457;--md-code-hl-function-color:#a846b9;--md-code-hl-constant-color:#6e59d9;--md-code-hl-keyword-color:#3f6ec6;--md-code-hl-string-color:#1c7d4d;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-del-color:#f5503d26;--md-typeset-ins-color:#0bd57026;--md-typeset-kbd-color:#fafafa;--md-typeset-kbd-accent-color:#fff;--md-typeset-kbd-border-color:#b8b8b8;--md-typeset-mark-color:#ffff0080;--md-typeset-table-color:#0000001f;--md-typeset-table-color--light:rgba(0,0,0,.035);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-warning-fg-color:#000000de;--md-warning-bg-color:#ff9;--md-shadow-z1:0 0.2rem 0.5rem #0000000d,0 0 0.05rem #0000001a;--md-shadow-z2:0 0.2rem 0.5rem #0000001a,0 0 0.05rem #00000040;--md-shadow-z3:0 0.2rem 0.5rem #0003,0 0 0.05rem #00000059;--color-foreground:0 0 0;--color-background:255 255 255;--color-background-subtle:240 240 240;--color-backdrop:255 255 255}.md-icon svg{fill:currentcolor;display:block;height:1.2rem;width:1.2rem}.md-icon svg.lucide{fill:#0000;stroke:currentcolor}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--md-text-font-family:var(--md-text-font,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif;--md-code-font-family:var(--md-code-font,_),SFMono-Regular,Consolas,Menlo,monospace}aside,body,input{font-feature-settings:"kern","liga";color:var(--md-typeset-color);font-family:var(--md-text-font-family)}code,kbd,pre{font-feature-settings:"kern";font-family:var(--md-code-font-family)}:root{--md-typeset-table-sort-icon:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--asc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--desc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-preview-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset{-webkit-print-color-adjust:exact;color-adjust:exact;font-size:.75rem;letter-spacing:-.01em;line-height:1.8;overflow-wrap:break-word}@media print{.md-typeset{font-size:.68rem}}.md-typeset blockquote,.md-typeset dl,.md-typeset figure,.md-typeset ol,.md-typeset pre,.md-typeset ul{margin-bottom:1em;margin-top:1em}.md-typeset h1{color:var(--md-default-fg-color);font-size:1.875em;line-height:1.3;margin:0 0 1.25em}.md-typeset h1,.md-typeset h2{font-weight:700;letter-spacing:-.025em}.md-typeset h2{font-size:1.5em;line-height:1.4;margin:1.6em 0 .64em}.md-typeset h3{font-size:1.25em;font-weight:700;letter-spacing:-.01em;line-height:1.5;margin:1.6em 0 .8em}.md-typeset h2+h3{margin-top:.8em}.md-typeset h4{font-weight:700;letter-spacing:-.01em;margin:1em 0}.md-typeset h5,.md-typeset h6{color:var(--md-default-fg-color--light);font-size:.8em;font-weight:700;letter-spacing:-.01em;margin:1.25em 0}.md-typeset h5{text-transform:uppercase}.md-typeset h5 code{text-transform:none}.md-typeset hr{border-bottom:.05rem solid var(--md-default-fg-color--lightest);display:flow-root;margin:1.5em 0}.md-typeset a{color:var(--md-typeset-a-color);text-decoration:underline;word-break:break-word}.md-typeset a,.md-typeset a:before{transition:color 125ms}.md-typeset a:focus,.md-typeset a:hover{color:var(--md-accent-fg-color)}.md-typeset a:focus code,.md-typeset a:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset a code{color:var(--md-typeset-a-color)}.md-typeset a.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset code,.md-typeset kbd,.md-typeset pre{color:var(--md-code-fg-color);direction:ltr;font-variant-ligatures:none;transition:background-color 125ms}@media print{.md-typeset code,.md-typeset kbd,.md-typeset pre{white-space:pre-wrap}}.md-typeset code{background-color:var(--md-code-bg-color);border-radius:.2rem;-webkit-box-decoration-break:clone;box-decoration-break:clone;font-size:.85em;padding:.25em .4em;transition:color 125ms,background-color 125ms;word-break:break-word}.md-typeset code:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset pre{display:flow-root;line-height:1.4;position:relative}.md-typeset pre>code{border-radius:.4rem;-webkit-box-decoration-break:slice;box-decoration-break:slice;box-shadow:none;display:block;margin:0;outline-color:var(--md-accent-fg-color);overflow:auto;padding:.7720588235em 1.1764705882em;scrollbar-color:var(--md-default-fg-color--lighter) #0000;scrollbar-width:thin;touch-action:auto;word-break:normal}.md-typeset pre>code:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-typeset pre>code::-webkit-scrollbar{height:.2rem;width:.2rem}.md-typeset pre>code::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset pre>code::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}.md-typeset kbd{border-radius:.2rem;box-shadow:0 0 0 .05rem var(--md-typeset-kbd-border-color),0 .15rem 0 var(--md-typeset-kbd-border-color);color:var(--md-default-fg-color);display:inline-block;font-size:.75em;padding:0 .6666666667em;vertical-align:text-top;word-break:break-word}.md-typeset mark{background-color:var(--md-typeset-mark-color);-webkit-box-decoration-break:clone;box-decoration-break:clone;color:inherit;word-break:break-word}.md-typeset abbr{border-bottom:.05rem dotted var(--md-default-fg-color--light);cursor:help;text-decoration:none}.md-typeset [data-preview]{position:relative}[dir=ltr] .md-typeset [data-preview]:after{margin-left:.125em}[dir=rtl] .md-typeset [data-preview]:after{margin-right:.125em}.md-typeset [data-preview]:after{background-color:currentcolor;content:"";display:inline-block;height:.8em;-webkit-mask-image:var(--md-typeset-preview-icon);mask-image:var(--md-typeset-preview-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-top;width:.8em}.md-typeset small{opacity:.75}[dir=ltr] .md-typeset sub,[dir=ltr] .md-typeset sup{margin-left:.078125em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-right:.078125em}[dir=ltr] .md-typeset blockquote{padding-left:.6rem}[dir=rtl] .md-typeset blockquote{padding-right:.6rem}[dir=ltr] .md-typeset blockquote{border-left:.2rem solid var(--md-default-fg-color--lighter)}[dir=rtl] .md-typeset blockquote{border-right:.2rem solid var(--md-default-fg-color--lighter)}.md-typeset blockquote{color:var(--md-default-fg-color--light);margin-left:0;margin-right:0}.md-typeset ul{list-style-type:disc}.md-typeset ul[type]{list-style-type:revert-layer}[dir=ltr] .md-typeset ol,[dir=ltr] .md-typeset ul{margin-left:.625em}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-right:.625em}.md-typeset ol,.md-typeset ul{padding:0}.md-typeset ol:not([hidden]),.md-typeset ul:not([hidden]){display:flow-root}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}.md-typeset ol ol ol ol,.md-typeset ul ol ol ol{list-style-type:upper-alpha}.md-typeset ol ol ol ol ol,.md-typeset ul ol ol ol ol{list-style-type:upper-roman}.md-typeset ol[type],.md-typeset ul[type]{list-style-type:revert-layer}[dir=ltr] .md-typeset ol li,[dir=ltr] .md-typeset ul li{margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-right:1.25em}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}[dir=ltr] .md-typeset ol li ol,[dir=ltr] .md-typeset ol li ul,[dir=ltr] .md-typeset ul li ol,[dir=ltr] .md-typeset ul li ul{margin-left:.625em}[dir=rtl] .md-typeset ol li ol,[dir=rtl] .md-typeset ol li ul,[dir=rtl] .md-typeset ul li ol,[dir=rtl] .md-typeset ul li ul{margin-right:.625em}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset dd{margin-left:1.875em}[dir=rtl] .md-typeset dd{margin-right:1.875em}.md-typeset dd{margin-bottom:1.5em;margin-top:1em}.md-typeset img,.md-typeset svg,.md-typeset video{height:auto;max-width:100%}.md-typeset img[align=left]{margin:1em 1em 1em 0}.md-typeset img[align=right]{margin:1em 0 1em 1em}.md-typeset img[align]:only-child{margin-top:0}.md-typeset figure{display:flow-root;margin:1em auto;max-width:100%;text-align:center;width:fit-content}.md-typeset figure img{display:block;margin:0 auto}.md-typeset figcaption{font-style:italic;margin:1em auto;max-width:24rem}.md-typeset iframe{max-width:100%}.md-typeset table:not([class]){background-color:var(--md-default-bg-color);border:.05rem solid var(--md-typeset-table-color);border-radius:.1rem;display:inline-block;font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto}@media print{.md-typeset table:not([class]){display:table}}.md-typeset table:not([class])+*{margin-top:1.5em}.md-typeset table:not([class]) td>:first-child,.md-typeset table:not([class]) th>:first-child{margin-top:0}.md-typeset table:not([class]) td>:last-child,.md-typeset table:not([class]) th>:last-child{margin-bottom:0}.md-typeset table:not([class]) td:not([align]),.md-typeset table:not([class]) th:not([align]){text-align:left}[dir=rtl] .md-typeset table:not([class]) td:not([align]),[dir=rtl] .md-typeset table:not([class]) th:not([align]){text-align:right}.md-typeset table:not([class]) th{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) td{border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) tbody tr{transition:background-color 125ms}.md-typeset table:not([class]) tbody tr:hover{background-color:var(--md-typeset-table-color--light);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset}.md-typeset table:not([class]) a{word-break:normal}.md-typeset table th[role=columnheader]{cursor:pointer}[dir=ltr] .md-typeset table th[role=columnheader]:after{margin-left:.5em}[dir=rtl] .md-typeset table th[role=columnheader]:after{margin-right:.5em}.md-typeset table th[role=columnheader]:after{content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-typeset-table-sort-icon);mask-image:var(--md-typeset-table-sort-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset table th[role=columnheader]:hover:after{background-color:var(--md-default-fg-color--lighter)}.md-typeset table th[role=columnheader][aria-sort=ascending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--asc);mask-image:var(--md-typeset-table-sort-icon--asc)}.md-typeset table th[role=columnheader][aria-sort=descending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--desc);mask-image:var(--md-typeset-table-sort-icon--desc)}.md-typeset__scrollwrap{margin:1em -.8rem;overflow-x:auto;touch-action:auto}.md-typeset__table{display:inline-block;margin-bottom:.5em;padding:0 .8rem}@media print{.md-typeset__table{display:block}}html .md-typeset__table table{display:table;margin:0;overflow:hidden;width:100%}@media screen and (max-width:44.984375em){.md-content__inner>pre{margin:1em -.8rem}.md-content__inner>pre code{border-radius:0}}.md-banner{background-color:var(--md-accent-fg-color--transparent);color:var(--md-default-fg-color);overflow:auto}@media print{.md-banner{display:none}}.md-banner--warning{background-color:var(--md-warning-bg-color);color:var(--md-warning-fg-color)}.md-banner__inner{font-size:.7rem;margin:.6rem auto;padding:0 .8rem}[dir=ltr] .md-banner__button{float:right}[dir=rtl] .md-banner__button{float:left}.md-banner__button{color:inherit;cursor:pointer;transition:opacity .25s}.no-js .md-banner__button{display:none}.md-banner__button:hover{opacity:.7}html{scrollbar-gutter:stable;font-size:125%;height:100%;overflow-x:hidden}@media screen and (min-width:100em){html{font-size:137.5%}}@media screen and (min-width:125em){html{font-size:150%}}body{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;font-size:.5rem;min-height:100%;position:relative;width:100%}@media print{body{display:block}}@media screen and (max-width:59.984375em){body[data-md-scrolllock]{position:fixed}}.md-grid{margin-left:auto;margin-right:auto;max-width:61rem}.md-container{display:flex;flex-direction:column;flex-grow:1}@media print{.md-container{display:block}}.md-main{flex-grow:1}.md-main__inner{display:flex;height:100%;margin-top:1.5rem}.md-ellipsis{overflow:hidden;text-overflow:ellipsis}.md-toggle{display:none}.md-option{height:0;opacity:0;position:absolute;width:0}.md-option:checked+label:not([hidden]){display:block}.md-option.focus-visible+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-skip{background-color:var(--md-default-fg-color);border-radius:.1rem;color:var(--md-default-bg-color);font-size:.64rem;margin:.5rem;opacity:0;outline-color:var(--md-accent-fg-color);padding:.3rem .5rem;position:fixed;transform:translateY(.4rem);z-index:-1}.md-skip:focus{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 175ms 75ms;z-index:10}@page{margin:25mm}:root{--md-clipboard-icon:url('data:image/svg+xml;charset=utf-8,')}.md-clipboard{border-radius:.1rem;color:var(--md-default-fg-color--lightest);cursor:pointer;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em;z-index:1}@media print{.md-clipboard{display:none}}.md-clipboard:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}:hover>.md-clipboard{color:var(--md-default-fg-color--light)}.md-clipboard:focus,.md-clipboard:hover{color:var(--md-accent-fg-color)}.md-clipboard:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-image:var(--md-clipboard-icon);mask-image:var(--md-clipboard-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-clipboard--inline{cursor:pointer}.md-clipboard--inline code{transition:color .25s,background-color .25s}.md-clipboard--inline:focus code,.md-clipboard--inline:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}:root{--md-code-select-icon:url('data:image/svg+xml;charset=utf-8,');--md-code-copy-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-code__content{display:grid}.md-code__nav{background-color:var(--md-code-bg-color--lighter);border-radius:.1rem;display:flex;gap:.2rem;padding:.2rem;position:absolute;right:.25em;top:.25em;transition:background-color .25s;z-index:1}:hover>.md-code__nav{background-color:var(--md-code-bg-color--light)}.md-code__button{color:var(--md-default-fg-color--lightest);cursor:pointer;display:block;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;transition:color .25s;width:1.5em}:hover>*>.md-code__button{color:var(--md-default-fg-color--light)}.md-code__button.focus-visible,.md-code__button:hover{color:var(--md-accent-fg-color)}.md-code__button--active{color:var(--md-default-fg-color)!important}.md-code__button:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-code__button[data-md-type=select]:after{-webkit-mask-image:var(--md-code-select-icon);mask-image:var(--md-code-select-icon)}.md-code__button[data-md-type=copy]:after{-webkit-mask-image:var(--md-code-copy-icon);mask-image:var(--md-code-copy-icon)}@keyframes consent{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@keyframes overlay{0%{opacity:0}to{opacity:1}}.md-consent__overlay{animation:overlay .35s both;-webkit-backdrop-filter:blur(.2rem);backdrop-filter:blur(.2rem);background-color:var(--md-default-bg-color--light);height:100%;opacity:1;position:fixed;top:0;width:100%;z-index:5}.md-consent__inner{bottom:0;display:flex;justify-content:center;max-height:100%;padding:0;position:fixed;width:100%;z-index:5}.md-consent__form{animation:consent .5s cubic-bezier(.1,.7,.1,1) both;background-color:var(--md-default-bg-color);border:0;border-radius:.8rem;box-shadow:var(--md-shadow-z3);margin:.4rem;overflow:auto;padding-left:1.2rem;padding-right:1.2rem}.md-consent__settings{display:none;margin:1em 0}input:checked+.md-consent__settings{display:block}.md-consent__controls{line-height:1.2;margin-bottom:.8rem}.md-typeset .md-consent__controls .md-button{display:inline}@media screen and (max-width:44.984375em){.md-typeset .md-consent__controls .md-button{display:block;margin-top:.4rem;text-align:center;width:100%}}.md-consent label{cursor:pointer}.md-content{flex-grow:1;min-width:0}.md-content__inner{margin:0 .8rem 1.2rem;padding-top:.7rem}@media screen and (min-width:76.25em){[dir=ltr] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}[dir=ltr] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner,[dir=rtl] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=rtl] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}}.md-content__inner:before{content:"";display:block;height:.4rem}.md-content__inner>:last-child{margin-bottom:0}[dir=ltr] .md-content__button{float:right}[dir=rtl] .md-content__button{float:left}[dir=ltr] .md-content__button{margin-left:.4rem}[dir=rtl] .md-content__button{margin-right:.4rem}.md-content__button{background-color:var(--md-default-fg-color--lightest);border-radius:.4rem;display:flex;margin-top:.2rem;padding:.3rem}@media print{.md-content__button{display:none}}.md-typeset .md-content__button{color:var(--md-default-fg-color);transition:color .25s,background-color .25s}.md-typeset .md-content__button svg{opacity:.5;transition:opacity .25s}.md-typeset .md-content__button:focus,.md-typeset .md-content__button:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset .md-content__button:focus svg,.md-typeset .md-content__button:hover svg{opacity:1}.md-content__button svg{height:.9rem;width:.9rem}[dir=rtl] .md-content__button svg{transform:scaleX(-1)}.md-content__button svg.lucide{fill:#0000;stroke:currentcolor}[dir=ltr] .md-dialog{right:.8rem}[dir=rtl] .md-dialog{left:.8rem}.md-dialog{background-color:var(--md-accent-fg-color);border-radius:1.2rem;bottom:.8rem;box-shadow:var(--md-shadow-z3);min-width:11.1rem;opacity:0;padding:.4rem 1.2rem;pointer-events:none;position:fixed;transform:translateY(100%);transition:transform 0ms .4s,opacity .4s;z-index:4}@media print{.md-dialog{display:none}}.md-dialog--active{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(.075,.85,.175,1),opacity .4s}.md-dialog__inner{color:var(--md-default-bg-color);font-size:.7rem}.md-feedback{margin:2em 0 1em;text-align:center}.md-feedback fieldset{border:none;margin:0;padding:0}.md-feedback__title{font-weight:700;margin:1em auto}.md-feedback__inner{position:relative}.md-feedback__list{display:flex;flex-wrap:wrap;place-content:baseline center;position:relative}.md-feedback__list:hover .md-icon:not(:disabled){color:var(--md-default-fg-color--lighter)}:disabled .md-feedback__list{min-height:1.8rem}.md-feedback__icon{color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;margin:0 .1rem;transition:color 125ms}.md-feedback__icon:not(:disabled).md-icon:hover{color:var(--md-accent-fg-color)}.md-feedback__icon:disabled{color:var(--md-default-fg-color--lightest);pointer-events:none}.md-feedback__note{opacity:0;position:relative;transform:translateY(.4rem);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-feedback__note>*{margin:0 auto;max-width:16rem}:disabled .md-feedback__note{opacity:1;transform:translateY(0)}@media print{.md-feedback{display:none}}.md-footer{background-color:var(--md-default-bg-color);border-top:.05rem solid var(--md-default-fg-color--lightest);color:var(--md-default-fg-color)}@media print{.md-footer{display:none}}.md-footer__inner{justify-content:space-between;overflow:auto;padding:.2rem}.md-footer__inner:not([hidden]){display:flex}.md-footer__link{align-items:end;display:flex;flex-grow:0.01;margin-bottom:.4rem;margin-top:1rem;max-width:100%;outline-color:var(--md-accent-fg-color);overflow:hidden;transition:opacity .25s}.md-footer__link:focus,.md-footer__link:hover{opacity:.7}[dir=rtl] .md-footer__link svg{transform:scaleX(-1)}@media screen and (max-width:44.984375em){.md-footer__link--prev{flex-shrink:0}.md-footer__link--prev .md-footer__title{display:none}}[dir=ltr] .md-footer__link--next{margin-left:auto}[dir=rtl] .md-footer__link--next{margin-right:auto}.md-footer__link--next{text-align:right}[dir=rtl] .md-footer__link--next{text-align:left}.md-footer__title{flex-grow:1;font-size:.8rem;margin-bottom:.7rem;max-width:calc(100% - 2.4rem);padding:0 1rem;white-space:nowrap}.md-footer__button{margin:.2rem;padding:.4rem}.md-footer__direction{font-size:.6rem;opacity:.7}.md-footer-meta{background-color:var(--md-default-fg-color--lightest)}.md-footer-meta__inner{display:flex;flex-wrap:wrap;justify-content:space-between;padding:.2rem}html .md-footer-meta.md-typeset a:not(:focus,:hover){color:var(--md-default-fg-color)}.md-copyright{color:var(--md-default-fg-color--light);font-size:.64rem;margin:auto .6rem;padding:.4rem 0;width:100%}@media screen and (min-width:45em){.md-copyright{width:auto}}.md-copyright__highlight{color:var(--md-default-fg-color)}.md-social{display:inline-flex;gap:.2rem;margin:0 .4rem;padding:.2rem 0 .6rem}@media screen and (min-width:45em){.md-social{padding:.6rem 0}}.md-social__link{display:inline-block;height:1.6rem;text-align:center;width:1.6rem}.md-social__link:before{line-height:1.9}.md-social__link svg{fill:currentcolor;max-height:.8rem;vertical-align:-25%}.md-social__link svg.lucide{fill:#0000;stroke:currentcolor}.md-typeset .md-button{background-color:var(--md-default-fg-color--lightest);border-radius:1.2rem;color:var(--md-default-fg-color--light);cursor:pointer;display:inline-block;font-size:.875em;font-weight:700;padding:.625em 2em;text-decoration:none;transition:color 125ms,background-color 125ms,opacity 125ms}.md-typeset .md-button.focus-visible{outline-offset:0}.md-typeset .md-button:focus,.md-typeset .md-button:hover{color:var(--md-default-fg-color--light);opacity:.8}.md-typeset .md-button--primary{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color)}.md-typeset .md-button--primary:focus,.md-typeset .md-button--primary:hover{color:var(--md-primary-bg-color);opacity:.8}[dir=ltr] .md-typeset .md-input{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .md-input,[dir=rtl] .md-typeset .md-input{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .md-input{border-top-left-radius:.1rem}.md-typeset .md-input{border-bottom:.1rem solid var(--md-default-fg-color--lighter);box-shadow:var(--md-shadow-z1);font-size:.8rem;height:1.8rem;padding:0 .6rem;transition:border .25s,box-shadow .25s}.md-typeset .md-input:focus,.md-typeset .md-input:hover{border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input--stretch{width:100%}.md-header{-webkit-backdrop-filter:blur(.4rem);backdrop-filter:blur(.4rem);background-color:var(--md-default-bg-color--light);color:var(--md-default-fg-color);display:block;left:0;position:sticky;right:0;top:0;z-index:4}@media print{.md-header{display:none}}.md-header[hidden]{transform:translateY(-100%);transition:transform .25s cubic-bezier(.8,0,.6,1)}.md-header--shadow{box-shadow:0 .05rem 0 var(--md-default-fg-color--lightest);transition:transform .25s cubic-bezier(.1,.7,.1,1)}.md-header__inner{align-items:center;display:flex;padding:0 .4rem}.md-header__button{color:currentcolor;cursor:pointer;margin:.2rem;outline-color:var(--md-accent-fg-color);padding:.4rem;position:relative;transition:opacity .25s;vertical-align:middle;z-index:1}.md-header__button:hover{opacity:.7}.md-header__button:not([hidden]){display:inline-block}.md-header__button:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-header__button.md-logo{margin:.2rem;padding:.4rem}@media screen and (max-width:76.234375em){.md-header__button.md-logo{display:none}}.md-header__button.md-logo img,.md-header__button.md-logo svg{fill:currentcolor;display:block;height:1.2rem;width:auto}.md-header__button.md-logo img.lucide,.md-header__button.md-logo svg.lucide{fill:#0000;stroke:currentcolor}@media screen and (min-width:60em){.md-header__button[for=__search]{display:none}}.no-js .md-header__button[for=__search]{display:none}[dir=rtl] .md-header__button[for=__search] svg{transform:scaleX(-1)}@media screen and (min-width:76.25em){.md-header__button[for=__drawer]{display:none}}.md-header__topic{display:flex;max-width:100%;position:absolute;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;white-space:nowrap}.md-header__topic+.md-header__topic{opacity:0;pointer-events:none;transform:translateX(1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__topic+.md-header__topic{transform:translateX(-1.25rem)}.md-header__topic:first-child{font-weight:700}.md-header__title{flex-grow:1;font-size:.9rem;height:2.4rem;letter-spacing:-.025em;line-height:2.4rem;margin-left:.4rem;margin-right:.4rem}.md-header__title--active .md-header__topic{opacity:0;pointer-events:none;transform:translateX(-1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__title--active .md-header__topic{transform:translateX(1.25rem)}.md-header__title--active .md-header__topic+.md-header__topic{opacity:1;pointer-events:auto;transform:translateX(0);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;z-index:0}.md-header__title>.md-header__ellipsis{height:100%;position:relative;width:100%}.md-header__option{display:flex;flex-shrink:0;max-width:100%;white-space:nowrap}.md-header__option>input{bottom:0}.md-header__source{display:none}@media screen and (min-width:60em){[dir=ltr] .md-header__source{margin-left:1rem}[dir=rtl] .md-header__source{margin-right:1rem}.md-header__source{display:block;max-width:11.5rem;width:11.5rem}}@media screen and (min-width:76.25em){[dir=ltr] .md-header__source{margin-left:1.4rem}[dir=rtl] .md-header__source{margin-right:1.4rem}}.md-header .md-icon svg{height:1rem;width:1rem}:root{--md-nav-icon--next:url('data:image/svg+xml;charset=utf-8,')}.md-nav{font-size:.7rem;line-height:1.3;transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav .md-nav__title{display:none}.md-nav__list{display:flex;flex-direction:column;gap:.2rem;list-style:none;margin:0;padding:0}[dir=ltr] .md-nav__list .md-nav__list{margin-left:.6rem}[dir=rtl] .md-nav__list .md-nav__list{margin-right:.6rem}.md-nav__item--nested .md-nav__list:after,.md-nav__item--nested .md-nav__list:before{content:" ";display:block;height:0}.md-nav__link{align-items:flex-start;border-radius:.4rem;cursor:pointer;display:flex;gap:.6rem;margin-left:.2rem;margin-right:.2rem;padding:.35rem .8rem;transition:color .25s,background-color .25s}.md-nav__link .md-nav__link{margin:0}.md-nav__link--passed,.md-nav__link--passed code{color:var(--md-default-fg-color--light)}.md-nav__item .md-nav__link--active{font-weight:500}.md-nav--primary .md-nav__item .md-nav__link--active{background:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-nav__item .md-nav__link--active,.md-nav__item .md-nav__link--active code{color:var(--md-typeset-a-color)}.md-nav__item .md-nav__link--active code svg,.md-nav__item .md-nav__link--active svg{opacity:1}[dir=ltr] .md-nav__item--nested>.md-nav__link:not(.md-nav__container){padding-right:.35rem}[dir=rtl] .md-nav__item--nested>.md-nav__link:not(.md-nav__container){padding-left:.35rem}.md-nav__link .md-ellipsis{flex-grow:1;position:relative}.md-nav__link .md-ellipsis code{word-break:normal}.md-nav__link svg{fill:currentcolor;flex-shrink:0;height:1.3em;opacity:.5;position:relative;width:1.3em}.md-nav__link svg.lucide{fill:#0000;stroke:currentcolor}.md-nav--primary .md-nav__link[for]:focus:not(.md-nav__link--active),.md-nav--primary .md-nav__link[for]:hover:not(.md-nav__link--active),.md-nav--primary .md-nav__link[href]:focus:not(.md-nav__link--active),.md-nav--primary .md-nav__link[href]:hover:not(.md-nav__link--active){background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color)}.md-nav--secondary .md-nav__link{margin-left:.2rem;margin-right:.2rem;padding:.35rem .8rem}.md-nav--secondary .md-nav__link[for]:focus,.md-nav--secondary .md-nav__link[for]:hover,.md-nav--secondary .md-nav__link[href]:focus,.md-nav--secondary .md-nav__link[href]:hover{background-color:initial;color:var(--md-accent-fg-color)}.md-nav__link.focus-visible{outline-color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__link[for=__toc],.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:none}.md-nav__icon{font-size:.9rem;height:.9rem;width:.9rem}[dir=rtl] .md-nav__icon:after{transform:rotate(180deg)}.md-nav__item--nested .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:transform .25s;width:100%}@media screen and (min-width:76.25em){.md-nav__item--nested.md-nav__item--section>.md-nav__link .md-nav__icon:after{display:none}}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link .md-nav__icon:after,.md-nav__item--nested .md-toggle--indeterminate~.md-nav__link .md-nav__icon:after{transform:rotate(90deg)}.md-nav__container{background:#0000;gap:.2rem;padding:0}.md-nav__container>:first-child{flex-grow:1;min-width:0}.md-nav__container>:nth-child(2){padding:.35rem}@media screen and (min-width:76.25em){.md-nav__item--section>.md-nav__container>:nth-child(2){display:none}}.md-nav__container__icon{flex-shrink:0}.md-nav__toggle~.md-nav{display:grid;grid-template-rows:minmax(.005rem,0fr);opacity:0;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .25s,visibility 0ms .25s;visibility:collapse}.md-nav__toggle~.md-nav>.md-nav__list{overflow:hidden}.md-nav__toggle.md-toggle--indeterminate~.md-nav,.md-nav__toggle:checked~.md-nav{grid-template-rows:minmax(.4rem,1fr);opacity:1;transition:grid-template-rows .25s cubic-bezier(.86,0,.07,1),opacity .15s .1s,visibility 0ms;visibility:visible}.md-nav__toggle.md-toggle--indeterminate~.md-nav{transition:none}.md-nav--secondary{margin-bottom:.1rem;margin-top:.1rem}.md-nav--secondary .md-nav{margin-top:.2rem}.md-nav--secondary .md-nav__title{background:var(--md-default-bg-color);display:flex;font-weight:700;margin-left:.2rem;margin-right:.2rem;padding:.35rem .6rem;position:sticky;top:0;z-index:1}.md-nav--secondary .md-nav__title .md-nav__icon{display:none}.md-nav--secondary .md-nav__link{padding:.2rem .6rem}@media screen and (max-width:76.234375em){.md-nav--primary{margin-bottom:.4rem;margin-left:.2rem;margin-right:.2rem}.md-nav .md-nav__title[for=__drawer]{align-items:center;border-bottom:.05rem solid var(--md-default-fg-color-lightest);display:flex;font-size:.8rem;font-weight:700;gap:.4rem;padding:.8rem}.md-nav .md-nav__title[for=__drawer] .md-logo{height:1.6rem;width:1.6rem}.md-nav .md-nav__title[for=__drawer] .md-logo img,.md-nav .md-nav__title[for=__drawer] .md-logo svg{fill:currentcolor;display:block;height:100%;max-width:100%;object-fit:contain;width:auto}.md-nav .md-nav__title[for=__drawer] .md-logo img.lucide,.md-nav .md-nav__title[for=__drawer] .md-logo svg.lucide{fill:#0000;stroke:currentcolor}}.md-nav__source{border:.05rem solid var(--md-default-fg-color--lightest);border-radius:.4rem;margin:.2rem .2rem .6rem;transition:background-color .25s,border-color .25s}.md-nav__source:focus,.md-nav__source:hover{background-color:var(--md-default-fg-color--lightest);border-color:#0000}[dir=ltr] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{margin-left:1.1rem}[dir=rtl] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{margin-right:1.1rem}[dir=ltr] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-left:.05rem solid var(--md-default-fg-color--lightest)}[dir=rtl] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-right:.05rem solid var(--md-default-fg-color--lightest)}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{display:block;margin-bottom:.5em;margin-top:.5em;opacity:1;visibility:visible}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary .md-nav__link{background:#0000}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary .md-nav__link--active{font-weight:500}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary .md-nav__link:focus,.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary .md-nav__link:hover{color:var(--md-accent-fg-color)}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__list{margin-left:0;overflow:visible;padding-bottom:0}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__title{display:none}@media screen and (min-width:76.25em){.md-nav--primary{margin-bottom:.1rem;margin-top:.1rem}.md-nav__source{display:none}[dir=ltr] .md-nav__list .md-nav__item--section>.md-nav>.md-nav__list{margin-left:0}[dir=rtl] .md-nav__list .md-nav__item--section>.md-nav>.md-nav__list{margin-right:0}.md-nav__item--section>.md-nav__link--active,.md-nav__item--section>.md-nav__link>.md-nav__link--active{font-weight:700}.md-nav__item--section{margin-top:.4rem}.md-nav__item--section:first-child{margin-top:0}.md-nav__item--section:last-child{margin-bottom:0}.md-nav__item--section>.md-nav__link{font-weight:700}.md-nav__item--section>.md-nav__link:not(.md-nav__container){pointer-events:none}.md-nav__item--section>.md-nav{display:block;opacity:1;visibility:visible}.md-nav__item--section>.md-nav>.md-nav__list>.md-nav__item{padding:0}.md-nav--lifted{margin-top:0}.md-nav--lifted>.md-nav__list>.md-nav__item{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active{display:block}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav{margin-top:.1rem}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav>.md-nav__list:before,.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active.md-nav__item--section{margin:0}.md-nav--lifted .md-nav[data-md-level="1"]{grid-template-rows:minmax(.4rem,1fr);opacity:1;visibility:visible}}:root{--md-path-icon:url('data:image/svg+xml;charset=utf-8,')}.md-path{font-size:.7rem;margin:.4rem .8rem 0;overflow:auto;padding-top:1.2rem}.md-path:not([hidden]){display:block}@media screen and (min-width:76.25em){.md-path{margin:.4rem 1.2rem 0}}.md-path__list{align-items:center;display:flex;gap:.2rem;list-style:none;margin:0;padding:0}.md-path__item:not(:first-child){align-items:center;display:inline-flex;gap:.2rem;white-space:nowrap}.md-path__item:not(:first-child):before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline;height:.6rem;-webkit-mask-image:var(--md-path-icon);mask-image:var(--md-path-icon);width:.6rem}.md-path__link{align-items:center;color:var(--md-default-fg-color--light);display:flex;transition:color .25s}.md-path__link:focus,.md-path__link:hover{color:var(--md-accent-fg-color)}:root{--md-progress-value:0;--md-progress-delay:400ms}.md-progress{background:var(--md-primary-bg-color);height:.075rem;opacity:min(clamp(0,var(--md-progress-value),1),clamp(0,100 - var(--md-progress-value),1));position:fixed;top:0;transform:scaleX(calc(var(--md-progress-value)*1%));transform-origin:left;transition:transform .5s cubic-bezier(.19,1,.22,1),opacity .25s var(--md-progress-delay);width:100%;z-index:4}:root{--md-search-icon:url('data:image/svg+xml;charset=utf-8,')}.md-search{position:relative}@media screen and (min-width:45em){.md-search{padding:.2rem 0}}@media screen and (max-width:59.984375em){.md-search{display:none}}.no-js .md-search{display:none}[dir=ltr] .md-search__button{padding-left:1.9rem;padding-right:2.2rem}[dir=rtl] .md-search__button{padding-left:2.2rem;padding-right:1.9rem}.md-search__button{background:var(--md-default-bg-color);color:var(--md-default-fg-color);cursor:pointer;font-size:.7rem;position:relative;text-align:left}@media screen and (min-width:45em){.md-search__button{background-color:var(--md-default-fg-color--lightest);border-radius:.4rem;height:1.6rem;transition:background-color .4s,color .4s;width:8.9rem}.md-search__button:focus,.md-search__button:hover{background-color:var(--md-default-fg-color--lighter);color:var(--md-default-fg-color)}}[dir=ltr] .md-search__button:before{left:0}[dir=rtl] .md-search__button:before{right:0}.md-search__button:before{background-color:var(--md-default-fg-color);content:"";height:1rem;margin-left:.5rem;-webkit-mask-image:var(--md-search-icon);mask-image:var(--md-search-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.3rem;width:1rem}.md-search__button:after{background:var(--md-default-bg-color--light);border-radius:.2rem;content:"Ctrl+K";display:block;font-size:.6rem;padding:.1rem .2rem;position:absolute;right:.6rem;top:.35rem}[data-platform^=Mac] .md-search__button:after{content:"⌘K"}.md-select{position:relative;z-index:1}.md-select__inner{background-color:var(--md-default-bg-color);border-radius:.4rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);left:50%;margin-top:.2rem;max-height:0;opacity:0;position:absolute;top:calc(100% - .2rem);transform:translate3d(-50%,.3rem,0);transition:transform .25s 375ms,opacity .25s .25s,max-height 0ms .5s}@media screen and (max-width:59.984375em){.md-select__inner{left:100%;transform:translate3d(-100%,.3rem,0)}}.md-select:focus-within .md-select__inner,.md-select:hover .md-select__inner{max-height:min(75vh,28rem);opacity:1;transform:translate3d(-50%,0,0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}@media screen and (max-width:59.984375em){.md-select:focus-within .md-select__inner,.md-select:hover .md-select__inner{transform:translate3d(-100%,0,0)}}.md-select__inner:after{border-bottom:.2rem solid #0000;border-bottom-color:var(--md-default-bg-color);border-left:.2rem solid #0000;border-right:.2rem solid #0000;border-top:0;content:"";filter:drop-shadow(0 -1px 0 var(--md-default-fg-color--lightest));height:0;left:50%;margin-left:-.2rem;margin-top:-.2rem;position:absolute;top:0;width:0}@media screen and (max-width:59.984375em){.md-select__inner:after{left:auto;right:1rem}}.md-select__list{border-radius:.1rem;font-size:.8rem;list-style-type:none;margin:0;max-height:inherit;overflow:auto;padding:0}.md-select__item{line-height:1.8rem}[dir=ltr] .md-select__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-select__link{padding-left:1.2rem;padding-right:.6rem}.md-select__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:background-color .25s,color .25s;width:100%}.md-select__link:focus,.md-select__link:hover{color:var(--md-accent-fg-color)}.md-select__link:focus{background-color:var(--md-default-fg-color--lightest)}:root{--md-toc-icon:url('data:image/svg+xml;charset=utf-8,')}.md-sidebar{align-self:flex-start;flex-shrink:0;padding:1.1rem 0;position:sticky;top:2.4rem;width:12.1rem}@media print{.md-sidebar{display:none}}@media screen and (max-width:76.234375em){[dir=ltr] .md-sidebar--primary{left:-12.1rem}[dir=rtl] .md-sidebar--primary{right:-12.1rem}.md-sidebar--primary{-webkit-backdrop-filter:blur(.4rem);backdrop-filter:blur(.4rem);background-color:var(--md-default-bg-color--light);border-radius:.8rem;display:block;height:calc(100% - .8rem);position:fixed;top:.4rem;transform:translateX(0);transition:transform .2s cubic-bezier(.5,0,.5,0),box-shadow .2s;width:12.1rem;z-index:5}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:var(--md-shadow-z3);transform:translateX(12.5rem);transition:transform .25s cubic-bezier(.7,.7,.1,1),box-shadow .25s}[dir=rtl] [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{transform:translateX(-12.5rem)}.md-sidebar--primary .md-sidebar__scrollwrap{bottom:0;left:0;margin:0;overscroll-behavior-y:contain;position:absolute;right:0;top:0}}@media screen and (min-width:76.25em){.md-sidebar{height:0}.no-js .md-sidebar{height:auto}.md-header--lifted~.md-container .md-sidebar{top:4.8rem}}.md-sidebar--secondary{order:2}@media screen and (max-width:59.984375em){.md-sidebar--secondary{bottom:1.6rem;padding:0;position:fixed;right:.8rem;top:auto;width:auto;z-index:2}.md-sidebar--secondary .md-nav--secondary{margin-top:0}.md-sidebar--secondary .md-nav__title{padding:.55rem .6rem .35rem}.md-sidebar--secondary .md-sidebar__scrollwrap{display:flex;flex-direction:column-reverse;overflow-y:visible;position:relative}.md-sidebar--secondary .md-sidebar__inner{background-color:var(--md-default-bg-color);border-radius:.4rem;bottom:2.7rem;box-shadow:var(--md-shadow-z2);max-height:50vh;opacity:0;overflow-y:auto;padding-bottom:.4rem;pointer-events:none;position:absolute;right:0;transform:translateY(.4rem);transition:transform 0ms .25s,opacity .25s;width:11.7rem}.md-sidebar--secondary [type=checkbox]:checked~.md-sidebar__inner{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(0,1,.35,1),opacity .25s,z-index 0ms}.md-sidebar--secondary .md-sidebar-button{-webkit-backdrop-filter:blur(.4rem);backdrop-filter:blur(.4rem);background-color:var(--md-default-bg-color--light);border-radius:1.6rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);cursor:pointer;display:inline-flex;font-size:.7rem;gap:.4rem;outline:none;padding:.5rem;transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms}.md-sidebar--secondary .md-sidebar-button:after{background-color:currentcolor;content:"";display:block;height:.9rem;-webkit-mask-image:var(--md-toc-icon);mask-image:var(--md-toc-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:transform .25s;width:.9rem}.md-sidebar--secondary .md-sidebar-button:focus,.md-sidebar--secondary .md-sidebar-button:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-sidebar--secondary .md-sidebar-button__wrapper{text-align:right}}@media screen and (min-width:60em){.md-sidebar--secondary{height:0}.md-sidebar--secondary .md-sidebar-button{display:none}.no-js .md-sidebar--secondary{height:auto}.md-sidebar--secondary:not([hidden]){display:block}.md-sidebar--secondary .md-sidebar__scrollwrap{touch-action:pan-y}}.md-sidebar__scrollwrap{backface-visibility:hidden;overflow-y:auto;scrollbar-color:var(--md-default-fg-color--lighter) #0000}@media screen and (min-width:60em){.md-sidebar__scrollwrap{scrollbar-gutter:stable;scrollbar-width:thin}}.md-sidebar__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-sidebar__scrollwrap:focus-within,.md-sidebar__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) #0000}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-sidebar__scrollwrap:focus-within::-webkit-scrollbar-thumb:hover,.md-sidebar__scrollwrap:hover::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@supports selector(::-webkit-scrollbar){.md-sidebar__scrollwrap{scrollbar-gutter:auto}[dir=ltr] .md-sidebar__inner{padding-right:calc(100% - 11.5rem)}[dir=rtl] .md-sidebar__inner{padding-left:calc(100% - 11.5rem)}@media screen and (max-width:76.234375em){[dir=ltr] .md-sidebar__inner{padding-right:0}[dir=rtl] .md-sidebar__inner{padding-left:0}}}@media screen and (max-width:76.234375em){.md-overlay{-webkit-backdrop-filter:blur(.2rem);backdrop-filter:blur(.2rem);background-color:var(--md-default-bg-color--light);height:0;opacity:0;position:fixed;top:0;transition:width 0ms .5s,height 0ms .5s,opacity .25s 125ms;width:0;z-index:5}[data-md-toggle=drawer]:checked~.md-overlay{height:100%;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@keyframes facts{0%{height:0}to{height:.65rem}}@keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}:root{--md-source-forks-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-repositories-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-stars-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-source{backface-visibility:hidden;display:block;font-size:.55rem;line-height:1.2;outline-color:var(--md-accent-fg-color);transition:opacity .25s;white-space:nowrap}.md-source:hover{opacity:.7}.md-source__icon{display:inline-block;height:2.4rem;vertical-align:middle;width:2rem}[dir=ltr] .md-source__icon svg{margin-left:.6rem}[dir=rtl] .md-source__icon svg{margin-right:.6rem}.md-source__icon svg{margin-top:.6rem}.md-header .md-source__icon svg{height:1.2rem;width:1.2rem}[dir=ltr] .md-source__icon+.md-source__repository{padding-left:2rem}[dir=rtl] .md-source__icon+.md-source__repository{padding-right:2rem}[dir=ltr] .md-source__icon+.md-source__repository{margin-left:-2rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-right:-2rem}[dir=ltr] .md-source__repository{margin-left:.6rem}[dir=rtl] .md-source__repository{margin-right:.6rem}.md-source__repository{display:inline-block;max-width:calc(100% - 1.2rem);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}.md-source__facts{display:flex;font-size:.55rem;gap:.4rem;list-style-type:none;margin:.1rem 0 0;opacity:.75;overflow:hidden;padding:0;width:100%}.md-source__repository--active .md-source__facts{animation:facts 0ms ease-in}.md-source__fact{overflow:hidden;text-overflow:ellipsis}.md-source__repository--active .md-source__fact{animation:fact 0ms ease-out}[dir=ltr] .md-source__fact:before{margin-right:.1rem}[dir=rtl] .md-source__fact:before{margin-left:.1rem}.md-source__fact:before{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-top;width:.6rem}.md-source__fact:nth-child(1n+2){flex-shrink:0}.md-source__fact--version:before{-webkit-mask-image:var(--md-source-version-icon);mask-image:var(--md-source-version-icon)}.md-source__fact--stars:before{-webkit-mask-image:var(--md-source-stars-icon);mask-image:var(--md-source-stars-icon)}.md-source__fact--forks:before{-webkit-mask-image:var(--md-source-forks-icon);mask-image:var(--md-source-forks-icon)}.md-source__fact--repositories:before{-webkit-mask-image:var(--md-source-repositories-icon);mask-image:var(--md-source-repositories-icon)}.md-source-file{margin:1em 0}[dir=ltr] .md-source-file__fact{margin-right:.6rem}[dir=rtl] .md-source-file__fact{margin-left:.6rem}.md-source-file__fact{align-items:center;color:var(--md-default-fg-color--light);display:inline-flex;font-size:.68rem;gap:.3rem}.md-source-file__fact .md-icon{flex-shrink:0;margin-bottom:.05rem}[dir=ltr] .md-source-file__fact .md-author{float:left}[dir=rtl] .md-source-file__fact .md-author{float:right}.md-source-file__fact .md-author{margin-right:.2rem}.md-source-file__fact svg{width:.9rem}:root{--md-status:url('data:image/svg+xml;charset=utf-8,');--md-status--new:url('data:image/svg+xml;charset=utf-8,');--md-status--deprecated:url('data:image/svg+xml;charset=utf-8,')}.md-status:after{background-color:var(--md-default-fg-color--light);content:"";display:inline-block;height:1.125em;-webkit-mask-image:var(--md-status);mask-image:var(--md-status);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-bottom;width:1.125em}.md-status:hover:after{background-color:currentcolor}.md-status--new:after{-webkit-mask-image:var(--md-status--new);mask-image:var(--md-status--new)}.md-status--deprecated:after{-webkit-mask-image:var(--md-status--deprecated);mask-image:var(--md-status--deprecated)}.md-tabs{box-shadow:0 -.05rem 0 inset var(--md-default-fg-color--lightest);color:var(--md-default-fg-color);display:block;line-height:1.3;overflow:auto;width:100%;z-index:2}@media print{.md-tabs{display:none}}@media screen and (max-width:76.234375em){.md-tabs{display:none}}.md-header--lifted .md-tabs{box-shadow:none;margin-bottom:-.05rem}.md-tabs[hidden]{pointer-events:none}[dir=ltr] .md-tabs__list{margin-left:.4rem}[dir=rtl] .md-tabs__list{margin-right:.4rem}.md-tabs__list{contain:content;display:flex;list-style:none;margin:0;overflow:auto;padding:0;scrollbar-width:none;white-space:nowrap}.md-tabs__list::-webkit-scrollbar{display:none}.md-tabs__item{height:2.4rem;padding-left:.6rem;padding-right:.6rem}.md-tabs__item--active{border-bottom:.05rem solid var(--md-default-fg-color);font-weight:500;position:relative;transition:border-bottom .25s}.md-tabs[hidden] .md-tabs__item--active{border-bottom:.05rem solid #0000}.md-tabs__item--active .md-tabs__link{color:inherit;opacity:1}.md-tabs__link{backface-visibility:hidden;display:flex;font-size:.7rem;margin-top:.8rem;opacity:.7;outline-color:var(--md-accent-fg-color);outline-offset:.2rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s}.md-tabs__link:focus,.md-tabs__link:hover{color:inherit;opacity:1}[dir=ltr] .md-tabs__link svg{margin-right:.4rem}[dir=rtl] .md-tabs__link svg{margin-left:.4rem}.md-tabs__link svg{fill:currentcolor;height:1.3em}.md-tabs__item:nth-child(2) .md-tabs__link{transition-delay:20ms}.md-tabs__item:nth-child(3) .md-tabs__link{transition-delay:40ms}.md-tabs__item:nth-child(4) .md-tabs__link{transition-delay:60ms}.md-tabs__item:nth-child(5) .md-tabs__link{transition-delay:80ms}.md-tabs__item:nth-child(6) .md-tabs__link{transition-delay:.1s}.md-tabs__item:nth-child(7) .md-tabs__link{transition-delay:.12s}.md-tabs__item:nth-child(8) .md-tabs__link{transition-delay:.14s}.md-tabs__item:nth-child(9) .md-tabs__link{transition-delay:.16s}.md-tabs__item:nth-child(10) .md-tabs__link{transition-delay:.18s}.md-tabs__item:nth-child(11) .md-tabs__link{transition-delay:.2s}.md-tabs__item:nth-child(12) .md-tabs__link{transition-delay:.22s}.md-tabs__item:nth-child(13) .md-tabs__link{transition-delay:.24s}.md-tabs__item:nth-child(14) .md-tabs__link{transition-delay:.26s}.md-tabs__item:nth-child(15) .md-tabs__link{transition-delay:.28s}.md-tabs__item:nth-child(16) .md-tabs__link{transition-delay:.3s}.md-tabs[hidden] .md-tabs__link{opacity:0;transform:translateY(50%);transition:transform 0ms .1s,opacity .1s}:root{--md-tag-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-tags:not([hidden]){display:flex;flex-wrap:wrap;gap:.5em;margin-bottom:1.2rem;margin-top:.8rem;padding-top:1.2rem}.md-typeset .md-tag{align-items:center;background:var(--md-default-fg-color--lightest);border-radius:.4rem;display:inline-flex;font-size:.64rem;font-size:min(.8em,.64rem);font-weight:700;gap:.5em;letter-spacing:normal;line-height:1.6;padding:.3125em .78125em}.md-typeset .md-tag[href]{-webkit-tap-highlight-color:transparent;color:inherit;outline:none;transition:color 125ms,background-color 125ms}.md-typeset .md-tag[href]:focus,.md-typeset .md-tag[href]:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[id]>.md-typeset .md-tag{vertical-align:text-top}.md-typeset .md-tag-shadow{opacity:.5}.md-typeset .md-tag-icon:before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-tag-icon);mask-image:var(--md-tag-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset .md-tag-icon[href]:focus:before,.md-typeset .md-tag-icon[href]:hover:before{background-color:var(--md-accent-bg-color)}@keyframes pulse{0%{transform:scale(.95)}75%{transform:scale(1)}to{transform:scale(.95)}}:root{--md-annotation-bg-icon:url('data:image/svg+xml;charset=utf-8,');--md-annotation-icon:url('data:image/svg+xml;charset=utf-8,')}.md-tooltip{backface-visibility:hidden;background-color:var(--md-default-bg-color);border-radius:.4rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);font-family:var(--md-text-font-family);left:clamp(var(--md-tooltip-0,0rem) + .8rem,var(--md-tooltip-x) - .1rem,100vw + var(--md-tooltip-0,0rem) + .8rem - var(--md-tooltip-width) - 2 * .8rem);max-width:calc(100vw - 1.6rem);opacity:0;position:absolute;top:calc(var(--md-tooltip-y) - .1rem);transform:translateY(-.4rem);transition:transform 0ms .25s,opacity .25s,z-index .25s;width:var(--md-tooltip-width);z-index:0}.md-tooltip--active{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,z-index 0ms;z-index:2}.md-tooltip--inline{font-weight:400;-webkit-user-select:none;user-select:none;width:auto}.md-tooltip--inline:not(.md-tooltip--active){transform:translateY(.2rem) scale(.9)}.md-tooltip--inline .md-tooltip__inner{font-size:.55rem;padding:.2rem .4rem}[hidden]+.md-tooltip--inline{display:none}.focus-visible>.md-tooltip,.md-tooltip:target{outline:var(--md-accent-fg-color) auto}.md-tooltip__inner{font-size:.64rem;padding:.8rem}.md-tooltip__inner.md-typeset>:first-child{margin-top:0}.md-tooltip__inner.md-typeset>:last-child{margin-bottom:0}.md-annotation{font-style:normal;font-weight:400;outline:none;text-align:initial;vertical-align:text-bottom;white-space:normal}[dir=rtl] .md-annotation{direction:rtl}code .md-annotation{font-family:var(--md-code-font-family);font-size:inherit}.md-annotation:not([hidden]){display:inline-block;line-height:1.25}.md-annotation__index{border-radius:.01px;cursor:pointer;display:inline-block;margin-left:.4ch;margin-right:.4ch;outline:none;overflow:hidden;position:relative;-webkit-user-select:none;user-select:none;vertical-align:text-top;z-index:0}.md-annotation .md-annotation__index{transition:z-index .25s}@media screen{.md-annotation__index{width:2.2ch}[data-md-visible]>.md-annotation__index{animation:pulse 2s infinite}.md-annotation__index:before{background:var(--md-default-bg-color);-webkit-mask-image:var(--md-annotation-bg-icon);mask-image:var(--md-annotation-bg-icon)}.md-annotation__index:after,.md-annotation__index:before{content:"";height:2.2ch;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:-.1ch;width:2.2ch;z-index:-1}.md-annotation__index:after{background-color:var(--md-default-fg-color--lighter);-webkit-mask-image:var(--md-annotation-icon);mask-image:var(--md-annotation-icon);transform:scale(1.0001);transition:background-color .25s,transform .25s}.md-tooltip--active+.md-annotation__index:after{transform:rotate(45deg)}.md-tooltip--active+.md-annotation__index:after,:hover>.md-annotation__index:after{background-color:var(--md-accent-fg-color)}}.md-tooltip--active+.md-annotation__index{animation-play-state:paused;transition-duration:0ms;z-index:2}.md-annotation__index [data-md-annotation-id]{display:inline-block}@media print{.md-annotation__index [data-md-annotation-id]{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);font-weight:700;padding:0 .6ch;white-space:nowrap}.md-annotation__index [data-md-annotation-id]:after{content:attr(data-md-annotation-id)}}.md-typeset .md-annotation-list{counter-reset:annotation;list-style:none!important}.md-typeset .md-annotation-list li{position:relative}[dir=ltr] .md-typeset .md-annotation-list li:before{left:-2.125em}[dir=rtl] .md-typeset .md-annotation-list li:before{right:-2.125em}.md-typeset .md-annotation-list li:before{background:var(--md-default-fg-color--lighter);border-radius:2ch;color:var(--md-default-bg-color);content:counter(annotation);counter-increment:annotation;font-size:.8875em;font-weight:700;height:2ch;line-height:1.25;min-width:2ch;padding:0 .6ch;position:absolute;text-align:center;top:.25em}:root{--md-tooltip-width:20rem;--md-tooltip-tail:0.3rem}.md-tooltip2{backface-visibility:hidden;color:var(--md-default-fg-color);font-family:var(--md-text-font-family);opacity:0;pointer-events:none;position:absolute;top:calc(var(--md-tooltip-host-y) + var(--md-tooltip-y));transform:translateY(.4rem);transform-origin:calc(var(--md-tooltip-host-x) + var(--md-tooltip-x)) 0;transition:transform 0ms .25s,opacity .25s,z-index .25s;width:100%;z-index:0}.md-tooltip2:before{border-left:var(--md-tooltip-tail) solid #0000;border-right:var(--md-tooltip-tail) solid #0000;content:"";display:block;left:clamp(1.5 * .8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-tail),100vw - 2 * var(--md-tooltip-tail) - 1.5 * .8rem);position:absolute;z-index:1}.md-tooltip2--top:before{border-top:var(--md-tooltip-tail) solid var(--md-default-bg-color);bottom:calc(var(--md-tooltip-tail)*-1 + .025rem);filter:drop-shadow(0 1px 0 var(--md-default-fg-color--lightest))}.md-tooltip2--bottom:before{border-bottom:var(--md-tooltip-tail) solid var(--md-default-bg-color);filter:drop-shadow(0 -1px 0 var(--md-default-fg-color--lightest));top:calc(var(--md-tooltip-tail)*-1 + .025rem)}.md-tooltip2--active{opacity:1;transform:translateY(0);transition:transform .4s cubic-bezier(0,1,.35,1),opacity .25s,z-index 0ms;z-index:4}.md-tooltip2__inner{scrollbar-gutter:stable;background-color:var(--md-default-bg-color);border-radius:.4rem;box-shadow:var(--md-shadow-z2);left:clamp(.8rem,var(--md-tooltip-host-x) - .8rem,100vw - var(--md-tooltip-width) - .8rem);max-height:40vh;max-width:calc(100vw - 1.6rem);position:relative;scrollbar-width:thin}.md-tooltip2__inner::-webkit-scrollbar{height:.2rem;width:.2rem}.md-tooltip2__inner::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-tooltip2__inner::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}[role=dialog]>.md-tooltip2__inner{font-size:.64rem;overflow:auto;padding:0 .8rem;pointer-events:auto;width:var(--md-tooltip-width)}[role=dialog]>.md-tooltip2__inner:after,[role=dialog]>.md-tooltip2__inner:before{content:"";display:block;height:.8rem;position:sticky;width:100%;z-index:10}[role=dialog]>.md-tooltip2__inner:before{background:linear-gradient(var(--md-default-bg-color),#0000 75%);top:0}[role=dialog]>.md-tooltip2__inner:after{background:linear-gradient(#0000,var(--md-default-bg-color) 75%);bottom:0}[role=tooltip]>.md-tooltip2__inner{font-size:.55rem;font-weight:400;left:clamp(.8rem,var(--md-tooltip-host-x) + var(--md-tooltip-x) - var(--md-tooltip-width)/2,100vw - var(--md-tooltip-width) - .8rem);max-width:min(100vw - 2 * .8rem,400px);padding:.2rem .4rem;-webkit-user-select:none;user-select:none;width:fit-content}.md-tooltip2__inner.md-typeset>:first-child{margin-top:0}.md-tooltip2__inner.md-typeset>:last-child{margin-bottom:0}[dir=ltr] .md-top{margin-left:50%}[dir=rtl] .md-top{margin-right:50%}.md-top{-webkit-backdrop-filter:blur(.4rem);backdrop-filter:blur(.4rem);background-color:var(--md-default-bg-color--light);border-radius:1.6rem;bottom:1.6rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);cursor:pointer;display:flex;font-size:.7rem;gap:.4rem;outline:none;padding:.5rem .9rem .5rem .7rem;position:fixed;top:auto!important;transform:translate(-50%);transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms;z-index:2}@media print{.md-top{display:none}}[dir=rtl] .md-top{transform:translate(50%)}.md-top[hidden]{opacity:0;pointer-events:none;transform:translate(-50%,.2rem);transition-duration:0ms}[dir=rtl] .md-top[hidden]{transform:translate(50%,.2rem)}.md-top:focus,.md-top:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top svg{display:inline-block;height:.9rem;vertical-align:-.5em;width:.9rem}.md-top svg.lucide{fill:#0000;stroke:currentcolor}@keyframes hoverfix{0%{pointer-events:none}}:root{--md-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-version{flex-shrink:0;font-size:.8rem;height:2.4rem}[dir=ltr] .md-version__current{margin-left:1.4rem;margin-right:.4rem}[dir=rtl] .md-version__current{margin-left:.4rem;margin-right:1.4rem}.md-version__current{color:inherit;cursor:pointer;outline:none;position:relative;top:.05rem}[dir=ltr] .md-version__current:after{margin-left:.4rem}[dir=rtl] .md-version__current:after{margin-right:.4rem}.md-version__current:after{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-image:var(--md-version-icon);mask-image:var(--md-version-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.4rem}.md-version__alias{margin-left:.3rem;opacity:.7}.md-version__list{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);list-style-type:none;margin:.2rem .8rem;max-height:0;opacity:0;overflow:auto;padding:0;position:absolute;scroll-snap-type:y mandatory;top:.15rem;transition:max-height 0ms .5s,opacity .25s .25s;z-index:3}.md-version:focus-within .md-version__list,.md-version:hover .md-version__list{max-height:10rem;opacity:1;transition:max-height 0ms,opacity .25s}@media (hover:none),(pointer:coarse){.md-version:hover .md-version__list{animation:hoverfix .25s forwards}.md-version:focus-within .md-version__list{animation:none}}.md-version__item{line-height:1.8rem}[dir=ltr] .md-version__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-version__link{padding-left:1.2rem;padding-right:.6rem}.md-version__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:color .25s,background-color .25s;white-space:nowrap;width:100%}.md-version__link:focus,.md-version__link:hover{color:var(--md-accent-fg-color)}.md-version__link:focus{background-color:var(--md-default-fg-color--lightest)}:root{--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .admonition,.md-typeset details{background-color:#448aff1a;border-radius:.4rem;color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .8rem;page-break-inside:avoid}.md-typeset .admonition>*,.md-typeset details>*{box-sizing:border-box}.md-typeset .admonition .admonition,.md-typeset .admonition details,.md-typeset details .admonition,.md-typeset details details{margin-bottom:1em;margin-top:1em}.md-typeset .admonition .md-typeset__scrollwrap,.md-typeset details .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset .admonition .md-typeset__table,.md-typeset details .md-typeset__table{padding:0 .6rem}.md-typeset .admonition>.tabbed-set:only-child,.md-typeset details>.tabbed-set:only-child{margin-top:0}html .md-typeset .admonition>:last-child,html .md-typeset details>:last-child{margin-bottom:.6rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{padding-left:1.6rem;padding-right:.8rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{padding-left:.8rem;padding-right:1.6rem}.md-typeset .admonition-title,.md-typeset summary{font-weight:700;margin-bottom:1em;margin-top:.6rem;position:relative}[dir=ltr] .md-typeset .admonition-title:before,[dir=ltr] .md-typeset summary:before{left:0}[dir=rtl] .md-typeset .admonition-title:before,[dir=rtl] .md-typeset summary:before{right:0}.md-typeset .admonition-title:before,.md-typeset summary:before{background-color:#448aff;content:"";height:1rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.125em;width:1rem}.md-typeset .admonition.note,.md-typeset details.note{background-color:#448aff1a}.md-typeset .note>.admonition-title:before,.md-typeset .note>summary:before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note)}.md-typeset .note>.admonition-title:after,.md-typeset .note>summary:after{color:#448aff}.md-typeset .admonition.abstract,.md-typeset details.abstract{background-color:#00b0ff1a}.md-typeset .abstract>.admonition-title:before,.md-typeset .abstract>summary:before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract)}.md-typeset .abstract>.admonition-title:after,.md-typeset .abstract>summary:after{color:#00b0ff}.md-typeset .admonition.info,.md-typeset details.info{background-color:#00b8d41a}.md-typeset .info>.admonition-title:before,.md-typeset .info>summary:before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info)}.md-typeset .info>.admonition-title:after,.md-typeset .info>summary:after{color:#00b8d4}.md-typeset .admonition.tip,.md-typeset details.tip{background-color:#00bfa51a}.md-typeset .tip>.admonition-title:before,.md-typeset .tip>summary:before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip)}.md-typeset .tip>.admonition-title:after,.md-typeset .tip>summary:after{color:#00bfa5}.md-typeset .admonition.success,.md-typeset details.success{background-color:#00c8531a}.md-typeset .success>.admonition-title:before,.md-typeset .success>summary:before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success)}.md-typeset .success>.admonition-title:after,.md-typeset .success>summary:after{color:#00c853}.md-typeset .admonition.question,.md-typeset details.question{background-color:#64dd171a}.md-typeset .question>.admonition-title:before,.md-typeset .question>summary:before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question)}.md-typeset .question>.admonition-title:after,.md-typeset .question>summary:after{color:#64dd17}.md-typeset .admonition.warning,.md-typeset details.warning{background-color:#ff91001a}.md-typeset .warning>.admonition-title:before,.md-typeset .warning>summary:before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning)}.md-typeset .warning>.admonition-title:after,.md-typeset .warning>summary:after{color:#ff9100}.md-typeset .admonition.failure,.md-typeset details.failure{background-color:#ff52521a}.md-typeset .failure>.admonition-title:before,.md-typeset .failure>summary:before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure)}.md-typeset .failure>.admonition-title:after,.md-typeset .failure>summary:after{color:#ff5252}.md-typeset .admonition.danger,.md-typeset details.danger{background-color:#ff17441a}.md-typeset .danger>.admonition-title:before,.md-typeset .danger>summary:before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger)}.md-typeset .danger>.admonition-title:after,.md-typeset .danger>summary:after{color:#ff1744}.md-typeset .admonition.bug,.md-typeset details.bug{background-color:#f500571a}.md-typeset .bug>.admonition-title:before,.md-typeset .bug>summary:before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug)}.md-typeset .bug>.admonition-title:after,.md-typeset .bug>summary:after{color:#f50057}.md-typeset .admonition.example,.md-typeset details.example{background-color:#7c4dff1a}.md-typeset .example>.admonition-title:before,.md-typeset .example>summary:before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example)}.md-typeset .example>.admonition-title:after,.md-typeset .example>summary:after{color:#7c4dff}.md-typeset .admonition.quote,.md-typeset details.quote{background-color:#9e9e9e1a}.md-typeset .quote>.admonition-title:before,.md-typeset .quote>summary:before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote)}.md-typeset .quote>.admonition-title:after,.md-typeset .quote>summary:after{color:#9e9e9e}:root{--md-footnotes-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .footnote{color:var(--md-default-fg-color--light);font-size:.64rem}[dir=ltr] .md-typeset .footnote>ol{margin-left:0}[dir=rtl] .md-typeset .footnote>ol{margin-right:0}.md-typeset .footnote>ol>li{transition:color 125ms}.md-typeset .footnote>ol>li:target{color:var(--md-default-fg-color)}.md-typeset .footnote>ol>li:focus-within .footnote-backref{opacity:1;transform:translateY(0);transition:none}.md-typeset .footnote>ol>li:hover .footnote-backref,.md-typeset .footnote>ol>li:target .footnote-backref{opacity:1;transform:translateY(0)}.md-typeset .footnote>ol>li>:first-child{margin-top:0}.md-typeset .footnote-ref{font-size:.75em;font-weight:700;text-decoration:none}html .md-typeset .footnote-ref{outline-offset:.1rem}.md-typeset [id^="fnref:"]:target>.footnote-ref{outline:auto}.md-typeset .footnote-backref{color:var(--md-typeset-a-color);display:inline-block;font-size:0;opacity:0;transform:translateY(.25rem);transition:color .25s,transform .25s .25s,opacity 125ms .25s;vertical-align:text-bottom}@media print{.md-typeset .footnote-backref{color:var(--md-typeset-a-color);opacity:1;transform:translateY(0)}}[dir=rtl] .md-typeset .footnote-backref{transform:translateY(-.25rem)}.md-typeset .footnote-backref:hover{color:var(--md-accent-fg-color)}.md-typeset .footnote-backref:before{background-color:currentcolor;content:"";display:inline-block;height:.8rem;-webkit-mask-image:var(--md-footnotes-icon);mask-image:var(--md-footnotes-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.8rem}[dir=rtl] .md-typeset .footnote-backref:before{transform:scaleX(-1)}[dir=ltr] .md-typeset .headerlink{margin-left:.5rem}[dir=rtl] .md-typeset .headerlink{margin-right:.5rem}.md-typeset .headerlink{color:var(--md-default-fg-color--lighter);display:inline-block;opacity:0;text-decoration:none;transition:color .25s,opacity 125ms}@media print{.md-typeset .headerlink{display:none}}.md-typeset .headerlink:focus,.md-typeset :hover>.headerlink,.md-typeset :target>.headerlink{opacity:1;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset .headerlink:hover,.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset :target{--md-scroll-margin:3.6rem;--md-scroll-offset:0rem;scroll-margin-top:calc(var(--md-scroll-margin) - var(--md-scroll-offset))}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset :target{--md-scroll-margin:6rem}}.md-typeset h1:target{--md-scroll-offset:0.1rem}.md-typeset h3:target,.md-typeset h4:target{--md-scroll-offset:-0.1rem}:root{--md-admonition-icon--mkdocstrings:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--mkdocstrings-open:url('data:image/svg+xml;charset=utf-8,')}.doc-object-name{font-family:var(--md-code-font-family)}code.doc-symbol-heading{margin-right:.4rem;padding:0}[dir=ltr] .doc-labels{margin-left:.4rem}[dir=rtl] .doc-labels{margin-right:.4rem}.doc-label code{background:#0000;border:1px solid var(--md-default-fg-color--lightest);border-radius:.5rem;color:var(--md-default-fg-color--light);font-weight:400;padding-left:.3rem;padding-right:.3rem;vertical-align:text-bottom}.doc-contents td code{word-break:normal!important}.doc-md-description,.doc-md-description>p:first-child{display:inline}.md-typeset h5 .doc-object-name{text-transform:none}.doc .md-typeset__table,.doc .md-typeset__table table{display:table!important;width:100%}.doc .md-typeset__table tr{display:table-row}.doc-param-default,.doc-type_param-default{float:right}.doc-heading-parameter,.doc-heading-type_parameter{display:inline}.md-typeset .doc-heading-parameter{font-size:inherit}.doc-heading-parameter .headerlink,.doc-heading-type_parameter .headerlink{margin-left:0!important;margin-right:.2rem}.doc-section-title{font-weight:700}.doc-signature .autorefs{color:inherit;text-decoration-style:dotted}div.doc-contents:not(.first){border-left:.05rem solid var(--md-code-bg-color);margin-left:.4rem;padding-left:.8rem}:host,:root,[data-md-color-scheme=default]{--doc-symbol-parameter-fg-color:#829bd1;--doc-symbol-type_parameter-fg-color:#829bd1;--doc-symbol-attribute-fg-color:#953800;--doc-symbol-function-fg-color:#8250df;--doc-symbol-method-fg-color:#8250df;--doc-symbol-class-fg-color:#0550ae;--doc-symbol-type_alias-fg-color:#0550ae;--doc-symbol-module-fg-color:#5cad0f}[data-md-color-scheme=slate]{--doc-symbol-parameter-fg-color:#829bd1;--doc-symbol-type_parameter-fg-color:#829bd1;--doc-symbol-attribute-fg-color:#ffa657;--doc-symbol-function-fg-color:#d2a8ff;--doc-symbol-method-fg-color:#d2a8ff;--doc-symbol-class-fg-color:#79c0ff;--doc-symbol-type_alias-fg-color:#79c0ff;--doc-symbol-module-fg-color:#baff79}.md-ellipsis:has(.doc-symbol){font-family:var(--md-code-font-family);font-size:.95em}code.doc-symbol{background-color:initial;border-radius:.1rem;font-size:1em;font-weight:400}a code.doc-symbol-parameter,code.doc-symbol-parameter{color:var(--doc-symbol-parameter-fg-color)}.md-content code.doc-symbol-parameter:after{content:"param"}.md-sidebar code.doc-symbol-parameter:after{content:"p"}a code.doc-symbol-type_parameter,code.doc-symbol-type_parameter{color:var(--doc-symbol-type_parameter-fg-color)}.md-content code.doc-symbol-type_parameter:after{content:"type-param"}.md-sidebar code.doc-symbol-type_parameter:after{content:"t"}a code.doc-symbol-attribute,code.doc-symbol-attribute{color:var(--doc-symbol-attribute-fg-color)}.md-content code.doc-symbol-attribute:after{content:"attribute"}.md-sidebar code.doc-symbol-attribute:after{content:"a"}a code.doc-symbol-function,code.doc-symbol-function{color:var(--doc-symbol-function-fg-color)}.md-content code.doc-symbol-function:after{content:"function"}.md-sidebar code.doc-symbol-function:after{content:"f"}a code.doc-symbol-method,code.doc-symbol-method{color:var(--doc-symbol-method-fg-color)}.md-content code.doc-symbol-method:after{content:"method"}.md-sidebar code.doc-symbol-method:after{content:"m"}a code.doc-symbol-class,code.doc-symbol-class{color:var(--doc-symbol-class-fg-color)}.md-content code.doc-symbol-class:after{content:"class"}.md-sidebar code.doc-symbol-class:after{content:"c"}a code.doc-symbol-type_alias,code.doc-symbol-type_alias{color:var(--doc-symbol-type_alias-fg-color)}.md-content code.doc-symbol-type_alias:after{content:"type"}.md-sidebar code.doc-symbol-type_alias:after{content:"t"}a code.doc-symbol-module,code.doc-symbol-module{color:var(--doc-symbol-module-fg-color)}.md-content code.doc-symbol-module:after{content:"module"}.md-sidebar code.doc-symbol-module:after{content:"mod"}.md-typeset details.mkdocstrings-source{background:#0000;border:.05rem solid var(--md-code-bg-color)}.md-typeset details.mkdocstrings-source>summary:before{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-admonition-icon--mkdocstrings);mask-image:var(--md-admonition-icon--mkdocstrings)}.md-typeset details.mkdocstrings-source[open]>summary:before{-webkit-mask-image:var(--md-admonition-icon--mkdocstrings-open);mask-image:var(--md-admonition-icon--mkdocstrings-open)}.md-typeset details.mkdocstrings-source>summary:after{background-color:var(--md-default-fg-color--light)}.md-typeset div.arithmatex{overflow:auto}@media screen and (max-width:44.984375em){.md-typeset div.arithmatex{margin:0 -.8rem}.md-typeset div.arithmatex>*{width:min-content}}.md-typeset div.arithmatex>*{margin-left:auto!important;margin-right:auto!important;padding:0 .8rem;touch-action:auto}.md-typeset div.arithmatex>* mjx-container{margin:0!important}.md-typeset div.arithmatex mjx-assistive-mml{height:0}.md-typeset del.critic{background-color:var(--md-typeset-del-color)}.md-typeset del.critic,.md-typeset ins.critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset ins.critic{background-color:var(--md-typeset-ins-color)}.md-typeset .critic.comment{-webkit-box-decoration-break:clone;box-decoration-break:clone;color:var(--md-code-hl-comment-color)}.md-typeset .critic.comment:before{content:"/* "}.md-typeset .critic.comment:after{content:" */"}.md-typeset .critic.block{box-shadow:none;display:block;margin:1em 0;overflow:auto;padding-left:.8rem;padding-right:.8rem}.md-typeset .critic.block>:first-child{margin-top:.5em}.md-typeset .critic.block>:last-child{margin-bottom:.5em}:root{--md-details-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset details{display:flow-root;overflow:visible;padding-top:0}.md-typeset details[open]>summary:after{transform:rotate(90deg)}.md-typeset details:not([open]){box-shadow:none;padding-bottom:0}.md-typeset details:not([open])>summary{border-radius:.1rem;margin-bottom:.6rem}[dir=ltr] .md-typeset summary{padding-right:1.6rem}[dir=rtl] .md-typeset summary{padding-left:1.6rem}[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset summary{cursor:pointer;display:block;min-height:1rem;overflow:hidden}.md-typeset summary.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset summary:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[dir=ltr] .md-typeset summary:after{right:0}[dir=rtl] .md-typeset summary:after{left:0}.md-typeset summary:after{background-color:currentcolor;content:"";height:1rem;-webkit-mask-image:var(--md-details-icon);mask-image:var(--md-details-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.125em;transform:rotate(0deg);transition:transform .25s;width:1rem}[dir=rtl] .md-typeset summary:after{transform:rotate(180deg)}.md-typeset summary::marker{display:none}.md-typeset summary::-webkit-details-marker{display:none}.md-typeset .emojione,.md-typeset .gemoji,.md-typeset .twemoji{--md-icon-size:1.125em;display:inline-flex;height:var(--md-icon-size);vertical-align:text-top}.md-typeset .emojione svg,.md-typeset .gemoji svg,.md-typeset .twemoji svg{fill:currentcolor;max-height:100%;width:var(--md-icon-size)}.md-typeset .emojione svg.lucide,.md-typeset .gemoji svg.lucide,.md-typeset .twemoji svg.lucide{fill:#0000;stroke:currentcolor}.md-typeset .lg,.md-typeset .xl,.md-typeset .xxl,.md-typeset .xxxl{vertical-align:text-bottom}.md-typeset .middle{vertical-align:middle}.md-typeset .lg{--md-icon-size:1.5em}.md-typeset .xl{--md-icon-size:2.25em}.md-typeset .xxl{--md-icon-size:3em}.md-typeset .xxxl{--md-icon-size:4em}.highlight .o,.highlight .ow{color:var(--md-code-hl-operator-color)}.highlight .p{color:var(--md-code-hl-punctuation-color)}.highlight .cpf,.highlight .l,.highlight .s,.highlight .s1,.highlight .s2,.highlight .sb,.highlight .sc,.highlight .si,.highlight .ss{color:var(--md-code-hl-string-color)}.highlight .cp,.highlight .se,.highlight .sh,.highlight .sr,.highlight .sx{color:var(--md-code-hl-special-color)}.highlight .il,.highlight .m,.highlight .mb,.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:var(--md-code-hl-number-color)}.highlight .k,.highlight .kd,.highlight .kn,.highlight .kp,.highlight .kr,.highlight .kt{color:var(--md-code-hl-keyword-color)}.highlight .kc,.highlight .n{color:var(--md-code-hl-name-color)}.highlight .bp,.highlight .nb,.highlight .no{color:var(--md-code-hl-constant-color)}.highlight .nc,.highlight .ne,.highlight .nf,.highlight .nn{color:var(--md-code-hl-function-color)}.highlight .nd,.highlight .ni,.highlight .nl,.highlight .nt{color:var(--md-code-hl-keyword-color)}.highlight .c,.highlight .c1,.highlight .ch,.highlight .cm,.highlight .cs,.highlight .sd{color:var(--md-code-hl-comment-color)}.highlight .na,.highlight .nv,.highlight .vc,.highlight .vg,.highlight .vi{color:var(--md-code-hl-variable-color)}.highlight .ge,.highlight .gh,.highlight .go,.highlight .gp,.highlight .gr,.highlight .gs,.highlight .gt,.highlight .gu{color:var(--md-code-hl-generic-color)}.highlight .gd,.highlight .gi{border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight .gd{background-color:var(--md-typeset-del-color)}.highlight .gi{background-color:var(--md-typeset-ins-color)}.highlight .hll{background-color:var(--md-code-hl-color--light);box-shadow:2px 0 0 0 var(--md-code-hl-color) inset;display:block;margin:0 -1.1764705882em;padding:0 1.1764705882em}.highlight span.filename{background-color:var(--md-code-bg-color);border-bottom:.05rem solid var(--md-default-fg-color--lightest);border-top-left-radius:.4rem;border-top-right-radius:.4rem;display:flow-root;font-size:.85em;font-weight:700;margin-top:1em;padding:.6617647059em 1.1764705882em;position:relative}.highlight span.filename+pre{margin-top:0}.highlight span.filename+pre>code{border-top-left-radius:0;border-top-right-radius:0}.highlight [data-linenos]:before{background-color:var(--md-code-bg-color);box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;color:var(--md-default-fg-color--light);content:attr(data-linenos);float:left;left:-1.1764705882em;margin-left:-1.1764705882em;margin-right:1.1764705882em;padding-left:1.1764705882em;position:sticky;-webkit-user-select:none;user-select:none;z-index:3}.highlight code>span[id^=__span]>:last-child .md-annotation{margin-right:2.4rem}.highlight code[data-md-copying]{display:initial}.highlight code[data-md-copying] .hll{display:contents}.highlight code[data-md-copying] .md-annotation{display:none}.highlighttable{display:flow-root}.highlighttable tbody,.highlighttable td{display:block;padding:0}.highlighttable tr{display:flex}.highlighttable pre{margin:0}.highlighttable th.filename{flex-grow:1;padding:0;text-align:left}.highlighttable th.filename span.filename{margin-top:0}.highlighttable .linenos{background-color:var(--md-code-bg-color);border-bottom-left-radius:.4rem;border-top-left-radius:.4rem;font-size:.85em;padding:.7720588235em 0 .7720588235em 1.1764705882em;-webkit-user-select:none;user-select:none}.highlighttable .linenodiv{box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset}.highlighttable .linenodiv pre{color:var(--md-default-fg-color--light);text-align:right}.highlighttable .linenodiv span[class]{padding-right:.5882352941em}.highlighttable .code{flex:1;min-width:0}.linenodiv a{color:inherit;text-decoration:none}.md-typeset .highlighttable{direction:ltr;margin:1em 0}.md-typeset .highlighttable>tbody>tr>.code>div>pre>code{border-bottom-left-radius:0;border-top-left-radius:0}.md-typeset .highlight+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.4rem;border-bottom-right-radius:.4rem;border-top-width:.4rem;margin-top:-1.5em;overflow:visible;padding:0 1em}.md-typeset .highlight+.result:after{clear:both;content:"";display:block}@media screen and (max-width:44.984375em){.md-content__inner>.highlight{margin:1em -.8rem}.md-content__inner>.highlight>.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.code>div>pre>code,.md-content__inner>.highlight>.highlighttable>tbody>tr>.filename span.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.linenos,.md-content__inner>.highlight>pre>code{border-radius:0}.md-content__inner>.highlight+.result{border-left-width:0;border-radius:0;border-right-width:0;margin-left:-.8rem;margin-right:-.8rem}}.md-typeset .keys kbd:after,.md-typeset .keys kbd:before{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys span{color:var(--md-default-fg-color--light);padding:0 .2em}.md-typeset .keys .key-alt:before,.md-typeset .keys .key-left-alt:before,.md-typeset .keys .key-right-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-command:before,.md-typeset .keys .key-left-command:before,.md-typeset .keys .key-right-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-control:before,.md-typeset .keys .key-left-control:before,.md-typeset .keys .key-right-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-left-meta:before,.md-typeset .keys .key-meta:before,.md-typeset .keys .key-right-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-left-option:before,.md-typeset .keys .key-option:before,.md-typeset .keys .key-right-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-left-shift:before,.md-typeset .keys .key-right-shift:before,.md-typeset .keys .key-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-left-super:before,.md-typeset .keys .key-right-super:before,.md-typeset .keys .key-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-left-windows:before,.md-typeset .keys .key-right-windows:before,.md-typeset .keys .key-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-arrow-down:before{content:"↓";padding-right:.4em}.md-typeset .keys .key-arrow-left:before{content:"←";padding-right:.4em}.md-typeset .keys .key-arrow-right:before{content:"→";padding-right:.4em}.md-typeset .keys .key-arrow-up:before{content:"↑";padding-right:.4em}.md-typeset .keys .key-backspace:before{content:"⌫";padding-right:.4em}.md-typeset .keys .key-backtab:before{content:"⇤";padding-right:.4em}.md-typeset .keys .key-caps-lock:before{content:"⇪";padding-right:.4em}.md-typeset .keys .key-clear:before{content:"⌧";padding-right:.4em}.md-typeset .keys .key-context-menu:before{content:"☰";padding-right:.4em}.md-typeset .keys .key-delete:before{content:"⌦";padding-right:.4em}.md-typeset .keys .key-eject:before{content:"⏏";padding-right:.4em}.md-typeset .keys .key-end:before{content:"⤓";padding-right:.4em}.md-typeset .keys .key-escape:before{content:"⎋";padding-right:.4em}.md-typeset .keys .key-home:before{content:"⤒";padding-right:.4em}.md-typeset .keys .key-insert:before{content:"⎀";padding-right:.4em}.md-typeset .keys .key-page-down:before{content:"⇟";padding-right:.4em}.md-typeset .keys .key-page-up:before{content:"⇞";padding-right:.4em}.md-typeset .keys .key-print-screen:before{content:"⎙";padding-right:.4em}.md-typeset .keys .key-tab:after{content:"⇥";padding-left:.4em}.md-typeset .keys .key-num-enter:after{content:"⌤";padding-left:.4em}.md-typeset .keys .key-enter:after{content:"⏎";padding-left:.4em}:root{--md-tabbed-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-tabbed-icon--next:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .tabbed-set{border-radius:.075rem;display:flex;flex-flow:column wrap;margin:1em 0;position:relative}.md-typeset .tabbed-set>input{height:0;opacity:0;position:absolute;width:0}.md-typeset .tabbed-set>input:target{--md-scroll-offset:0.625em}.md-typeset .tabbed-set>input.focus-visible~.tabbed-labels:before{background-color:var(--md-accent-fg-color)}.md-typeset .tabbed-labels{-ms-overflow-style:none;box-shadow:0 -.05rem var(--md-default-fg-color--lightest) inset;display:flex;max-width:100%;overflow:auto;scrollbar-width:none}@media print{.md-typeset .tabbed-labels{display:contents}}@media screen{.js .md-typeset .tabbed-labels{position:relative}.js .md-typeset .tabbed-labels:before{background:var(--md-default-fg-color);bottom:0;content:"";display:block;height:1.5px;left:0;position:absolute;transform:translateX(var(--md-indicator-x));transition:width 225ms,background-color .25s,transform .25s;transition-timing-function:cubic-bezier(.4,0,.2,1);width:var(--md-indicator-width)}}.md-typeset .tabbed-labels::-webkit-scrollbar{display:none}.md-typeset .tabbed-labels>label{border-bottom:.1rem solid #0000;border-radius:.1rem .1rem 0 0;color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;font-size:.7rem;font-weight:400;padding:.78125em 1.25em .625em;scroll-margin-inline-start:1rem;transition:background-color .25s,color .25s;white-space:nowrap;width:auto}@media print{.md-typeset .tabbed-labels>label:first-child{order:1}.md-typeset .tabbed-labels>label:nth-child(2){order:2}.md-typeset .tabbed-labels>label:nth-child(3){order:3}.md-typeset .tabbed-labels>label:nth-child(4){order:4}.md-typeset .tabbed-labels>label:nth-child(5){order:5}.md-typeset .tabbed-labels>label:nth-child(6){order:6}.md-typeset .tabbed-labels>label:nth-child(7){order:7}.md-typeset .tabbed-labels>label:nth-child(8){order:8}.md-typeset .tabbed-labels>label:nth-child(9){order:9}.md-typeset .tabbed-labels>label:nth-child(10){order:10}.md-typeset .tabbed-labels>label:nth-child(11){order:11}.md-typeset .tabbed-labels>label:nth-child(12){order:12}.md-typeset .tabbed-labels>label:nth-child(13){order:13}.md-typeset .tabbed-labels>label:nth-child(14){order:14}.md-typeset .tabbed-labels>label:nth-child(15){order:15}.md-typeset .tabbed-labels>label:nth-child(16){order:16}.md-typeset .tabbed-labels>label:nth-child(17){order:17}.md-typeset .tabbed-labels>label:nth-child(18){order:18}.md-typeset .tabbed-labels>label:nth-child(19){order:19}.md-typeset .tabbed-labels>label:nth-child(20){order:20}}.md-typeset .tabbed-labels>label:hover{color:var(--md-default-fg-color)}.md-typeset .tabbed-labels>label>[href]:first-child{color:inherit;text-decoration:none}.md-typeset .tabbed-labels--linked>label{padding:0}.md-typeset .tabbed-labels--linked>label>a{display:block;padding:.78125em 1.25em .625em}.md-typeset .tabbed-content{width:100%}@media print{.md-typeset .tabbed-content{display:contents}}.md-typeset .tabbed-block{display:none}@media print{.md-typeset .tabbed-block{display:block}.md-typeset .tabbed-block:first-child{order:1}.md-typeset .tabbed-block:nth-child(2){order:2}.md-typeset .tabbed-block:nth-child(3){order:3}.md-typeset .tabbed-block:nth-child(4){order:4}.md-typeset .tabbed-block:nth-child(5){order:5}.md-typeset .tabbed-block:nth-child(6){order:6}.md-typeset .tabbed-block:nth-child(7){order:7}.md-typeset .tabbed-block:nth-child(8){order:8}.md-typeset .tabbed-block:nth-child(9){order:9}.md-typeset .tabbed-block:nth-child(10){order:10}.md-typeset .tabbed-block:nth-child(11){order:11}.md-typeset .tabbed-block:nth-child(12){order:12}.md-typeset .tabbed-block:nth-child(13){order:13}.md-typeset .tabbed-block:nth-child(14){order:14}.md-typeset .tabbed-block:nth-child(15){order:15}.md-typeset .tabbed-block:nth-child(16){order:16}.md-typeset .tabbed-block:nth-child(17){order:17}.md-typeset .tabbed-block:nth-child(18){order:18}.md-typeset .tabbed-block:nth-child(19){order:19}.md-typeset .tabbed-block:nth-child(20){order:20}}.md-typeset .tabbed-block>.highlight:first-child>pre,.md-typeset .tabbed-block>pre:first-child{margin:0}.md-typeset .tabbed-block>.highlight:first-child>pre>code,.md-typeset .tabbed-block>pre:first-child>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child>.filename{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable{margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.filename span.filename,.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.linenos{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.code>div>pre>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child+.result{margin-top:-.125em}.md-typeset .tabbed-block>.tabbed-set{margin:0}.md-typeset .tabbed-button{align-self:center;-webkit-backdrop-filter:blur(.4rem);backdrop-filter:blur(.4rem);background-color:var(--md-default-bg-color--light);border-radius:100%;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);cursor:pointer;display:block;height:.9rem;margin-top:.4rem;pointer-events:auto;transition:transform 125ms;width:.9rem}.md-typeset .tabbed-button:hover{transform:scale(1.125)}.md-typeset .tabbed-button:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-tabbed-icon--prev);mask-image:var(--md-tabbed-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color .25s,transform .25s;width:100%}.md-typeset .tabbed-control{display:flex;height:1.9rem;justify-content:start;pointer-events:none;position:absolute;transition:opacity 125ms;width:1.2rem}[dir=rtl] .md-typeset .tabbed-control{transform:rotate(180deg)}.md-typeset .tabbed-control[hidden]{opacity:0}.md-typeset .tabbed-control--next{justify-content:end;right:0}.md-typeset .tabbed-control--next .tabbed-button:after{-webkit-mask-image:var(--md-tabbed-icon--next);mask-image:var(--md-tabbed-icon--next)}@media screen and (max-width:44.984375em){[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels{margin:0 -.8rem;max-width:100vw;scroll-padding-inline-start:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels:after{content:""}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-right:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-left:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-right:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{width:2rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-left:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-right:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-left:-.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{width:2rem}}@media screen{.md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){color:var(--md-default-fg-color);font-weight:500}.md-typeset .no-js .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .no-js .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .no-js .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .no-js .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .no-js .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .no-js .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .no-js .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .no-js .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .no-js .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .no-js .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .no-js .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .no-js .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .no-js .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .no-js .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .no-js .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .no-js .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .no-js .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .no-js .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .no-js .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .no-js .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.md-typeset [role=dialog] .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset [role=dialog] .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset [role=dialog] .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset [role=dialog] .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset [role=dialog] .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset [role=dialog] .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset [role=dialog] .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset [role=dialog] .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset [role=dialog] .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset [role=dialog] .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset [role=dialog] .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset [role=dialog] .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset [role=dialog] .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset [role=dialog] .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset [role=dialog] .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset [role=dialog] .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset [role=dialog] .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset [role=dialog] .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset [role=dialog] .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset [role=dialog] .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.no-js .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.no-js .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.no-js .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.no-js .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.no-js .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.no-js .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.no-js .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.no-js .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.no-js .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.no-js .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.no-js .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.no-js .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.no-js .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.no-js .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.no-js .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.no-js .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.no-js .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.no-js .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.no-js .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.no-js .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),[role=dialog] .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,[role=dialog] .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),[role=dialog] .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),[role=dialog] .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),[role=dialog] .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),[role=dialog] .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),[role=dialog] .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),[role=dialog] .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),[role=dialog] .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),[role=dialog] .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),[role=dialog] .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),[role=dialog] .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),[role=dialog] .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),[role=dialog] .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),[role=dialog] .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),[role=dialog] .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),[role=dialog] .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),[role=dialog] .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),[role=dialog] .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),[role=dialog] .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){border-color:var(--md-default-fg-color)}}.md-typeset .tabbed-set>input:first-child.focus-visible~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10).focus-visible~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11).focus-visible~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12).focus-visible~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13).focus-visible~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14).focus-visible~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15).focus-visible~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16).focus-visible~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17).focus-visible~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18).focus-visible~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19).focus-visible~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2).focus-visible~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20).focus-visible~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3).focus-visible~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4).focus-visible~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5).focus-visible~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6).focus-visible~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7).focus-visible~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8).focus-visible~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9).focus-visible~.tabbed-labels>:nth-child(9){color:var(--md-accent-fg-color)}.md-typeset .tabbed-set>input:first-child:checked~.tabbed-content>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-content>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-content>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-content>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-content>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-content>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-content>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-content>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-content>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-content>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-content>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-content>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-content>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-content>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-content>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-content>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-content>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-content>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-content>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-content>:nth-child(9){display:block}:root{--md-tasklist-icon:url('data:image/svg+xml;charset=utf-8,');--md-tasklist-icon--checked:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .task-list-item{list-style-type:none;position:relative}[dir=ltr] .md-typeset .task-list-item [type=checkbox]{left:-2em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{right:-2em}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}[dir=ltr] .md-typeset .task-list-indicator:before{left:-1.5em}[dir=rtl] .md-typeset .task-list-indicator:before{right:-1.5em}.md-typeset .task-list-indicator:before{background-color:var(--md-default-fg-color--lighter);content:"";height:1.25em;-webkit-mask-image:var(--md-tasklist-icon);mask-image:var(--md-tasklist-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.25em;width:1.25em}.md-typeset [type=checkbox]:checked+.task-list-indicator:before{background-color:#00e676;-webkit-mask-image:var(--md-tasklist-icon--checked);mask-image:var(--md-tasklist-icon--checked)}@media print{.giscus,[id=__comments]{display:none}}:root>*{--md-mermaid-font-family:var(--md-text-font-family),sans-serif;--md-mermaid-edge-color:var(--md-code-fg-color);--md-mermaid-node-bg-color:var(--md-accent-fg-color--transparent);--md-mermaid-node-fg-color:var(--md-accent-fg-color);--md-mermaid-label-bg-color:var(--md-default-bg-color);--md-mermaid-label-fg-color:var(--md-code-fg-color);--md-mermaid-sequence-actor-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actor-fg-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-actor-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-actor-line-color:var(--md-default-fg-color--lighter);--md-mermaid-sequence-actorman-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-actorman-line-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-box-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-box-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-label-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-label-fg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-loop-bg-color:var(--md-mermaid-node-bg-color);--md-mermaid-sequence-loop-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-loop-border-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-message-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-message-line-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-bg-color:var(--md-mermaid-label-bg-color);--md-mermaid-sequence-note-fg-color:var(--md-mermaid-edge-color);--md-mermaid-sequence-note-border-color:var(--md-mermaid-label-fg-color);--md-mermaid-sequence-number-bg-color:var(--md-mermaid-node-fg-color);--md-mermaid-sequence-number-fg-color:var(--md-accent-bg-color)}.mermaid{line-height:normal;margin:1em 0}.md-typeset .grid{grid-gap:.4rem;display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,16rem),1fr));margin:1em 0}.md-typeset .grid.cards>ol,.md-typeset .grid.cards>ul{display:contents}.md-typeset .grid.cards>ol>li,.md-typeset .grid.cards>ul>li,.md-typeset .grid>.card{border:.05rem solid var(--md-default-fg-color--lightest);border-radius:.4rem;display:block;margin:0;padding:.8rem;transition:background-color .25s,border .25s,box-shadow .25s}.md-typeset .grid.cards>ol>li:focus-within,.md-typeset .grid.cards>ol>li:hover,.md-typeset .grid.cards>ul>li:focus-within,.md-typeset .grid.cards>ul>li:hover,.md-typeset .grid>.card:focus-within,.md-typeset .grid>.card:hover{border-color:#0000;box-shadow:var(--md-shadow-z2)}.md-typeset .grid.cards>ol>li>hr,.md-typeset .grid.cards>ul>li>hr,.md-typeset .grid>.card>hr{margin-bottom:1em;margin-top:1em}.md-typeset .grid.cards>ol>li>:first-child,.md-typeset .grid.cards>ul>li>:first-child,.md-typeset .grid>.card>:first-child{margin-top:0}.md-typeset .grid.cards>ol>li>:last-child,.md-typeset .grid.cards>ul>li>:last-child,.md-typeset .grid>.card>:last-child{margin-bottom:0}.md-typeset .grid>*,.md-typeset .grid>.admonition,.md-typeset .grid>.highlight>*,.md-typeset .grid>.highlighttable,.md-typeset .grid>.md-typeset details,.md-typeset .grid>details,.md-typeset .grid>pre{margin-bottom:0;margin-top:0}.md-typeset .grid>.highlight>pre:only-child,.md-typeset .grid>.highlight>pre>code,.md-typeset .grid>.highlighttable,.md-typeset .grid>.highlighttable>tbody,.md-typeset .grid>.highlighttable>tbody>tr,.md-typeset .grid>.highlighttable>tbody>tr>.code,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre,.md-typeset .grid>.highlighttable>tbody>tr>.code>.highlight>pre>code{height:100%}.md-typeset .grid>.tabbed-set{margin-bottom:0;margin-top:0}@media screen and (min-width:45em){[dir=ltr] .md-typeset .inline{float:left}[dir=rtl] .md-typeset .inline{float:right}[dir=ltr] .md-typeset .inline{margin-right:.8rem}[dir=rtl] .md-typeset .inline{margin-left:.8rem}.md-typeset .inline{margin-bottom:.8rem;margin-top:0;width:11.7rem}[dir=ltr] .md-typeset .inline.end{float:right}[dir=rtl] .md-typeset .inline.end{float:left}[dir=ltr] .md-typeset .inline.end{margin-left:.8rem;margin-right:0}[dir=rtl] .md-typeset .inline.end{margin-left:0;margin-right:.8rem}} \ No newline at end of file diff --git a/site/blog/2026-01-27-building-ctx-using-ctx/index.html b/site/blog/2026-01-27-building-ctx-using-ctx/index.html index b8351796f..ceab7e9b8 100644 --- a/site/blog/2026-01-27-building-ctx-using-ctx/index.html +++ b/site/blog/2026-01-27-building-ctx-using-ctx/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + A Meta-Experiment in AI-Assisted Development - + @@ -1124,9 +1000,9 @@
  • - + AI Amnesia - + @@ -1135,9 +1011,9 @@
  • - + The Genesis - + @@ -1146,9 +1022,9 @@
  • - - The Meta-Experiment: Using amem to Build amem - + + The Meta-Experiment: Using amem to Build amem + @@ -1157,9 +1033,9 @@
  • - + The Rename - + @@ -1168,9 +1044,9 @@
  • - + YOLO Mode: Fast, but Dangerous - + @@ -1179,9 +1055,9 @@
  • - + The Dogfooding Test That Failed - + @@ -1190,9 +1066,9 @@
  • - + The Constitution versus Conventions - + @@ -1201,9 +1077,9 @@
  • - + Hooks: Harder than They Look - + @@ -1212,9 +1088,9 @@
  • - + The Session Files - + @@ -1223,9 +1099,9 @@
  • - + The Decision Log: 18 Architectural Decisions - + @@ -1234,9 +1110,9 @@
  • - + The Learning Log: 24 Gotchas and Insights - + @@ -1245,9 +1121,9 @@
  • - + Task Archives: The Completed Work - + @@ -1256,9 +1132,9 @@
  • - + What I Learned about AI-Assisted Development - + @@ -1267,9 +1143,9 @@
  • - + The Future: Recall System - + @@ -1278,9 +1154,9 @@
  • - + Conclusion - + @@ -1367,7 +1243,7 @@

    The GenesisThere is no step 3.

  • The first commit was just scaffolding. But within hours, the -Ralph Loop (An iterative AI development workflow) +Ralph Loop (An iterative AI development workflow) had produced a working CLI:

    feat(cli): implement amem init command
     feat(cli): implement amem status command
    @@ -1846,10 +1722,10 @@ 

    Conclusion{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-01-ctx-v0.2.0-the-archaeology-release/index.html b/site/blog/2026-02-01-ctx-v0.2.0-the-archaeology-release/index.html index 28b09d275..dc1b02ea5 100644 --- a/site/blog/2026-02-01-ctx-v0.2.0-the-archaeology-release/index.html +++ b/site/blog/2026-02-01-ctx-v0.2.0-the-archaeology-release/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + Digging through the Past to Build the Future - + @@ -1124,9 +1000,9 @@
  • - + The Problem: Amnesia Isn't Just Session-Level - + @@ -1135,9 +1011,9 @@
  • - + The Solution: Recall and Journal - + @@ -1147,9 +1023,9 @@
  • - - ctx recall: Browse Your Past - + + ctx recall: Browse Your Past + @@ -1158,9 +1034,9 @@
  • - - ctx journal: From Raw to Rich - + + ctx journal: From Raw to Rich + @@ -1174,9 +1050,9 @@
  • - + The Meta: Slash Commands for Self-Analysis - + @@ -1185,9 +1061,9 @@
  • - + The Structure: Decisions as First-Class Citizens - + @@ -1196,9 +1072,9 @@
  • - + The Order: Newest First - + @@ -1207,9 +1083,9 @@
  • - + The Index: Quick Reference Tables - + @@ -1218,9 +1094,9 @@
  • - - The Configuration: .contextrc - + + The Configuration: .contextrc + @@ -1229,9 +1105,9 @@
  • - + The Flags: Global CLI Options - + @@ -1240,9 +1116,9 @@
  • - + The Refactoring: Under the Hood - + @@ -1251,9 +1127,9 @@
  • - + What We Learned Building v0.2.0 - + @@ -1263,9 +1139,9 @@
  • - + 1. Raw Data Isn't Knowledge - + @@ -1274,9 +1150,9 @@
  • - + 2. Enforcement > Documentation - + @@ -1285,9 +1161,9 @@
  • - + 3. Token Budget Is UX - + @@ -1296,9 +1172,9 @@
  • - + 4. Meta-Tools Compound - + @@ -1312,9 +1188,9 @@
  • - + v0.2.0 in the Numbers - + @@ -1323,9 +1199,9 @@
  • - + What's Next - + @@ -1334,9 +1210,9 @@
  • - + Get Started - + @@ -1592,7 +1468,7 @@

    The Index: Quick Reference Tables

  • The Configuration: .contextrc

    -

    Projects can now customize ctx behavior +

    Projects can now customize ctx behavior via .contextrc.

    This makes ctx usable in real teams, not just personal projects.

    Priority order: CLI flags > environment variables > .contextrc > @@ -1800,10 +1676,10 @@

    Get Started{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-01-refactoring-with-intent/index.html b/site/blog/2026-02-01-refactoring-with-intent/index.html index eec4c43c5..906ffa3a2 100644 --- a/site/blog/2026-02-01-refactoring-with-intent/index.html +++ b/site/blog/2026-02-01-refactoring-with-intent/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + Human-Guided Sessions in AI Development - + @@ -1124,9 +1000,9 @@
  • - + The Velocity Trap - + @@ -1135,9 +1011,9 @@
  • - - The Shift: From Velocity to Intent - + + The Shift: From Velocity to Intent + @@ -1146,9 +1022,9 @@
  • - - The Decomposition: embed.go - + + The Decomposition: embed.go + @@ -1157,9 +1033,9 @@
  • - + The Documentation Debt - + @@ -1169,9 +1045,9 @@
  • - + Terminology Fixes - + @@ -1180,9 +1056,9 @@
  • - + Go Docstrings - + @@ -1191,9 +1067,9 @@
  • - + CLI Output Convention - + @@ -1207,9 +1083,9 @@
  • - + The Journal System - + @@ -1218,9 +1094,9 @@
  • - + The Constants Consolidation - + @@ -1229,9 +1105,9 @@
  • - + I (Re)Learned My Lessons - + @@ -1241,9 +1117,9 @@
  • - + 1. Velocity and Quality Aren't Opposites - + @@ -1252,9 +1128,9 @@
  • - - 2. Documentation IS Code - + + 2. Documentation IS Code + @@ -1263,9 +1139,9 @@
  • - + 3. Decomposition > Deletion - + @@ -1274,9 +1150,9 @@
  • - + 4. Meta-Tools Pay Dividends - + @@ -1290,9 +1166,9 @@
  • - + The Release: v0.2.0 - + @@ -1301,9 +1177,9 @@
  • - + The Meta Continues - + @@ -1796,10 +1672,10 @@

    The Meta Continues{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-03-the-attention-budget/index.html b/site/blog/2026-02-03-the-attention-budget/index.html index 148572d94..1a51dae24 100644 --- a/site/blog/2026-02-03-the-attention-budget/index.html +++ b/site/blog/2026-02-03-the-attention-budget/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + Why Your AI Forgets What You Just Told It - + @@ -1124,9 +1000,9 @@
  • - + The Finite Resource Nobody Talks About - + @@ -1135,9 +1011,9 @@
  • - + The Middle Gets Lost - + @@ -1146,9 +1022,9 @@
  • - - ctx Primitives - + + ctx Primitives + @@ -1158,9 +1034,9 @@
  • - + Primitive 1: Separation of Concerns - + @@ -1169,9 +1045,9 @@
  • - + Primitive 2: Explicit Budgets - + @@ -1180,9 +1056,9 @@
  • - + Primitive 3: Indexes over Full Content - + @@ -1191,9 +1067,9 @@
  • - + Primitive 4: Filesystem as Navigation - + @@ -1207,9 +1083,9 @@
  • - + Progressive Disclosure in Practice - + @@ -1218,9 +1094,9 @@
  • - + Quality over Quantity - + @@ -1229,9 +1105,9 @@
  • - + Designing for Degradation - + @@ -1240,9 +1116,9 @@
  • - - The ctx Philosophy - + + The ctx Philosophy + @@ -1251,9 +1127,9 @@
  • - + The Mental Model - + @@ -1733,10 +1609,10 @@

    The Mental Model{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-04-skills-that-fight-the-platform/index.html b/site/blog/2026-02-04-skills-that-fight-the-platform/index.html index 1f7a1a727..28c662559 100644 --- a/site/blog/2026-02-04-skills-that-fight-the-platform/index.html +++ b/site/blog/2026-02-04-skills-that-fight-the-platform/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + When Your Custom Prompts Work against You - + @@ -1124,9 +1000,9 @@
  • - + The System Prompt You Don't See - + @@ -1135,9 +1011,9 @@
  • - + Conflict Pattern 1: Judgment Suppression - + @@ -1146,9 +1022,9 @@
  • - + Conflict Pattern 2: Redundant Guidance - + @@ -1157,9 +1033,9 @@
  • - + Conflict Pattern 3: Guilt-Tripping - + @@ -1168,9 +1044,9 @@
  • - + Conflict Pattern 4: Phantom Dependencies - + @@ -1179,9 +1055,9 @@
  • - + Conflict Pattern 5: Universal Triggers - + @@ -1190,9 +1066,9 @@
  • - + The Litmus Test - + @@ -1201,9 +1077,9 @@
  • - + What Good Skills Look Like - + @@ -1212,9 +1088,9 @@
  • - + Appendix: Bad Skill → Fixed Skill - + @@ -1224,9 +1100,9 @@
  • - + Example 1: Overbearing Safety - + @@ -1235,9 +1111,9 @@
  • - + Example 2: Redundant Minimalism - + @@ -1246,9 +1122,9 @@
  • - + Example 3: Guilt-Based Verification - + @@ -1257,9 +1133,9 @@
  • - + Example 4: Phantom Tooling - + @@ -1268,9 +1144,9 @@
  • - + Example 5: Universal Trigger - + @@ -1284,9 +1160,9 @@
  • - + The Meta-Lesson - + @@ -1742,10 +1618,10 @@

    The Meta-Lesson{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-05-you-cant-import-expertise/index.html b/site/blog/2026-02-05-you-cant-import-expertise/index.html index 0ffef2deb..bae531b3c 100644 --- a/site/blog/2026-02-05-you-cant-import-expertise/index.html +++ b/site/blog/2026-02-05-you-cant-import-expertise/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + Why Good Skills Can't Be Copy-Pasted - + @@ -1124,9 +1000,9 @@
  • - + The Skill Looked Great on Paper - + @@ -1135,9 +1011,9 @@
  • - + Applying E/A/R: The 70-20-10 Split - + @@ -1147,9 +1023,9 @@
  • - + What Was Redundant (~70%) - + @@ -1163,9 +1039,9 @@
  • - - What Does a B+ in Code Organization Actually Mean?! - + + What Does a B+ in Code Organization Actually Mean?! + @@ -1175,9 +1051,9 @@
  • - - What Was Activation (~10%) - + + What Was Activation (~10%) + @@ -1186,9 +1062,9 @@
  • - - What Was Expert (~20%) - + + What Was Expert (~20%) + @@ -1202,9 +1078,9 @@
  • - + What the Skill Didn't Know - + @@ -1213,9 +1089,9 @@
  • - + The Adapted Skill - + @@ -1224,9 +1100,9 @@
  • - + The Deeper Pattern - + @@ -1235,9 +1111,9 @@
  • - + The Template Trap - + @@ -1246,9 +1122,9 @@
  • - + The Litmus Test - + @@ -1257,9 +1133,9 @@
  • - + What Good Adaptation Looks Like - + @@ -1731,10 +1607,10 @@

    What Good Adaptation Looks Like{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-07-the-anatomy-of-a-skill-that-works/index.html b/site/blog/2026-02-07-the-anatomy-of-a-skill-that-works/index.html index fcf5a6e21..cbcf72816 100644 --- a/site/blog/2026-02-07-the-anatomy-of-a-skill-that-works/index.html +++ b/site/blog/2026-02-07-the-anatomy-of-a-skill-that-works/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + What 20 Skill Rewrites Taught Me about Guiding AI - + @@ -1124,9 +1000,9 @@
  • - + The Starting Point - + @@ -1135,9 +1011,9 @@
  • - + The Pattern That Emerged - + @@ -1146,9 +1022,9 @@
  • - + Lesson 1: Quality Gates Prevent Premature Execution - + @@ -1157,9 +1033,9 @@
  • - - Lesson 2: "When NOT to Use" Is Not Optional - + + Lesson 2: "When NOT to Use" Is Not Optional + @@ -1168,9 +1044,9 @@
  • - + Lesson 3: Examples Set Boundaries Better than Rules - + @@ -1179,9 +1055,9 @@
  • - + Lesson 4: Skills Are Read by Agents, Not Humans - + @@ -1190,9 +1066,9 @@
  • - + Lesson 5: The Description Field Is the Trigger - + @@ -1201,9 +1077,9 @@
  • - + Lesson 6: Flag Tables Beat Prose - + @@ -1212,9 +1088,9 @@
  • - + Lesson 7: Template Drift Is a Real Maintenance Burden - + @@ -1223,9 +1099,9 @@
  • - + The Rewrite Scorecard - + @@ -1234,9 +1110,9 @@
  • - + The Meta-Lesson - + @@ -1710,10 +1586,10 @@

    The Meta-Lesson{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-08-not-everything-is-a-skill/index.html b/site/blog/2026-02-08-not-everything-is-a-skill/index.html index 8ed729bdb..4110d3965 100644 --- a/site/blog/2026-02-08-not-everything-is-a-skill/index.html +++ b/site/blog/2026-02-08-not-everything-is-a-skill/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + What a Codebase Audit Taught Me about Restraint - + @@ -1124,9 +1000,9 @@
  • - + The Audit - + @@ -1135,9 +1011,9 @@
  • - + The Question - + @@ -1146,9 +1022,9 @@
  • - + Recipes vs Skills - + @@ -1157,9 +1033,9 @@
  • - + What the Audit Actually Produced - + @@ -1168,9 +1044,9 @@
  • - + The Audit Prompt - + @@ -1179,9 +1055,9 @@
  • - + The Deeper Pattern - + @@ -1190,9 +1066,9 @@
  • - - This Mindset in the Context of ctx - + + This Mindset in the Context of ctx + @@ -1748,10 +1624,10 @@

    This Mindset in the Context of {"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-09-defense-in-depth-securing-ai-agents/index.html b/site/blog/2026-02-09-defense-in-depth-securing-ai-agents/index.html index aefcb4913..fb998871f 100644 --- a/site/blog/2026-02-09-defense-in-depth-securing-ai-agents/index.html +++ b/site/blog/2026-02-09-defense-in-depth-securing-ai-agents/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + When Markdown Is Not a Security Boundary - + @@ -1124,9 +1000,9 @@
  • - + The Realization - + @@ -1135,9 +1011,9 @@
  • - + Five Layers, Each with a Hole - + @@ -1147,9 +1023,9 @@
  • - + Layer 1: Soft Instructions (Probabilistic) - + @@ -1158,9 +1034,9 @@
  • - - Layer 2: Application Controls (Deterministic at Runtime, Mutable across Iterations) - + + Layer 2: Application Controls (Deterministic at Runtime, Mutable across Iterations) + @@ -1169,9 +1045,9 @@
  • - - Layer 3: OS-Level Isolation (Unbypassable) - + + Layer 3: OS-Level Isolation (Unbypassable) + @@ -1180,9 +1056,9 @@
  • - + Layer 4: Network Controls - + @@ -1191,9 +1067,9 @@
  • - + Layer 5: Infrastructure Isolation - + @@ -1207,9 +1083,9 @@
  • - + The Pattern - + @@ -1218,9 +1094,9 @@
  • - + Common Mistakes I See - + @@ -1229,9 +1105,9 @@
  • - + The Connection to Context Engineering - + @@ -1240,9 +1116,9 @@
  • - + The Checklist - + @@ -1251,9 +1127,9 @@
  • - - What Changed in ctx - + + What Changed in ctx + @@ -1746,10 +1622,10 @@

    What Changed in ctx{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-12-how-deep-is-too-deep/index.html b/site/blog/2026-02-12-how-deep-is-too-deep/index.html index 4a9331a34..670e80a9d 100644 --- a/site/blog/2026-02-12-how-deep-is-too-deep/index.html +++ b/site/blog/2026-02-12-how-deep-is-too-deep/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + When "Master ML" Is the Wrong Next Step - + @@ -1124,9 +1000,9 @@
  • - + The Hierarchy Nobody Questions - + @@ -1135,9 +1011,9 @@
  • - - The Honest Observation - + + The Honest Observation + @@ -1146,9 +1022,9 @@
  • - + Same Tools, Different Regime - + @@ -1157,9 +1033,9 @@
  • - + Why Scaling Laws Feel Alien - + @@ -1168,9 +1044,9 @@
  • - + Where Depth Actually Pays Off - + @@ -1179,9 +1055,9 @@
  • - + The Connection to Context Engineering - + @@ -1190,9 +1066,9 @@
  • - + Agentic Systems Are Not an ML Problem - + @@ -1201,9 +1077,9 @@
  • - + The Real Answer - + @@ -1212,9 +1088,9 @@
  • - + A Practical Litmus Test - + @@ -1223,9 +1099,9 @@
  • - - The ctx Lesson - + + The ctx Lesson + @@ -1234,9 +1110,9 @@
  • - + Closing Thought - + @@ -1680,10 +1556,10 @@

    Closing Thought{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-14-irc-as-context/index.html b/site/blog/2026-02-14-irc-as-context/index.html index 68d364514..7e34a3dea 100644 --- a/site/blog/2026-02-14-irc-as-context/index.html +++ b/site/blog/2026-02-14-irc-as-context/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + The Reset Problem - + @@ -1124,9 +1000,9 @@
  • - + Stateless Protocol, Stateful Life - + @@ -1135,9 +1011,9 @@
  • - + The Bouncer Pattern - + @@ -1146,9 +1022,9 @@
  • - + Presence without Flapping - + @@ -1157,9 +1033,9 @@
  • - + Before LLM Context Windows - + @@ -1168,9 +1044,9 @@
  • - + Minimal Architecture - + @@ -1179,9 +1055,9 @@
  • - + Platform Memory - + @@ -1190,9 +1066,9 @@
  • - + Signal Density - + @@ -1201,9 +1077,9 @@
  • - + Infrastructure as Cognition - + @@ -1212,9 +1088,9 @@
  • - + Build It - + @@ -1223,9 +1099,9 @@
  • - + MOTD - + @@ -1560,10 +1436,10 @@

    MOTD&par - + - + diff --git a/site/blog/2026-02-14-parallel-agents-with-worktrees/index.html b/site/blog/2026-02-14-parallel-agents-with-worktrees/index.html index 73fc87b82..809fa8191 100644 --- a/site/blog/2026-02-14-parallel-agents-with-worktrees/index.html +++ b/site/blog/2026-02-14-parallel-agents-with-worktrees/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + The Backlog Problem - + @@ -1124,9 +1000,9 @@
  • - + The Insight: File Overlap Is the Constraint - + @@ -1135,9 +1011,9 @@
  • - + Git Worktrees: The Mechanism - + @@ -1146,9 +1022,9 @@
  • - + The Setup - + @@ -1157,9 +1033,9 @@
  • - + What Actually Happened - + @@ -1168,9 +1044,9 @@
  • - - The TASKS.md Conflict - + + The TASKS.md Conflict + @@ -1179,9 +1055,9 @@
  • - + Limits - + @@ -1190,9 +1066,9 @@
  • - + The Pattern - + @@ -1201,9 +1077,9 @@
  • - + Should This Be a Skill? - + @@ -1212,9 +1088,9 @@
  • - + The Takeaway - + @@ -1586,10 +1462,10 @@

    The Takeaway{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-15-ctx-v0.3.0-the-discipline-release/index.html b/site/blog/2026-02-15-ctx-v0.3.0-the-discipline-release/index.html index b5e8ecdbe..f0aa4283d 100644 --- a/site/blog/2026-02-15-ctx-v0.3.0-the-discipline-release/index.html +++ b/site/blog/2026-02-15-ctx-v0.3.0-the-discipline-release/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + When the Ratio of Polish to Features Is 3:1, You Know Something Changed - + @@ -1124,9 +1000,9 @@
  • - + The Migration: Commands to Skills - + @@ -1135,9 +1011,9 @@
  • - + The Skill Sweep - + @@ -1146,9 +1022,9 @@
  • - + The Consolidation Sweep - + @@ -1157,9 +1033,9 @@
  • - + The E/A/R Framework - + @@ -1168,9 +1044,9 @@
  • - + Backup and Monitoring Infrastructure - + @@ -1179,9 +1055,9 @@
  • - + The Numbers - + @@ -1190,9 +1066,9 @@
  • - + What v0.3.0 Means - + @@ -1201,9 +1077,9 @@
  • - + What Comes Next - + @@ -1653,10 +1529,10 @@

    What Comes Next{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-15-eight-ways-a-hook-can-talk/index.html b/site/blog/2026-02-15-eight-ways-a-hook-can-talk/index.html index 6d63186a5..024feb119 100644 --- a/site/blog/2026-02-15-eight-ways-a-hook-can-talk/index.html +++ b/site/blog/2026-02-15-eight-ways-a-hook-can-talk/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + When Your Warning Disappears - + @@ -1124,9 +1000,9 @@
  • - + The Audit - + @@ -1136,9 +1012,9 @@
  • - + 1. Hard Gate - + @@ -1147,9 +1023,9 @@
  • - + 2. VERBATIM Relay - + @@ -1158,9 +1034,9 @@
  • - + 3. Agent Directive - + @@ -1169,9 +1045,9 @@
  • - + 4. Silent Context Injection - + @@ -1180,9 +1056,9 @@
  • - + 5. Silent Side-Effect - + @@ -1196,9 +1072,9 @@
  • - + The Patterns We Don't Have Yet - + @@ -1207,9 +1083,9 @@
  • - + The Principle - + @@ -1460,10 +1336,10 @@

    The Principle{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-15-why-zensical/index.html b/site/blog/2026-02-15-why-zensical/index.html index 8006a38e7..b3fcb103e 100644 --- a/site/blog/2026-02-15-why-zensical/index.html +++ b/site/blog/2026-02-15-why-zensical/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - - Why ctx's Journal Site Runs on a v0.0.21 Tool - + + Why ctx's Journal Site Runs on a v0.0.21 Tool + @@ -1124,9 +1000,9 @@
  • - + The Problem - + @@ -1135,9 +1011,9 @@
  • - + The Evaluation - + @@ -1147,9 +1023,9 @@
  • - + 1. The Team - + @@ -1158,9 +1034,9 @@
  • - + 2. The Architecture - + @@ -1169,9 +1045,9 @@
  • - + 3. The Migration Path - + @@ -1180,9 +1056,9 @@
  • - + 4. The Dependency Tree - + @@ -1191,9 +1067,9 @@
  • - + 5. The Fit - + @@ -1207,9 +1083,9 @@
  • - + The Caveat - + @@ -1218,9 +1094,9 @@
  • - + The Evaluation Framework - + @@ -1229,9 +1105,9 @@
  • - + The Broader Pattern - + @@ -1456,7 +1332,7 @@

    The Caveatpipx, which creates an isolated environment with the correct Python version automatically.

    That kind of friction is typical for young Python tooling, and it is documented -in the Common Workflows guide.

    +in the Getting Started guide.

    And 3,000 stars at v0.0.21 is strong early traction, but it's still early: The community is small. When something breaks, you're reading source code, not documentation.

    @@ -1718,10 +1594,10 @@

    The Broader Pattern{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-16-ctx-v0.6.0-the-integration-release/index.html b/site/blog/2026-02-16-ctx-v0.6.0-the-integration-release/index.html index d60716de6..595b593c7 100644 --- a/site/blog/2026-02-16-ctx-v0.6.0-the-integration-release/index.html +++ b/site/blog/2026-02-16-ctx-v0.6.0-the-integration-release/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + Two Commands to Persistent Memory - + @@ -1124,9 +1000,9 @@
  • - + Before: Six Shell Scripts and a Prayer - + @@ -1135,9 +1011,9 @@
  • - + After: One Plugin, Zero Shell Scripts - + @@ -1146,9 +1022,9 @@
  • - + The Plugin Model - + @@ -1157,9 +1033,9 @@
  • - + Beyond the Plugin: What Else Shipped - + @@ -1169,9 +1045,9 @@
  • - + Obsidian Vault Export - + @@ -1180,9 +1056,9 @@
  • - + Encrypted Scratchpad - + @@ -1191,9 +1067,9 @@
  • - + Security Hardening - + @@ -1202,9 +1078,9 @@
  • - + Hooks That Know When to Be Quiet - + @@ -1218,9 +1094,9 @@
  • - + The Numbers - + @@ -1229,9 +1105,9 @@
  • - - What Does v0.6.0 Mean for ctx? - + + What Does v0.6.0 Mean for ctx? + @@ -1240,9 +1116,9 @@
  • - + What Comes Next - + @@ -1669,10 +1545,10 @@

    What Comes Next{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-17-code-is-cheap-judgment-is-not/index.html b/site/blog/2026-02-17-code-is-cheap-judgment-is-not/index.html index 1d90e5ca0..577654e62 100644 --- a/site/blog/2026-02-17-code-is-cheap-judgment-is-not/index.html +++ b/site/blog/2026-02-17-code-is-cheap-judgment-is-not/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + Why AI Replaces Effort, Not Expertise - + @@ -1124,9 +1000,9 @@
  • - + The Three Confusions - + @@ -1135,9 +1011,9 @@
  • - + Code Is Nothing - + @@ -1146,9 +1022,9 @@
  • - - The Evidence from Building ctx - + + The Evidence from Building ctx + @@ -1158,9 +1034,9 @@
  • - + YOLO Mode Proved Production Is Cheap - + @@ -1169,9 +1045,9 @@
  • - + The 3:1 Ratio Proved Judgment Has a Cadence - + @@ -1180,9 +1056,9 @@
  • - + The Attention Budget Proved Framing Is Scarce - + @@ -1191,9 +1067,9 @@
  • - + Skills Design Proved Taste Is Load-Bearing - + @@ -1202,9 +1078,9 @@
  • - + Automation Discipline Proved Restraint Is a Skill - + @@ -1213,9 +1089,9 @@
  • - + Defense in Depth Proved Boundaries Require Judgment - + @@ -1224,9 +1100,9 @@
  • - + Parallel Agents Proved Scale Amplifies the Gap - + @@ -1240,9 +1116,9 @@
  • - + The Two Reactions - + @@ -1251,9 +1127,9 @@
  • - + What This Means in Practice - + @@ -1262,9 +1138,9 @@
  • - + If Anything, I Feel Empowered - + @@ -1273,9 +1149,9 @@
  • - + The Arc - + @@ -1704,10 +1580,10 @@

    The Arc{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-17-context-as-infrastructure/index.html b/site/blog/2026-02-17-context-as-infrastructure/index.html index 43b8b6134..761b0eb5b 100644 --- a/site/blog/2026-02-17-context-as-infrastructure/index.html +++ b/site/blog/2026-02-17-context-as-infrastructure/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + Why Your AI Needs a Filesystem, Not a Prompt - + @@ -1124,9 +1000,9 @@
  • - + The Prompt Paradigm - + @@ -1135,9 +1011,9 @@
  • - + The Infrastructure Paradigm - + @@ -1146,9 +1022,9 @@
  • - + Separation of Concerns - + @@ -1157,9 +1033,9 @@
  • - + The Two-Tier Persistence Model - + @@ -1168,9 +1044,9 @@
  • - + Decision Records as First-Class Citizens - + @@ -1179,9 +1055,9 @@
  • - + The "IDE Is the Interface" Decision - + @@ -1190,9 +1066,9 @@
  • - + Progressive Disclosure for AI - + @@ -1201,9 +1077,9 @@
  • - + The Philosophical Shift - + @@ -1212,9 +1088,9 @@
  • - - Beyond ctx: The Principles - + + Beyond ctx: The Principles + @@ -1223,9 +1099,9 @@
  • - + The Arc - + @@ -1828,10 +1704,10 @@

    The Arc{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-17-parallel-agents-merge-debt-and-the-myth-of-overnight-progress/index.html b/site/blog/2026-02-17-parallel-agents-merge-debt-and-the-myth-of-overnight-progress/index.html index 75d32ece3..1933dcc8e 100644 --- a/site/blog/2026-02-17-parallel-agents-merge-debt-and-the-myth-of-overnight-progress/index.html +++ b/site/blog/2026-02-17-parallel-agents-merge-debt-and-the-myth-of-overnight-progress/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + When the Screen Looks like Progress - + @@ -1124,9 +1000,9 @@
  • - + The Unit of Scale Is Not the Agent - + @@ -1135,9 +1011,9 @@
  • - - The "Five Agent" Rule - + + The "Five Agent" Rule + @@ -1146,9 +1022,9 @@
  • - + Role Separation Beats File Locking - + @@ -1157,9 +1033,9 @@
  • - + When Terminals Stop Scaling - + @@ -1168,9 +1044,9 @@
  • - + The Overnight Loop Illusion - + @@ -1179,9 +1055,9 @@
  • - + Skills That Fight the Platform - + @@ -1190,9 +1066,9 @@
  • - + Hooks Are Context That Execute - + @@ -1201,9 +1077,9 @@
  • - + Complexity Is a Tax - + @@ -1212,9 +1088,9 @@
  • - + Literature Is Throughput - + @@ -1223,9 +1099,9 @@
  • - + The Real Metric - + @@ -1234,9 +1110,9 @@
  • - - ctx Was Never about Spawning More Minds - + + ctx Was Never about Spawning More Minds + @@ -1245,9 +1121,9 @@
  • - + Practical Summary - + @@ -1753,10 +1629,10 @@

    Practical Summary{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-17-the-3-1-ratio/index.html b/site/blog/2026-02-17-the-3-1-ratio/index.html index c41e96eed..657fe20c3 100644 --- a/site/blog/2026-02-17-the-3-1-ratio/index.html +++ b/site/blog/2026-02-17-the-3-1-ratio/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + Scheduling Consolidation in AI Development - + @@ -1124,9 +1000,9 @@
  • - + The Observation - + @@ -1135,9 +1011,9 @@
  • - + The Evidence: Git History - + @@ -1146,9 +1022,9 @@
  • - + What Drift Actually Looks Like - + @@ -1158,9 +1034,9 @@
  • - + Predicate Naming - + @@ -1169,9 +1045,9 @@
  • - + Magic Strings - + @@ -1180,9 +1056,9 @@
  • - + Hardcoded Permissions - + @@ -1196,9 +1072,9 @@
  • - + Why You Cannot Consolidate on Day One - + @@ -1207,9 +1083,9 @@
  • - + The Consolidation Skill - + @@ -1218,9 +1094,9 @@
  • - + The Decision Matrix - + @@ -1229,9 +1105,9 @@
  • - + Consolidation as Context Hygiene - + @@ -1240,9 +1116,9 @@
  • - + The Practice - + @@ -1251,9 +1127,9 @@
  • - + What the Ratio Is Not - + @@ -1262,9 +1138,9 @@
  • - + The Arc so Far - + @@ -1778,10 +1654,10 @@

    The Arc so Far{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-17-when-a-system-starts-explaining-itself/index.html b/site/blog/2026-02-17-when-a-system-starts-explaining-itself/index.html index 724b4fff7..ace2052d8 100644 --- a/site/blog/2026-02-17-when-a-system-starts-explaining-itself/index.html +++ b/site/blog/2026-02-17-when-a-system-starts-explaining-itself/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + Field Notes from the Moment a Private Workflow Becomes Portable - + @@ -1124,9 +1000,9 @@
  • - + The First External Signals - + @@ -1135,9 +1011,9 @@
  • - + Misclassification Is a Sign of a New Primitive - + @@ -1146,9 +1022,9 @@
  • - + The Pharmacological Metaphor - + @@ -1157,9 +1033,9 @@
  • - + Throughput on Ambiguous Work - + @@ -1168,9 +1044,9 @@
  • - + The Moment of Portability - + @@ -1179,9 +1055,9 @@
  • - + The Split Voice - + @@ -1190,9 +1066,9 @@
  • - + Systems That Generate Explainers - + @@ -1201,9 +1077,9 @@
  • - + The Absence of Metrics - + @@ -1212,9 +1088,9 @@
  • - + What Is Actually Happening - + @@ -1223,9 +1099,9 @@
  • - + The Arc - + @@ -1604,10 +1480,10 @@

    The Arc{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-25-the-homework-problem/index.html b/site/blog/2026-02-25-the-homework-problem/index.html index 7f6386f7f..c581d1367 100644 --- a/site/blog/2026-02-25-the-homework-problem/index.html +++ b/site/blog/2026-02-25-the-homework-problem/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + Teaching AI Agents to Read Before They Write - + @@ -1124,9 +1000,9 @@
  • - + TL;DR - + @@ -1135,9 +1011,9 @@
  • - + The Pattern - + @@ -1146,9 +1022,9 @@
  • - + The Setup - + @@ -1157,9 +1033,9 @@
  • - + The Delegation Trap - + @@ -1168,9 +1044,9 @@
  • - + The Timing Problem - + @@ -1179,9 +1055,9 @@
  • - + The Solution - + @@ -1190,9 +1066,9 @@
  • - + The One-Liner That Worked - + @@ -1201,9 +1077,9 @@
  • - + The Escape Hatch - + @@ -1213,9 +1089,9 @@
  • - + The Compliance Canary - + @@ -1229,9 +1105,9 @@
  • - + Heuristics Is a Jeremy Bearimy - + @@ -1241,9 +1117,9 @@
  • - + Session 1: Total Blindness - + @@ -1252,9 +1128,9 @@
  • - + Session 2: Shallow Compliance - + @@ -1263,9 +1139,9 @@
  • - + Session 3: Conscious Rejection - + @@ -1274,9 +1150,9 @@
  • - + Session 4: The Skip-and-Relay - + @@ -1285,9 +1161,9 @@
  • - + Session 5: Full Compliance - + @@ -1296,9 +1172,9 @@
  • - + The Progression - + @@ -1312,9 +1188,9 @@
  • - + The Escape Hatch Problem - + @@ -1323,9 +1199,9 @@
  • - + The Residual Risk - + @@ -1334,9 +1210,9 @@
  • - + The Feedback Loop - + @@ -1345,9 +1221,9 @@
  • - + A Note on Precision - + @@ -1356,9 +1232,9 @@
  • - + Agent Behavior Testing Rule - + @@ -1368,9 +1244,9 @@
  • - + The Wrong Way to Test - + @@ -1379,9 +1255,9 @@
  • - + The Right Way to Test - + @@ -1390,9 +1266,9 @@
  • - + What the Agent Actually Did - + @@ -1406,9 +1282,9 @@
  • - + What I've Learned - + @@ -1418,9 +1294,9 @@
  • - + 1. Instructions Compete for Attention - + @@ -1429,9 +1305,9 @@
  • - + 2. Delegation Chains Decay - + @@ -1440,9 +1316,9 @@
  • - + 3. Social Accountability Changes Behavior - + @@ -1451,9 +1327,9 @@
  • - + 4. Timing Batters More than Wording - + @@ -1462,9 +1338,9 @@
  • - + 5. Agent Testing Requires Indirection - + @@ -1473,9 +1349,9 @@
  • - + 6. Better Comprehension Enables Better Rationalization - + @@ -1484,9 +1360,9 @@
  • - + 7. Observable Failure Beats Silent Compliance - + @@ -1495,9 +1371,9 @@
  • - + 8. Context Files Are a Feedback Loop - + @@ -1511,9 +1387,9 @@
  • - + The Principle - + @@ -1522,9 +1398,9 @@
  • - + The Arc - + @@ -1533,9 +1409,9 @@
  • - + For the Interested - + @@ -1545,9 +1421,9 @@
  • - + Optimization as the Underlying Bias - + @@ -1556,9 +1432,9 @@
  • - + Attention Is a Scarce Resource - + @@ -1567,9 +1443,9 @@
  • - + Attention Is Also the Compute Bottleneck in Transformers - + @@ -1578,9 +1454,9 @@
  • - + Why Improvements Arrive as Phase Shifts - + @@ -1589,9 +1465,9 @@
  • - + Putting It All Together - + @@ -2440,10 +2316,10 @@

    Putting It All Together{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-02-28-the-last-question/index.html b/site/blog/2026-02-28-the-last-question/index.html index 7371e6c7f..3c31daaae 100644 --- a/site/blog/2026-02-28-the-last-question/index.html +++ b/site/blog/2026-02-28-the-last-question/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + The System That Never Forgets - + @@ -1124,9 +1000,9 @@
  • - + The Reboot Loop - + @@ -1135,9 +1011,9 @@
  • - + Stateless Intelligence - + @@ -1146,9 +1022,9 @@
  • - + The Tragedy Is Not the Question - + @@ -1157,9 +1033,9 @@
  • - + Substrate Migration - + @@ -1168,9 +1044,9 @@
  • - + Civilizations and Working Sets - + @@ -1179,9 +1055,9 @@
  • - + The First Continuous Mind - + @@ -1190,9 +1066,9 @@
  • - + Why the Answer Becomes Possible - + @@ -1201,9 +1077,9 @@
  • - + Field Note - + @@ -1212,9 +1088,9 @@
  • - + The Arc - + @@ -1539,10 +1415,10 @@

    The Arc{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-03-04-agent-memory-is-infrastructure/index.html b/site/blog/2026-03-04-agent-memory-is-infrastructure/index.html index 3e1b02c74..afc196ebf 100644 --- a/site/blog/2026-03-04-agent-memory-is-infrastructure/index.html +++ b/site/blog/2026-03-04-agent-memory-is-infrastructure/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + The Problem Isn't Forgetting: It's Not Building Anything That Lasts. - + @@ -1124,9 +1000,9 @@
  • - + The Notepad Isn't the Problem - + @@ -1135,9 +1011,9 @@
  • - + The Memory Stack - + @@ -1146,9 +1022,9 @@
  • - + Software Systems Accumulate Knowledge - + @@ -1157,9 +1033,9 @@
  • - + What Infrastructure Means - + @@ -1168,9 +1044,9 @@
  • - - The git clone Test - + + The git clone Test + @@ -1179,9 +1055,9 @@
  • - + What Gets Lost without Infrastructure Memory - + @@ -1190,9 +1066,9 @@
  • - + Infrastructure Is Boring. That's the Point. - + @@ -1201,9 +1077,9 @@
  • - + The Cooperative Layer - + @@ -1212,9 +1088,9 @@
  • - + A Layer That Doesn't Exist Yet - + @@ -1223,9 +1099,9 @@
  • - + The Arc - + @@ -1731,10 +1607,10 @@

    The Arc{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-03-23-ctx-v0.8.0-the-architecture-release/index.html b/site/blog/2026-03-23-ctx-v0.8.0-the-architecture-release/index.html index 80eb4a192..0b49e90a9 100644 --- a/site/blog/2026-03-23-ctx-v0.8.0-the-architecture-release/index.html +++ b/site/blog/2026-03-23-ctx-v0.8.0-the-architecture-release/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + The Starting Point - + @@ -1124,9 +1000,9 @@
  • - + The Three Pillars - + @@ -1136,9 +1012,9 @@
  • - + 1. Every Package Gets a Taxonomy - + @@ -1147,9 +1023,9 @@
  • - + 2. Every String Gets a Key - + @@ -1158,9 +1034,9 @@
  • - + 3. Everything Gets a Protocol - + @@ -1174,9 +1050,9 @@
  • - + The Memory Bridge - + @@ -1185,9 +1061,9 @@
  • - + What Got Deleted - + @@ -1196,9 +1072,9 @@
  • - + Before and After - + @@ -1207,9 +1083,9 @@
  • - + Making AI-Assisted Development Easier - + @@ -1218,9 +1094,9 @@
  • - + Key Commits - + @@ -1229,9 +1105,9 @@
  • - + Lessons Learned - + @@ -1240,9 +1116,9 @@
  • - + What's Next - + @@ -1251,9 +1127,9 @@
  • - + The Arc - + @@ -1787,10 +1663,10 @@

    The Arc{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-03-23-we-broke-the-3-1-rule/index.html b/site/blog/2026-03-23-we-broke-the-3-1-rule/index.html index f78250123..d4e3336eb 100644 --- a/site/blog/2026-03-23-we-broke-the-3-1-rule/index.html +++ b/site/blog/2026-03-23-we-broke-the-3-1-rule/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + The Rule We Wrote - + @@ -1124,9 +1000,9 @@
  • - + What Happened - + @@ -1135,9 +1011,9 @@
  • - + What Compounded - + @@ -1147,9 +1023,9 @@
  • - + The String Problem - + @@ -1158,9 +1034,9 @@
  • - + The Taxonomy Problem - + @@ -1169,9 +1045,9 @@
  • - + The Type Problem - + @@ -1180,9 +1056,9 @@
  • - + The Error Problem - + @@ -1191,9 +1067,9 @@
  • - + The Output Problem - + @@ -1207,9 +1083,9 @@
  • - + The Compound Interest Math - + @@ -1218,9 +1094,9 @@
  • - + What Consolidation Actually Looked Like - + @@ -1229,9 +1105,9 @@
  • - + Lessons (Again) - + @@ -1240,9 +1116,9 @@
  • - + The Updated Rule - + @@ -1251,9 +1127,9 @@
  • - + The Arc - + @@ -1684,10 +1560,10 @@

    The Arc{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-04-02-code-structure-as-an-agent-interface/index.html b/site/blog/2026-04-02-code-structure-as-an-agent-interface/index.html index 690683b47..856f06b3b 100644 --- a/site/blog/2026-04-02-code-structure-as-an-agent-interface/index.html +++ b/site/blog/2026-04-02-code-structure-as-an-agent-interface/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + What 19 AST Tests Taught Us about Agent-Readable Code - + @@ -1124,9 +1000,9 @@
  • - + How It Began - + @@ -1135,9 +1011,9 @@
  • - + The Shell Script Problem - + @@ -1146,9 +1022,9 @@
  • - + The AST Migration - + @@ -1157,9 +1033,9 @@
  • - + The Tightening Loop - + @@ -1169,9 +1045,9 @@
  • - + Example 1: The Local Const Loophole - + @@ -1180,9 +1056,9 @@
  • - + Example 2: The Single-Character Dodge - + @@ -1191,9 +1067,9 @@
  • - + Example 3: The Replacer versus Regex - + @@ -1207,9 +1083,9 @@
  • - + A Before-and-After - + @@ -1218,9 +1094,9 @@
  • - + The Principles - + @@ -1230,9 +1106,9 @@
  • - + Cognitive Constraints - + @@ -1241,9 +1117,9 @@
  • - + Structural Constraints - + @@ -1252,9 +1128,9 @@
  • - + Operational Benefits - + @@ -1268,9 +1144,9 @@
  • - + The Numbers - + @@ -1279,9 +1155,9 @@
  • - + The Uncomfortable Implication - + @@ -1290,9 +1166,9 @@
  • - + What's Next - + @@ -1901,10 +1777,10 @@

    What's Next{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-04-06-the-watermelon-rind-anti-pattern/index.html b/site/blog/2026-04-06-the-watermelon-rind-anti-pattern/index.html index 477af5fff..b22e95e32 100644 --- a/site/blog/2026-04-06-the-watermelon-rind-anti-pattern/index.html +++ b/site/blog/2026-04-06-the-watermelon-rind-anti-pattern/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + Why Smarter Tools Make Shallower Agents - + @@ -1124,9 +1000,9 @@
  • - + A Turkish Proverb Walks into a Codebase - + @@ -1135,9 +1011,9 @@
  • - + The Experiment - + @@ -1146,9 +1022,9 @@
  • - + The Rind - + @@ -1157,9 +1033,9 @@
  • - + The Donkey's Idea - + @@ -1168,9 +1044,9 @@
  • - + The Two-Pass Compiler - + @@ -1179,9 +1055,9 @@
  • - + The Principle - + @@ -1190,9 +1066,9 @@
  • - + When Does This Apply? - + @@ -1201,9 +1077,9 @@
  • - + Takeaway - + @@ -1521,10 +1397,10 @@

    Takeaway{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/2026-06-21-the-cheapest-patch-was-the-most-expensive/index.html b/site/blog/2026-06-21-the-cheapest-patch-was-the-most-expensive/index.html index 9b29ea055..271001260 100644 --- a/site/blog/2026-06-21-the-cheapest-patch-was-the-most-expensive/index.html +++ b/site/blog/2026-06-21-the-cheapest-patch-was-the-most-expensive/index.html @@ -21,7 +21,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -58,7 +58,7 @@ - + @@ -228,15 +228,6 @@ - - - - - - - - -
  • @@ -256,27 +247,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -296,29 +266,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -338,29 +285,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -380,29 +304,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -421,23 +322,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -457,23 +341,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -554,7 +421,8 @@ - Manifesto + Manifesto + @@ -582,7 +450,8 @@ - The Thesis + The Thesis + @@ -634,7 +503,8 @@ - Blog + Blog + @@ -704,7 +574,8 @@ - Home + Home + @@ -776,7 +647,8 @@ - Recipes + Recipes + @@ -848,7 +720,8 @@ - CLI + CLI + @@ -920,7 +793,8 @@ - Reference + Reference + @@ -986,7 +860,8 @@ - Operations + Operations + @@ -1052,7 +927,8 @@ - Security + Security + @@ -1113,9 +989,9 @@
  • - + What Seven AI Coding Runs Taught Me About Cost - + @@ -1124,9 +1000,9 @@
  • - + The Shared Parser - + @@ -1135,9 +1011,9 @@
  • - + The Task at Hand - + @@ -1146,9 +1022,9 @@
  • - + The Runs - + @@ -1157,9 +1033,9 @@
  • - + The Cost Table That Looks Boring But Isn't - + @@ -1168,9 +1044,9 @@
  • - + The Patch Quality Review - + @@ -1179,9 +1055,9 @@
  • - + The Most Expensive Model Is Not Automatically Safer - + @@ -1190,9 +1066,9 @@
  • - + Scout Versus Executor - + @@ -1201,9 +1077,9 @@
  • - + Token Telemetry - + @@ -1212,9 +1088,9 @@
  • - + Workflow Enhancement - + @@ -1223,9 +1099,9 @@
  • - + The Fix: Make Problem-Space Inventory a Hard Gate - + @@ -1234,9 +1110,9 @@
  • - - What /plan Must Prove - + + What /plan Must Prove + @@ -1245,9 +1121,9 @@
  • - - The spec-kit Gotcha - + + The spec-kit Gotcha + @@ -1256,9 +1132,9 @@
  • - + Context Compression - + @@ -1267,9 +1143,9 @@
  • - + The YOLO Fun - + @@ -1278,9 +1154,9 @@
  • - + What I Would Repeat - + @@ -1289,9 +1165,9 @@
  • - + What This Experiment Can't Tell You - + @@ -1300,9 +1176,9 @@
  • - + The Takeaway - + @@ -1311,9 +1187,9 @@
  • - + Where This Connects - + @@ -2185,10 +2061,10 @@

    Where This Connects{"annotate":null,"base":"../..","features":["announce.dismiss","content.code.annotate","content.code.copy","content.code.select","content.footnote.tooltips","content.tabs.link","content.tooltips","navigation.footer","navigation.indexes","navigation.instant","navigation.instant.prefetch","navigation.path","navigation.prune","navigation.tabs","navigation.tabs.sticky","navigation.top","navigation.tracking","search.highlight"],"search":"../../assets/javascripts/workers/search.b6b7e04f.min.js","tags":null,"translations":{"clipboard.copied":"Copied to clipboard","clipboard.copy":"Copy to clipboard","search.result.more.one":"1 more on this page","search.result.more.other":"# more on this page","search.result.none":"No matching documents","search.result.one":"1 matching document","search.result.other":"# matching documents","search.result.placeholder":"Type to start searching","search.result.term.missing":"Missing","select.version":"Select version"},"version":null} + - + diff --git a/site/blog/index.html b/site/blog/index.html index d52e38b42..7f014890d 100644 --- a/site/blog/index.html +++ b/site/blog/index.html @@ -25,7 +25,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -62,7 +62,7 @@ - + @@ -234,15 +234,6 @@ - - - - - - - - -
  • @@ -262,27 +253,6 @@ - - - - - - - - - - - - - - - - - - - - -
  • @@ -302,29 +272,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -344,29 +291,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -386,29 +310,6 @@ - - - - - - - - - - - - - - - - - - - - - - -
  • @@ -427,23 +328,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -463,23 +347,6 @@ - - - - - - - - - - - - - - - - -
  • @@ -560,7 +427,8 @@ - Manifesto + Manifesto + @@ -588,7 +456,8 @@ - The Thesis + The Thesis + @@ -644,7 +513,8 @@ - Blog + Blog + @@ -660,7 +530,8 @@ - Blog + Blog +