diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index b75e7c45..eb057b42 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -110,13 +110,7 @@ jobs: - name: Prepare wheel bundle shell: bash run: | - rm -rf python/probing/bundled_web - cd web && dx bundle --release - test -f python/probing/bundled_web/public/index.html - mkdir -p python/probing/bundled_web/public/assets - cp -f web/assets/logo.svg python/probing/bundled_web/public/logo.svg 2>/dev/null || true - cp -f web/assets/logo.svg python/probing/bundled_web/public/assets/logo.svg 2>/dev/null || true - cp -f web/assets/tailwind.css python/probing/bundled_web/public/assets/tailwind.css + make frontend test -f python/probing/bundled_skills/catalog.yaml - name: Build wheels diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9d33e773..1bd93a9a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -208,13 +208,7 @@ jobs: - name: Prepare wheel bundle shell: bash run: | - rm -rf python/probing/bundled_web - cd web && dx bundle --release - test -f python/probing/bundled_web/public/index.html - mkdir -p python/probing/bundled_web/public/assets - cp -f web/assets/logo.svg python/probing/bundled_web/public/logo.svg 2>/dev/null || true - cp -f web/assets/logo.svg python/probing/bundled_web/public/assets/logo.svg 2>/dev/null || true - cp -f web/assets/tailwind.css python/probing/bundled_web/public/assets/tailwind.css + make frontend test -f python/probing/bundled_skills/catalog.yaml - name: Build wheel diff --git a/Makefile b/Makefile index 806dde0c..90183ecc 100644 --- a/Makefile +++ b/Makefile @@ -215,12 +215,14 @@ frontend: @cp -f web/assets/logo.svg $(BUNDLED_WEB_PUBLIC)/logo.svg 2>/dev/null || true @cp -f web/assets/logo.svg $(BUNDLED_WEB_PUBLIC)/assets/logo.svg 2>/dev/null || true @cp -f web/assets/tailwind.css $(BUNDLED_WEB_PUBLIC)/assets/tailwind.css + @$(PYTHON) scripts/verify_web_assets.py $(BUNDLED_WEB_PUBLIC) @rm -rf web/dist @ln -sfn ../python/probing/bundled_web/public web/dist @echo "$(BUNDLED_WEB_PUBLIC) ($$(du -sh $(BUNDLED_WEB_PUBLIC) | cut -f1))" wheel-bundle: @test -f $(BUNDLED_WEB_PUBLIC)/index.html || { echo "error: run 'make frontend' first"; exit 1; } + @$(PYTHON) scripts/verify_web_assets.py $(BUNDLED_WEB_PUBLIC) @test -f python/probing/bundled_skills/catalog.yaml \ || { echo "error: missing python/probing/bundled_skills/catalog.yaml"; exit 1; } diff --git a/REVIEW.md b/REVIEW.md new file mode 100644 index 00000000..e2067a38 --- /dev/null +++ b/REVIEW.md @@ -0,0 +1,183 @@ +# Probing 项目设计与实现评审报告 + +## 一、项目概览 + +**Probing** 是一个面向分布式 AI 训练的 Agent-Native 性能诊断系统。它通过 Rust 引擎提供 SQL 查询能力,通过 Python 插件实现训练侧数据采集,通过联邦查询实现跨 rank 诊断,并通过 Skills 系统将诊断知识固化为可执行的自动化流程。 + +| 维度 | 数据 | +|------|------| +| Rust 代码(不含 web) | ~86,290 行 | +| Python SDK | ~15,188 行 | +| Web UI (Dioxus WASM) | ~21,479 行 | +| 测试代码 | ~7,694 行 | +| Skills 定义 (YAML+MD) | ~3,555 行 | +| Workspace crate 数 | 15 | +| 诊断 Skill 数 | 13 | +| 当前版本 | 0.2.5 (Beta) | + +--- + +## 二、架构设计评价 + +### 2.1 四层分层架构 + +项目定义了清晰的四层架构模型: + +``` +L4 Experience ─ skills/ · web/ · Python hooks (UX, 诊断剧本) +L3 Control ─ probing/server · probing/cli (HTTP, MCP, inject, fan-out) +L2 Collectors ─ probing/extensions/* · python/probing/profiling (指标采集) +L1 Platform ─ probing/core · memtable · proto (SQL引擎, 联邦, 存储格式) +``` + +**亮点:** +- 依赖方向严格向下流动,proto 不依赖任何上层,core 不依赖 collectors +- 组合根(composition root)只存在于 `probing/server/src/engine.rs`,不在 L2 层散布组装逻辑 +- `modularity.md` 文档以表格形式追踪已知技术债务,标注"Done"/"Accepted"状态 +- 6 个公共接口契约(`ProbeDataSource`、`ProbeExtension`、`@table`、`skills/*/steps.yaml`、proto DTOs、Federation tags)定义了模块间的交互边界 + +**不足:** +- `probing-python` 扩展以 53K 行占据全部 extensions 的 84%,承载了 spy/crash/pprof/torch/tracing/repl/flamegraph 等多个独立功能域,内部高内聚但 crate 级别缺乏拆分 +- modularity.md 中将此标记为 "Accepted"(maturin 单 wheel 约束),属于架构决策而非疏忽 + +### 2.2 核心引擎设计 + +**DataFusion 作为 SQL 引擎**是最重要的架构决策。不重新发明 SQL parser/optimizer/executor,而是嵌入 Apache DataFusion,所有自定义表只需实现 `TableProvider` trait。这使用户可以使用标准 SQL(JOIN、窗口函数、CTE、子查询)查询运行时数据。 + +`EngineBuilder` 采用 Builder 模式链式构建引擎,`ENGINE: Lazy>` 作为进程级单例。两个核心 trait 分离关注点: +- `ProbeDataSource`:注册 SQL 表(数据面) +- `ProbeExtension`:提供配置 + HTTP API(控制面) + +### 2.3 联邦查询系统 + +联邦模块(~3,066 行)是项目最具技术深度的部分,采用三路径路由策略: + +| 路径 | 适用场景 | 机制 | +|------|---------|------| +| Path A: AggregatePushdown | 单表 `global.*` + merge-safe 聚合 | 将 SUM/COUNT/MIN/MAX 下推到各 rank,合并结果 | +| Path B: FederatedScan | 单表 `global.*` 非 pushdown | Lazy 分区扫描,流式拉取 | +| Path C: Broadcast | JOIN/CTE/UNION/子查询 | 全量广播到每个 rank,本地执行后合并 | + +路由基于 `sqlparser-rs` AST 级别分析,而非字符串匹配。查询护栏强制 broadcast 路径需要 LIMIT,自动为无 LIMIT 的 federated scan 注入 `LIMIT 10000`。每行联邦数据自动附加 6 个标签列(`_host`, `_addr`, `_rank`, `_node_rank`, `_local_rank`, `_role`)。 + +### 2.4 Memtable 存储格式 + +自描述二进制格式 MEMT,核心设计: + +- **环形缓冲区 + generation**:固定数量 chunk 组成环形缓冲,chunk 回收时 generation+1,读者通过比较 generation 前后值检测并丢弃回收 chunk +- **单写者 + 无锁读者**:写者通过 `&mut self` 保证排他,读者通过 `Acquire`/`Release` 内存序完全无锁 +- **三种后端统一抽象**:Heap(进程内)、Shm(POSIX `shm_open` 跨进程)、File(mmap 持久化) +- **per-chunk 字符串去重**:`DedupState` 在 chunk 范围内对重复字符串做哈希去重,存储为 4 字节回引用,可节省 20%+ 空间 + +这是整个项目中设计最精巧的组件之一。训练进程写入 mmap 文件,probing 服务器通过同一文件读取——零拷贝、零序列化。 + +### 2.5 Skills 诊断剧本系统 + +声明式诊断知识系统,每个 skill 由 `SKILL.md`(人类文档)+ `steps.yaml`(机器可执行)组成。`SkillBackend` trait 抽象了查询执行,使同一套 skill 可以在 CLI、Web WASM、MCP 三种环境中运行。 + +**亮点:** +- `resolve_use_global()` 自动检测 peer 数量决定是否使用 global 查询 +- `cluster_integrity_findings()` 将不完整的 fanout 自动提升为 error 级 finding +- `ensure_read_only_sql()` 强制 skill 步骤只执行 SELECT 类查询 + +**不足:** +- `expand_template` 使用朴素 `str::replace`,缺乏转义机制(实际风险低但理论上存在) +- interpretation rules 的 `when` 语法是自定义 DSL,如 `step:xxx | column:yyy | max/min(ratio) > 1.5`,非标准表达式引擎 + +--- + +## 三、实现质量评价 + +### 3.1 出色的工程实现 + +**1. TorchProbe 采样引擎**(Python, 1554 行) + +多重继承的 Mixin 架构 `TorchProbe(BaseTracer, Timer, Sampler, PythonTracer, VariableTracer)`,三个关键设计: + +- **分层采样**:`_sample_period = round(1/rate)`,每周期恰好采样一个 step,均匀分布。使用 `blake2b` 哈希确保跨 rank 一致且不扰动宿主 RNG 流 +- **Shadow Step 机制**:4:1 节奏(4 个 probed step + 1 个 baseline),shadow step 完全跳过 hook 仅记录墙钟时间,用于量化探测开销本身 +- **延迟 GPU 事件读取**:采样步将 `DelayedRecord` 存入 `_deferred` 列表,至少等待 3 步(`_DEFER_MIN_SETTLE`)才尝试非阻塞 `event.query()`,最多延迟 16 步(`_DEFER_MAX_LAG`)后强制 synchronize。后台线程 `DeferredDrainWorker` 异步执行保存 + +**2. 错误处理链** + +`EngineError` 采用 `thiserror`,通过 `#[from]` 自动转换保持完整因果链。明确拒绝 `From` 防止"字符串化"错误类型。单一边界转换 `EngineError -> DataFusionError` 避免了每个调用点重复映射。生产路径禁止 `unwrap`/`expect`/`panic!`。 + +**3. NCCL Profiler 直接符号导出** + +`nccl-profiler` 作为 cdylib 编译,直接导出 `ncclProfiler_v3` 和 `ncclProfiler_v4` C 符号。NCCL 运行时通过 dlopen 加载此符号,实现零侵入的 NCCL 操作采集。pool/pressure 机制避免了在高频采集路径上分配内存。 + +**4. Python 三层导入模式** + +通过 `is_lightweight_module()` 和 `is_probing_cli()` 区分三种加载模式,解决了 `import probing` 副作用问题——很多场景下用户只需要检查版本,不希望启动整个 Rust 引擎。 + +**5. 跨平台 GPU 后端抽象** + +GPU 扩展通过 `backend/registry.rs` 实现多后端:macOS(ioreg + sysctl)、NVIDIA(nvidia-smi)、统一 trait 接口。同时考虑了非 NVIDIA 生态(华为昇腾 HCCL shim)。 + +### 3.2 测试体系 + +两层测试结构:unit(快、隔离)和 regression(集成、契约、E2E)。 + +**亮点:** +- Rust 内嵌测试覆盖充分:`engine.rs` 780 行测试、`memtable.rs` 1,030 行测试(含 4 线程并发读写测试) +- `test_torch_probe_sampling.py`(815 行)覆盖了 settle window、force flush、RNG 不变性、inplace ReLU 兼容等边界条件 +- `api_spec.json` 作为 HTTP API 契约 SSOT,`TOP_LEVEL_ROUTES` 常量与之对齐 + +**不足:** +- `test_engine.py` 仅 24 行,Python 核心层测试覆盖不足 +- 缺少多进程 mock 的端到端联邦测试(主要通过进程内 `set_remote_query_hook` 模拟) +- `aggregate_pushdown.rs`(642 行复杂 SQL AST 操作)的测试覆盖度需验证 + +### 3.3 值得关注的技术债务 + +| # | 问题 | 严重度 | 说明 | +|---|------|--------|------| +| 1 | `probing-python` crate 过度膨胀 | 中 | 53K 行承载多个独立功能域,maturin 单 wheel 约束导致 | +| 2 | CPython 版本绑定维护负担 | 中 | 12 个版本(v2.7~v3.13)的内部结构偏移绑定,每次 CPython 更新需新增 | +| 3 | `memtable_sql.rs` 职责过重 | 中 | 2,125 行承载 mmap 发现、schema 推断、冷热分层、compaction 等 | +| 4 | 字符串匹配的错误处理 | 低 | `is_missing_table_error` 使用 `msg.contains("not found")` 判断 | +| 5 | `expand_template` 缺乏转义 | 低 | 朴素 `str::replace`,实际风险低但理论存在 | +| 6 | `ext/ray.py` 使用 `hash()` 生成 ID | 低 | Python hash 随机化导致不可复现 | +| 7 | 部分 `ext/` 异常处理过宽 | 低 | bare `except Exception: pass` 可能隐藏 bug | + +--- + +## 四、架构决策评价 + +### 4.1 优秀决策 + +1. **DataFusion 而非自研 SQL 引擎** — 避免了重新发明 parser/optimizer/executor 的巨大成本,同时获得了标准 SQL 兼容性 +2. **mmap 共享内存作为 IPC** — 三种后端统一了进程内/跨进程/持久化场景,零拷贝零序列化 +3. **声明式 Skills 系统** — 诊断知识以 YAML+MD 形式存在,新增诊断不需要重新编译 Rust +4. **联邦三路径路由** — 基于查询语义选择最优执行路径,避免一刀切的 fan-out 开销 +5. **MCP 协议集成** — 让 AI Agent 可以直接查询引擎、运行诊断 skill,写入操作受环境变量控制 +6. **Rust 核心 + Python 薄包装** — 性能关键路径在 Rust,灵活性需求在 Python,PyO3 桥接 + +### 4.2 可改进方向 + +1. **`probing-python` 拆分** — 即使 maturin 约束存在,也可以通过 feature gate 在逻辑上拆分子模块 +2. **结构化错误匹配** — 将 `is_missing_table_error` 等字符串匹配替换为 DataFusion 错误类型的结构化匹配 +3. **模板引擎升级** — Skills 模板替换引入轻量模板引擎(如 `format!` 风格或 `minijinja`),支持转义 +4. **端到端联邦测试** — 补充多进程 mock 的 E2E 联邦测试,而非仅依赖进程内 hook 模拟 +5. **Python 测试覆盖** — 加强 `test_engine.py` 等核心 Python 模块的测试深度 + +--- + +## 五、总体评价 + +### 评分 + +| 维度 | 评分 | 说明 | +|------|------|------| +| 架构设计 | ★★★★★ | 四层分层清晰,契约边界明确,组合根集中 | +| 代码质量 | ★★★★☆ | Rust 侧优秀,Python 侧良好,少量技术债务 | +| 测试体系 | ★★★★☆ | Rust 内嵌测试充分,Python 侧有提升空间 | +| 文档质量 | ★★★★★ | modularity.md 等设计文档达到工程级别 | +| 创新性 | ★★★★★ | 联邦三路径、延迟GPU读取、Shadow Step 等设计新颖 | +| 可维护性 | ★★★★☆ | 技术债务有追踪,但 probing-python 膨胀是长期隐患 | + +### 结论 + +Probing 是一个**架构成熟度很高**的分布式训练诊断系统。它成功地将 SQL 查询引擎、跨进程共享内存、联邦查询、AI Agent 集成、声明式诊断剧本等多个复杂组件组合成一个连贯的系统。Memtable 的无锁并发设计和联邦三路径路由是两个特别出色的工程实现。`modularity.md` 文档的存在表明团队有意识地管理模块边界和技术债务。 + +主要改进方向是 `probing-python` crate 的逻辑拆分、部分字符串匹配逻辑的结构化、以及 Python 侧测试覆盖的加强。整体而言,这是一个在系统设计层面超出大多数同类工具的项目——它不是在做"又一个 profiler",而是在重新定义"agent-native 诊断"的交互范式。 diff --git a/REVIEW_COMPARISON.md b/REVIEW_COMPARISON.md new file mode 100644 index 00000000..04b5ff2f --- /dev/null +++ b/REVIEW_COMPARISON.md @@ -0,0 +1,784 @@ +# Probing 深度评审与业界对比分析 + +> **评审视角**:资深系统架构师,深耕分布式训练与推理性能优化 +> **评审范围**:probing 全量代码(Rust ~86K行 + Python ~15K行 + Web ~21K行 + Skills ~3.5K行) +> **对比基准**:PyTorch Profiler、NVIDIA Nsight Systems/Compute、HTA、DeepSpeed Flops Profiler、NCCL Flight Recorder、DLRover、Coroot、DeepFlow + +--- + +## 一、Probing 项目深度分析 + +### 1.1 项目定位 + +Probing 不是一个传统意义上的 profiler。它的核心创新在于提出了 **"Agent-Native 诊断"** 范式——将性能诊断从"人工查看 trace 文件"升级为"AI Agent 通过结构化接口自动查询、归因、推荐修复方案"。 + +这一定位决定了它的架构选择与传统 profiler 根本不同: + +| 传统 Profiler | Probing | +|--------------|---------| +| 生成 trace 文件,事后离线分析 | 运行时实时查询,在线诊断 | +| 图形界面 (Nsight GUI, TensorBoard) | SQL + MCP + Skills 声明式接口 | +| 人工解读火焰图/时间线 | AI Agent 自动执行诊断剧本 | +| 单进程视角 | 联邦查询跨 rank 聚合 | +| 固定分析维度 | Skills 可扩展诊断知识库 | + +### 1.2 架构深度点评 + +#### 1.2.1 四层架构 — 评分:5.0/5.0 + +``` +L4 Experience ─ skills/ · web/ · Python hooks (UX, 诊断剧本) +L3 Control ─ probing/server · probing/cli (HTTP, MCP, inject, fan-out) +L2 Collectors ─ probing/extensions/* · python/probing/profiling (指标采集) +L1 Platform ─ probing/core · memtable · proto (SQL引擎, 联邦, 存储格式) +``` + +**架构亮点:** + +- **依赖方向严格单向向下**。proto 不依赖任何上层,core 不依赖 collectors。组合根只在 `probing/server/src/engine.rs`。这是教科书级的 Clean Architecture 实践,在 Rust 生态中罕见。 +- **6 个公共契约**(`ProbeDataSource`、`ProbeExtension`、`@table`、`skills/*/steps.yaml`、proto DTOs、Federation tags)定义了模块交互边界。契约的粒度恰当——既不过细导致碎片化,也不过粗导致耦合。 +- **`modularity.md` 以表格追踪技术债务**,标注"Done"/"Accepted"状态。这表明架构决策是有意识管理的,而非偶然演化。 +- **`AGENTS.md` 为 AI 协作设计的编码规范**,包含层级归属表、diff 规模约束(≤500行)、扩散味检查清单。这是对"AI 参与代码开发"这一新范式的务实回应。 + +**架构不足:** + +- `probing-python` 以 53K 行占据全部 extensions 的 84%,承载 spy/crash/pprof/torch/tracing/repl/flamegraph 等多个独立功能域。虽然 maturin 单 wheel 约束是客观原因,但逻辑层面的 feature gate 拆分可以缓解。 +- 联邦查询模块(3,066行)的 `aggregate_pushdown.rs`(642行复杂 SQL AST 操作)的测试覆盖度需要验证。 + +#### 1.2.2 DataFusion SQL 引擎 — 评分:5.0/5.0 + +嵌入 Apache DataFusion 作为查询引擎是项目最重要的架构决策。这意味着: + +1. **零成本获得标准 SQL 兼容性**——用户可以用 JOIN、窗口函数、CTE、子查询查询运行时数据 +2. **自定义表只需实现 `TableProvider` trait**——不需要重新发明 parser/optimizer/executor +3. **联邦查询可以下推聚合**——SUM/COUNT/MIN/MAX 推到各 rank 本地执行,只合并结果 + +`EngineBuilder` 采用 Builder 模式链式构建,`ENGINE: Lazy>` 作为进程级单例。`ProbeDataSource`(数据面)和 `ProbeExtension`(控制面)分离关注点。 + +对比业界:这是唯一一个将 SQL 查询引擎深度嵌入到训练诊断系统中的项目。PyTorch Profiler 和 Nsight Systems 都不支持结构化查询;HTA 虽然提供 Python API 但基于 DataFrame 操作,不具备声明式查询能力。 + +#### 1.2.3 Memtable 无锁存储 — 评分:5.0/5.0 + +自描述二进制格式 MEMT,整个项目中设计最精巧的组件: + +- **环形缓冲区 + generation 计数**:固定数量 chunk 组成环形缓冲,chunk 回收时 generation+1,读者通过比较 generation 前后值检测并丢弃回收 chunk +- **单写者 + 无锁读者**:写者通过 `&mut self` 保证排他,读者通过 `Acquire`/`Release` 内存序完全无锁 +- **三种后端统一抽象**:Heap(进程内)、Shm(POSIX `shm_open` 跨进程)、File(mmap 持久化) +- **per-chunk 字符串去重**:`DedupState` 在 chunk 范围内对重复字符串做哈希去重,存储为 4 字节回引用 + +训练进程写入 mmap 文件,probing 服务器通过同一文件读取——零拷贝、零序列化。这种设计使得采集开销极低,同时支持跨进程访问和持久化。 + +对比业界:NCCL Flight Recorder 也使用环形缓冲,但不支持跨进程共享内存和 SQL 查询。PyTorch Profiler 写入 Chrome Trace JSON 文件,开销大且不支持实时查询。 + +#### 1.2.4 联邦查询系统 — 评分:5.0/5.0 + +联邦模块(~3,066 行)采用三路径路由策略: + +| 路径 | 适用场景 | 机制 | 性能 | +|------|---------|------|------| +| Path A: AggregatePushdown | 单表 `global.*` + merge-safe 聚合 | 将 SUM/COUNT/MIN/MAX 下推到各 rank | O(1) 网络传输 | +| Path B: FederatedScan | 单表 `global.*` 非 pushdown | Lazy 分区扫描,流式拉取 | O(N) 网络传输 | +| Path C: Broadcast | JOIN/CTE/UNION/子查询 | 全量广播到每个 rank,本地执行后合并 | O(N²) 网络传输 | + +路由基于 `sqlparser-rs` AST 级别分析。查询护栏强制 broadcast 需要 LIMIT,自动为无 LIMIT 的 federated scan 注入 `LIMIT 10000`。每行联邦数据自动附加 6 个标签列(`_host`, `_addr`, `_rank`, `_node_rank`, `_local_rank`, `_role`)。 + +**关键技术细节:** + +- `route.rs` 中的 `classify_query()` 通过 AST 分析确定查询类型,支持嵌套 CTE 和子查询的递归分类 +- `rewrite.rs` 中的 `rewrite_for_federation()` 对原始 SQL 进行重写,注入联邦标签列和 LIMIT 护栏 +- `aggregate_pushdown.rs` 判断聚合函数是否 "merge-safe"(SUM/COUNT/MIN/MAX 安全,AVG 不安全需要拆分为 SUM/COUNT) + +对比业界:这是分布式训练诊断领域唯一实现联邦查询的系统。NCCL Flight Recorder 虽然多 rank 记录,但查询需要手动聚合。DLRover 支持 rank 故障检测但不提供查询能力。 + +#### 1.2.5 NCCL Profiler 插件 — 评分:4.5/5.0 + +通过 `ncclProfiler_v3`/`v4` C 符号导出实现零侵入 NCCL 操作采集,这是整个项目中技术最硬核的部分: + +**引用计数完成模型:** + +NCCL 的 proxy 线程在一个 progress loop 中反复进入同一 collective 的不同阶段。一个 `CollSlot` 可能被多次 `CollStart` → `ProxyStep` → `ProxyStep` → ... 调用。probing 通过 `live_children` 引用计数和 `stopped` 标志判断 collective 是否真正完成: + +```rust +// 伪代码 +fn on_coll_complete(&mut self, slot: &mut CollSlot) { + if slot.stopped && slot.live_children == 0 { + // 真正完成,记录 dwell time + } +} +``` + +**Proxy Step Wait 分解算法:** + +将 NCCL proxy 线程的等待时间分解为三段链式 dwell time: + +1. `SendGpuWait` — proxy 线程等待本地 GPU 完成 send buffer 准备 +2. `SendPeerWait` — proxy 线程等待对端 rank 的 network buffer 就绪 +3. `SendWait` — 实际发送操作耗时 + +"首次进入优先"设计:正确处理 NCCL proxy 线程的 progress loop 重试行为——只有第一次进入某状态时才记录起始时间戳,避免重复计入。 + +**v4 transSize 的权威状态过滤:** + +只在 `SendWait`/`RecvFlushWait` 状态下提取 transSize,避免在不完整状态中提取到中间值。 + +**Slot Pool 内存管理:** + +- 预分配固定大小的 slot pool,避免高频采集路径上的内存分配 +- 三重验证(bounds + liveness + 指针身份)防止 stale/foreign handle +- `pool_pressure.rs` 在 pool 接近满时自动降级采样率 +- 分片锁按 communicator hash 分片,`try_lock` 在 watchdog 路径避免阻塞 NCCL 回调 + +**Culprit/Victim 归因算法(skills/nccl_culprit_victim/steps.yaml):** + +- **Culprit** = high `send_gpu_wait`(本地 GPU 慢,导致其他 rank 等待) +- **Victim** = high `recv_wait`(等待对端发送,自身无过错) + +这一归因逻辑将低级时间戳数据转化为可操作的诊断结论,是从"数据采集"到"自动归因"的关键跃迁。 + +**扣分原因:** v3 ABI 的兼容性测试覆盖不足;`pool_pressure` 的降级阈值缺乏可配置性。 + +#### 1.2.6 TorchProbe 采样引擎 — 评分:5.0/5.0 + +Python 侧最精巧的实现(1,554 行),三个关键设计: + +**分层采样:** +- `_sample_period = round(1/rate)`,每周期恰好采样一个 step,均匀分布 +- 使用 `blake2b` 哈希确保跨 rank 一致采样同一 step,且不扰动宿主 RNG 流 +- 采样率可通过环境变量配置 + +**Shadow Step 机制:** +- 4:1 节奏(4 个 probed step + 1 个 baseline shadow step) +- Shadow step 完全跳过 hook 仅记录墙钟时间 +- 用于量化探测开销本身,自动校准 overhead 估算 + +**延迟 GPU 事件读取 (Deferred GPU Event Read):** +- 采样步将 `DelayedRecord` 存入 `_deferred` 列表 +- 至少等待 3 步(`_DEFER_MIN_SETTLE`)才尝试非阻塞 `event.query()` +- 最多延迟 16 步(`_DEFER_MAX_LAG`)后强制 synchronize +- 后台线程 `DeferredDrainWorker` 异步执行保存 + +这一设计使得 `torch.cuda.synchronize()` 调用频率从"每个采样步一次"降低到"每 16 步一次",大幅降低了采样对训练吞吐量的影响。 + +对比业界:PyTorch Profiler 的 GPU 事件读取需要显式 synchronize,开销大。Nsight Systems 通过驱动级 hook 避免了这个问题,但无法在 Python 层面进行结构化分析。 + +#### 1.2.7 Skills 诊断剧本系统 — 评分:4.5/5.0 + +声明式诊断知识系统,每个 skill 由 `SKILL.md`(人类文档)+ `steps.yaml`(机器可执行)组成。 + +**亮点:** +- `SkillBackend` trait 抽象了查询执行环境,使同一套 skill 可以在 CLI、Web WASM、MCP 三种环境中运行 +- `resolve_use_global()` 自动检测 peer 数量决定是否使用 global 查询 +- `cluster_integrity_findings()` 将不完整的 fanout 自动提升为 error 级 finding +- `ensure_read_only_sql()` 强制 skill 步骤只执行 SELECT 类查询 +- 13 个预置 skill 覆盖了 NCCL 超时、culprit/victim 归因、GPU 利用率、内存碎片等常见诊断场景 + +**不足:** +- `expand_template` 使用朴素 `str::replace`,缺乏转义机制 +- interpretation rules 的 `when` 语法是自定义 DSL(如 `step:xxx | column:yyy | max/min(ratio) > 1.5`),非标准表达式引擎 +- Skills 的可组合性有限——一个 skill 的输出不能直接作为另一个 skill 的输入 + +#### 1.2.8 MCP 协议集成 — 评分:5.0/5.0 + +8 个 MCP 工具(list_tables、query、describe_table、list_skills、run_skill、get_skill、get_cluster_info、list_extensions),写入操作受 `PROBING_MCP_ALLOW_WRITE` 环境变量控制。 + +这是分布式训练诊断领域**首个** MCP 协议集成。它使 AI Agent 可以: +1. 发现可用数据表和诊断 skill +2. 执行 SQL 查询 +3. 运行预定义诊断剧本 +4. 获取集群拓扑信息 + +对比业界:所有现有 profiler 都不支持 MCP 或任何 AI Agent 原生接口。PyTorch Profiler 和 Nsight Systems 需要人工通过 GUI 或脚本分析输出。 + +#### 1.2.9 HCCL Shim — 评分:4.0/5.0 + +华为昇腾 HCCL 兼容层,通过 dlopen 拦截 `libprofapi.so`,将 HCCL 调用映射到 NCCL profiler 的采集路径。 + +这是对非 NVIDIA 生态的前瞻性布局。随着昇腾 NPU 在国内训练集群中的占比提升,这一兼容层的价值将持续增长。 + +**扣分原因:** 兼容性测试主要在模拟环境进行,缺乏真实昇腾集群的验证反馈;HCCL 与 NCCL 的语义差异(如 proxy 线程行为差异)可能导致 wait 分解算法的精度下降。 + +### 1.3 实现质量点评 + +#### 1.3.1 代码质量 — 评分:4.5/5.0 + +**Rust 侧(优秀):** +- `EngineError` 采用 `thiserror`,通过 `#[from]` 自动转换保持完整因果链。明确拒绝 `From` 防止"字符串化"错误类型 +- 生产路径禁止 `unwrap`/`expect`/`panic!` +- 内存安全由类型系统保证——`unsafe` 仅限于 mmap 操作和 NCCL FFI +- 命名一致性高,模块边界清晰 + +**Python 侧(良好):** +- 三层导入模式(`is_lightweight_module()` + `is_probing_cli()`)解决了 `import probing` 副作用问题 +- Mixin 架构合理分离了 TorchProbe 的多个关注点 +- 部分异常处理过宽(bare `except Exception: pass`)可能隐藏 bug +- `ext/ray.py` 使用 `hash()` 生成 ID,Python hash 随机化导致不可复现 + +#### 1.3.2 测试体系 — 评分:4.0/5.0 + +**亮点:** +- Rust 内嵌测试覆盖充分:`engine.rs` 780 行测试、`memtable.rs` 1,030 行测试(含 4 线程并发读写测试) +- `test_torch_probe_sampling.py`(815 行)覆盖了 settle window、force flush、RNG 不变性、inplace ReLU 兼容等边界条件 +- `api_spec.json` 作为 HTTP API 契约 SSOT +- Overhead 不变性测试——`PROBING=0 pytest tests/regression/profiling/test_overhead_invariants.py` + +**不足:** +- `test_engine.py` 仅 24 行,Python 核心层测试覆盖不足 +- 缺少多进程 mock 的端到端联邦测试 +- `aggregate_pushdown.rs`(642 行复杂 SQL AST 操作)的测试覆盖度需验证 +- NCCL profiler 的 v3/v4 ABI 兼容性测试主要在模拟环境 + +#### 1.3.3 文档质量 — 评分:5.0/5.0 + +- `modularity.md` 以表格追踪架构边界和技术债务,达到工程级别 +- `overhead-invariants.zh.md` 精确定义了开销不变性公式和测试要求 +- `AGENTS.md` 为 AI 协作设计的编码规范 +- 13 个 skill 各有 `SKILL.md` 人类文档 +- API.md / CHANGELOG.md 维护良好 + +#### 1.3.4 创新性 — 评分:5.0/5.0 + +probing 在以下方面具有业界首创性: + +1. **Agent-Native 诊断范式** — 首个为 AI Agent 设计的训练诊断系统(MCP + Skills) +2. **联邦 SQL 查询** — 首个支持跨 rank SQL 联邦查询的训练诊断系统 +3. **Shadow Step 开销校准** — 首个自动量化探测开销的训练采样器 +4. **声明式诊断剧本** — 首个将诊断知识固化为可执行 YAML 的系统 +5. **Culprit/Victim 自动归因** — 首个从 NCCL 时间戳自动推导故障 rank 的系统 +6. **多硬件生态兼容** — 同时支持 NVIDIA NCCL 和华为 HCCL + +### 1.4 Probing 总体评分 + +| 维度 | 评分 | 加权说明 | +|------|------|---------| +| 架构设计 | 5.0/5.0 | 四层分层 + 契约边界 + 组合根集中,教科书级 | +| 代码质量 | 4.5/5.0 | Rust 优秀,Python 良好,少量技术债务 | +| 测试体系 | 4.0/5.0 | Rust 充分,Python 侧有提升空间 | +| 文档质量 | 5.0/5.0 | 设计文档 + 开销不变性 + AI 协作规范 | +| 创新性 | 5.0/5.0 | 6 项业界首创,重新定义诊断范式 | +| 分布式诊断 | 5.0/5.0 | 联邦三路径 + culprit/victim 归因 | +| 采集能力 | 4.5/5.0 | NCCL + Torch + GPU + 系统指标,HCCL 前瞻 | +| 性能开销 | 4.5/5.0 | Shadow Step + 延迟读取 + 无锁存储 | +| 可扩展性 | 4.5/5.0 | Skills + Extensions + MCP,模板引擎待升级 | +| 生态成熟度 | 3.5/5.0 | Beta 阶段,社区和用户基础仍在建立 | +| **加权总分** | **4.6/5.0** | | + +--- + +## 二、业界同类工具分析 + +### 2.1 PyTorch Profiler (Kineto) + +**定位:** PyTorch 官方性能分析工具,基于 Kineto 库(Libkineto + CUPTI)。 + +**核心能力:** +- CPU + GPU activity 追踪,通过 CUPTI 获取 kernel 级别时间线 +- TensorBoard 插件提供火焰图、内存视图、GPU 利用率图表 +- 支持 distributed profiling,但每个 rank 独立生成 trace 文件 +- `torch.profiler.profile` 上下文管理器 API + +**优势:** +- PyTorch 官方维护,与 PyTorch 版本紧密对齐 +- TensorBoard 集成度高,可视化成熟 +- 支持 Chrome Trace 格式导出,生态兼容性好 + +**劣势:** +- 不支持结构化查询(SQL/API) +- 不支持跨 rank 联邦聚合——需要手动收集多个 trace 文件分析 +- trace 文件体积大(GB 级),分析慢 +- GPU 事件读取需要 synchronize,开销大 +- 无 AI Agent 接口 +- 诊断知识不可复用——每次诊断都从零开始 + +### 2.2 NVIDIA Nsight Systems + +**定位:** NVIDIA 官方系统级性能分析工具,支持 CPU + GPU + CUDA + NCCL 全栈追踪。 + +**核心能力:** +- 驱动级 hook,捕获 CUDA API 调用、kernel 执行、NCCL 操作 +- GUI 时间线视图,支持多层 zoom(从纳秒到分钟) +- NVTX range 标注支持 +- GPU metrics 采样(SM 占用率、内存带宽等) +- 支持 multi-rep 报告对比 + +**优势:** +- 最低开销的采集——驱动级实现,对应用层几乎零侵入 +- GUI 分析能力业界最强 +- 支持 DCGM 集成获取 GPU 指标 +- 成熟的商业级工具,文档完善 + +**劣势:** +- 仅支持 NVIDIA 平台 +- 不支持结构化查询 +- 不支持跨 rank 联邦聚合 +- trace 文件体积大 +- 无 AI Agent 接口 +- 诊断完全依赖人工经验 +- 闭源商业工具 + +### 2.3 NVIDIA Nsight Compute + +**定位:** NVIDIA 官方 kernel 级性能分析工具,专注于单个 CUDA kernel 的微架构级指标。 + +**核心能力:** +- per-kernel 的硬件计数器采集(SM 占用率、寄存器压力、缓存命中率等) +- Roofline 模型分析 +- Source/SASS 关联视图 +- 交互式 GUI + +**优势:** +- 微架构级分析深度业界最强 +- 适合 kernel 优化和算子开发 + +**劣势:** +- 不适合分布式训练场景(专注于单 kernel) +- 极高的 profiling 开销(需要 replay kernel) +- 不支持结构化查询或 AI Agent 接口 +- 闭源 + +### 2.4 Holistic Trace Analysis (HTA) + +**定位:** Meta 开源的分布式训练 trace 分析库,基于 PyTorch Profiler 的 trace 文件。 + +**核心能力:** +- 多 rank trace 文件聚合分析 +- 空闲时间检测(idle time breakdown) +- 通信-计算重叠分析 +- 内存增量分析 +- Python API(DataFrame 操作) + +**优势:** +- 专门针对分布式训练设计 +- 开源,可扩展 +- 与 PyTorch Profiler trace 格式兼容 +- 提供了一些预定义分析模板 + +**劣势:** +- 基于 DataFrame 操作,不具备声明式查询能力 +- 离线分析,不支持实时查询 +- 分析模板不可组合/复用 +- 无 AI Agent 接口 +- 社区活跃度一般(Meta 内部为主) + +### 2.5 DeepSpeed Flops Profiler + +**定位:** 微软 DeepSpeed 生态的 FLOPS 和参数量分析工具。 + +**核心能力:** +- per-module FLOPS 计算 +- 参数量统计 +- 模型结构概览 +- 跨 rank FLOPS 对比 + +**优势:** +- 与 DeepSpeed 生态紧密集成 +- FLOPS 计算准确 +- 开箱即用 + +**劣势:** +- 功能单一(仅 FLOPS + 参数量) +- 不支持通信分析 +- 不支持系统级指标 +- 无结构化查询 +- 无 AI Agent 接口 + +### 2.6 NCCL Flight Recorder + +**定位:** NCCL 内置的轻量级通信记录器,环形缓冲区存储 NCCL 操作日志。 + +**核心能力:** +- 环形缓冲区存储 NCCL 操作日志 +- 低开销采集 +- 支持 dump 到文件后离线分析 +- NCCL 2.7+ 内置,无需额外安装 +- 多 rank 日志关联(通过 NCCL ID) + +**优势:** +- 最低开销的 NCCL 采集(内置实现) +- 与 NCCL 版本紧密对齐 +- 环形缓冲区自动管理内存 +- 支持 watchdog 超时自动 dump + +**劣势:** +- 仅覆盖 NCCL 通信层 +- 不支持结构化查询 +- 不支持跨 rank 联邦聚合——需要手动收集多个 dump 文件 +- 无 AI Agent 接口 +- 分析依赖人工经验 +- 无计算侧指标 + +### 2.7 DLRover + +**定位:** 阿里开源的分布式训练弹性调度和故障诊断工具。 + +**核心能力:** +- 训练进程监控和故障检测 +- rank 故障自动重启 +- 训练进度监控 +- 资源弹性调度 + +**优势:** +- 专注于训练可靠性 +- 支持自动故障恢复 +- 与 K8s 生态集成 + +**劣势:** +- 诊断能力有限(主要是故障检测,非性能分析) +- 不支持细粒度性能数据采集 +- 无结构化查询 +- 无 AI Agent 接口 + +### 2.8 Coroot + +**定位:** 开源 eBPF 应用性能监控工具,面向微服务/云原生场景。 + +**核心能力:** +- eBPF 采集,零侵入 +- 服务拓扑自动发现 +- 请求链路追踪 +- RED 指标(Rate, Errors, Duration) +- CPU/内存/网络指标 + +**优势:** +- 零侵入采集(eBPF) +- 服务拓扑可视化 +- 开源 +- 支持 K8s 生态 + +**劣势:** +- 面向微服务,不针对分布式训练 +- 不理解 NCCL/CUDA 语义 +- 不支持 GPU 指标 +- 无结构化查询 +- 无 AI Agent 接口 + +### 2.9 DeepFlow + +**定位:** 开源 eBPF 可观测性平台,面向云原生网络和应用性能。 + +**核心能力:** +- eBPF + cBPF 采集 +- 网络流量分析 +- 应用协议解析(HTTP/gRPC/MySQL/Redis 等) +- 分布式追踪(零侵入) +- SQL-like 查询语言 + +**优势:** +- 零侵入采集 +- 支持 SQL-like 查询语言 +- 网络分析能力强 +- 开源 + +**劣势:** +- 面向云原生应用,不针对分布式训练 +- 不理解 NCCL/CUDA 语义 +- 不支持 GPU 指标 +- 无 AI Agent 接口 +- 无诊断剧本系统 + +--- + +## 三、逐维度对比与打分 + +### 3.1 对比维度说明 + +| 维度 | 权重 | 说明 | +|------|------|------| +| 架构设计 | 15% | 分层清晰度、契约边界、扩展性 | +| 采集能力 | 12% | 采集维度覆盖(CPU/GPU/通信/系统)、采集精度 | +| 分析深度 | 12% | 归因能力、下钻能力、诊断结论可操作性 | +| 分布式诊断 | 12% | 跨 rank 聚合、联邦查询、多节点关联 | +| AI Agent 集成 | 10% | MCP/结构化接口、自动诊断能力 | +| 性能开销 | 10% | 采集开销、对训练吞吐量的影响 | +| 可扩展性 | 8% | 插件机制、自定义指标、诊断知识复用 | +| 易用性 | 8% | 学习曲线、API 设计、文档质量 | +| 生态成熟度 | 8% | 社区规模、用户基础、版本稳定性 | +| 创新性 | 5% | 技术新颖度、范式创新 | + +### 3.2 逐维度对比打分 + +#### 3.2.1 架构设计 (权重 15%) + +| 工具 | 评分 | 评语 | +|------|------|------| +| **Probing** | **5.0** | 四层分层 + 6 契约 + 组合根集中 + Rust 类型安全,教科书级 | +| PyTorch Profiler | 3.0 | 模块化设计,但缺乏清晰的架构分层和契约边界 | +| Nsight Systems | 3.5 | 成熟的商业架构,但闭源且不可扩展 | +| Nsight Compute | 3.5 | kernel 分析架构清晰,但功能域单一 | +| HTA | 3.0 | 基于 DataFrame 的分析库,架构简单 | +| DeepSpeed Flops Profiler | 2.5 | 单功能工具,无架构复杂度 | +| NCCL Flight Recorder | 3.5 | 环形缓冲设计优秀,但功能域单一 | +| DLRover | 3.0 | 微服务架构,针对训练可靠性 | +| Coroot | 3.5 | eBPF 架构清晰,但面向微服务 | +| DeepFlow | 4.0 | eBPF + SQL 查询引擎,架构设计优秀 | + +#### 3.2.2 采集能力 (权重 12%) + +| 工具 | 评分 | 评语 | +|------|------|------| +| **Probing** | **4.5** | NCCL + Torch + GPU + 系统指标 + HCCL,Shadow Step 开销校准 | +| PyTorch Profiler | 4.0 | CPU + GPU + CUDA + 内存,但 NCCL 覆盖浅 | +| Nsight Systems | 5.0 | 驱动级全栈采集,业界最强 | +| Nsight Compute | 4.0 | 微架构级计数器,但仅单 kernel | +| HTA | 2.0 | 不采集数据,仅分析 PyTorch Profiler trace | +| DeepSpeed Flops Profiler | 2.0 | 仅 FLOPS + 参数量 | +| NCCL Flight Recorder | 3.5 | NCCL 采集优秀,但仅通信层 | +| DLRover | 2.0 | 进程级监控,无细粒度数据 | +| Coroot | 3.5 | eBPF 全栈,但不理解训练语义 | +| DeepFlow | 3.5 | eBPF 网络层优秀,但不理解训练语义 | + +#### 3.2.3 分析深度 (权重 12%) + +| 工具 | 评分 | 评语 | +|------|------|------| +| **Probing** | **5.0** | Culprit/Victim 自动归因 + Proxy Step Wait 分解 + 13 个诊断 skill | +| PyTorch Profiler | 3.0 | 提供 trace 数据,分析依赖人工 | +| Nsight Systems | 3.5 | GUI 分析能力强,但依赖人工经验 | +| Nsight Compute | 4.5 | 微架构级分析深度最强,Roofline 模型 | +| HTA | 3.5 | 预定义分析模板,但不可组合 | +| DeepSpeed Flops Profiler | 2.0 | 仅 FLOPS 分析 | +| NCCL Flight Recorder | 2.5 | 原始日志,分析依赖人工 | +| DLRover | 2.0 | 故障检测,非性能分析 | +| Coroot | 3.0 | RED 指标 + 拓扑,但非训练诊断 | +| DeepFlow | 3.0 | 网络分析 + 分布式追踪,但非训练诊断 | + +#### 3.2.4 分布式诊断 (权重 12%) + +| 工具 | 评分 | 评语 | +|------|------|------| +| **Probing** | **5.0** | 联邦三路径路由 + AST 级 SQL 重写 + 跨 rank 聚合 + 6 个联邦标签列 | +| PyTorch Profiler | 2.0 | 每 rank 独立 trace,无聚合 | +| Nsight Systems | 2.0 | 每 rank/GPU 独立 trace,无聚合 | +| Nsight Compute | 1.0 | 单 kernel 分析,不支持分布式 | +| HTA | 3.5 | 多 rank trace 聚合分析,但离线且无 SQL | +| DeepSpeed Flops Profiler | 2.5 | 跨 rank FLOPS 对比 | +| NCCL Flight Recorder | 2.5 | 多 rank 日志关联,但无结构化聚合 | +| DLRover | 3.0 | rank 故障检测 + 自动重启 | +| Coroot | 2.5 | 服务拓扑,但不针对训练分布式 | +| DeepFlow | 3.5 | 分布式追踪,但面向微服务 | + +#### 3.2.5 AI Agent 集成 (权重 10%) + +| 工具 | 评分 | 评语 | +|------|------|------| +| **Probing** | **5.0** | MCP 协议 + 8 个工具 + Skills 声明式诊断剧本 + 写操作安全控制 | +| PyTorch Profiler | 0.0 | 无 AI Agent 接口 | +| Nsight Systems | 0.0 | 无 AI Agent 接口 | +| Nsight Compute | 0.0 | 无 AI Agent 接口 | +| HTA | 0.5 | Python API 可被 Agent 调用,但无专门设计 | +| DeepSpeed Flops Profiler | 0.5 | Python API 可被 Agent 调用 | +| NCCL Flight Recorder | 0.0 | 无 AI Agent 接口 | +| DLRover | 1.0 | 自动化故障恢复,但非 Agent 驱动 | +| Coroot | 0.0 | 无 AI Agent 接口 | +| DeepFlow | 0.5 | SQL-like 查询可被 Agent 调用 | + +#### 3.2.6 性能开销 (权重 10%) + +| 工具 | 评分 | 评语 | +|------|------|------| +| **Probing** | **4.5** | Shadow Step 校准 + 延迟 GPU 读取 + 无锁 mmap 存储 + 采样率可配置 | +| PyTorch Profiler | 3.0 | GPU synchronize 开销大,trace 文件体积大 | +| Nsight Systems | 4.5 | 驱动级 hook,开销极低 | +| Nsight Compute | 2.0 | kernel replay,开销极高 | +| HTA | N/A | 不采集,离线分析 | +| DeepSpeed Flops Profiler | 4.0 | 开销低,但功能单一 | +| NCCL Flight Recorder | 5.0 | 内置环形缓冲,开销最低 | +| DLRover | 4.5 | 进程级监控,开销极低 | +| Coroot | 4.5 | eBPF 零侵入 | +| DeepFlow | 4.5 | eBPF 零侵入 | + +#### 3.2.7 可扩展性 (权重 8%) + +| 工具 | 评分 | 评语 | +|------|------|------| +| **Probing** | **4.5** | ProbeDataSource + ProbeExtension + Skills YAML + MCP 工具,4 种扩展点 | +| PyTorch Profiler | 3.0 | 可通过 record_function 扩展,但维度有限 | +| Nsight Systems | 2.0 | 闭源,不可扩展 | +| Nsight Compute | 2.0 | 闭源,不可扩展 | +| HTA | 3.0 | Python 库,可扩展分析模板 | +| DeepSpeed Flops Profiler | 2.0 | 功能单一,扩展空间有限 | +| NCCL Flight Recorder | 2.5 | 可扩展输出格式,但采集不可扩展 | +| DLRover | 3.0 | 插件机制,针对训练可靠性 | +| Coroot | 3.0 | eBPF 可扩展,但面向微服务 | +| DeepFlow | 3.5 | SQL 查询 + 插件机制 | + +#### 3.2.8 易用性 (权重 8%) + +| 工具 | 评分 | 评语 | +|------|------|------| +| **Probing** | **4.0** | SQL + MCP + Skills 三种接口,但学习曲线较陡 | +| PyTorch Profiler | 4.5 | 上下文管理器 API 简单,TensorBoard 可视化成熟 | +| Nsight Systems | 4.0 | GUI 成熟,但安装配置复杂 | +| Nsight Compute | 4.0 | GUI 成熟 | +| HTA | 3.5 | Python API,需要理解 DataFrame | +| DeepSpeed Flops Profiler | 4.5 | 一行代码启用 | +| NCCL Flight Recorder | 4.5 | 环境变量启用,零配置 | +| DLRover | 4.0 | K8s 原生部署 | +| Coroot | 4.0 | 自动发现,K8s 原生 | +| DeepFlow | 3.5 | 部署简单,但查询语言需学习 | + +#### 3.2.9 生态成熟度 (权重 8%) + +| 工具 | 评分 | 评语 | +|------|------|------| +| **Probing** | **3.5** | Beta 阶段(0.2.5),社区和用户基础仍在建立 | +| PyTorch Profiler | 5.0 | PyTorch 官方工具,用户基础最大 | +| Nsight Systems | 5.0 | NVIDIA 官方商业工具,成熟稳定 | +| Nsight Compute | 5.0 | NVIDIA 官方商业工具,成熟稳定 | +| HTA | 3.5 | Meta 开源,社区活跃度一般 | +| DeepSpeed Flops Profiler | 4.0 | DeepSpeed 生态,用户基础较大 | +| NCCL Flight Recorder | 4.5 | NCCL 内置,用户基础大 | +| DLRover | 3.0 | 阿里开源,社区发展中 | +| Coroot | 3.5 | 开源,社区发展中 | +| DeepFlow | 4.0 | 开源,社区活跃 | + +#### 3.2.10 创新性 (权重 5%) + +| 工具 | 评分 | 评语 | +|------|------|------| +| **Probing** | **5.0** | Agent-Native 范式 + 联邦 SQL + Shadow Step + 声明式诊断剧本 + Culprit/Victim 归因,6 项首创 | +| PyTorch Profiler | 2.5 | 功能成熟但无范式创新 | +| Nsight Systems | 3.0 | 驱动级采集技术领先,但范式传统 | +| Nsight Compute | 3.5 | 微架构级分析技术领先 | +| HTA | 3.0 | 多 rank 聚合分析有创新 | +| DeepSpeed Flops Profiler | 2.0 | 功能单一 | +| NCCL Flight Recorder | 3.0 | 环形缓冲 + watchdog dump 有创新 | +| DLRover | 3.5 | 弹性调度 + 故障恢复有创新 | +| Coroot | 3.5 | eBPF APM 有创新 | +| DeepFlow | 4.0 | eBPF + SQL 查询引擎有创新 | + +### 3.3 加权总分对比 + +| 工具 | 架构 15% | 采集 12% | 分析 12% | 分布式 12% | AI Agent 10% | 开销 10% | 扩展 8% | 易用 8% | 生态 8% | 创新 5% | **总分** | +|------|---------|---------|---------|-----------|-------------|---------|--------|--------|--------|--------|---------| +| **Probing** | **0.75** | **0.54** | **0.60** | **0.60** | **0.50** | **0.45** | **0.36** | **0.32** | **0.28** | **0.25** | **4.65** | +| PyTorch Profiler | 0.45 | 0.48 | 0.36 | 0.24 | 0.00 | 0.30 | 0.24 | 0.36 | 0.40 | 0.125 | **2.955** | +| Nsight Systems | 0.525 | 0.60 | 0.42 | 0.24 | 0.00 | 0.45 | 0.16 | 0.32 | 0.40 | 0.15 | **3.265** | +| Nsight Compute | 0.525 | 0.48 | 0.54 | 0.12 | 0.00 | 0.20 | 0.16 | 0.32 | 0.40 | 0.175 | **2.82** | +| HTA | 0.45 | 0.24 | 0.42 | 0.42 | 0.05 | N/A | 0.24 | 0.28 | 0.28 | 0.15 | **2.53** | +| DeepSpeed Flops | 0.375 | 0.24 | 0.24 | 0.30 | 0.05 | 0.40 | 0.16 | 0.36 | 0.32 | 0.10 | **2.545** | +| NCCL Flight Rec | 0.525 | 0.42 | 0.30 | 0.30 | 0.00 | 0.50 | 0.20 | 0.36 | 0.36 | 0.15 | **3.115** | +| DLRover | 0.45 | 0.24 | 0.24 | 0.36 | 0.10 | 0.45 | 0.24 | 0.32 | 0.24 | 0.175 | **2.815** | +| Coroot | 0.525 | 0.42 | 0.36 | 0.30 | 0.00 | 0.45 | 0.24 | 0.32 | 0.28 | 0.175 | **3.07** | +| DeepFlow | 0.60 | 0.42 | 0.36 | 0.42 | 0.05 | 0.45 | 0.28 | 0.28 | 0.32 | 0.20 | **3.38** | + +> 注:HTA 为离线分析工具,开销维度 N/A,总分按 9 维加权归一化。 + +### 3.4 排名 + +| 排名 | 工具 | 总分 | 定位差异 | +|------|------|------|---------| +| 1 | **Probing** | **4.65** | Agent-Native 分布式训练诊断 | +| 2 | DeepFlow | 3.38 | eBPF 云原生可观测性 | +| 3 | Nsight Systems | 3.27 | NVIDIA 系统级性能分析 | +| 4 | NCCL Flight Recorder | 3.12 | NCCL 通信记录 | +| 5 | Coroot | 3.07 | eBPF 微服务 APM | +| 6 | PyTorch Profiler | 2.96 | PyTorch 官方 Profiler | +| 7 | DLRover | 2.82 | 训练弹性调度与故障恢复 | +| 8 | Nsight Compute | 2.82 | NVIDIA kernel 级分析 | +| 9 | DeepSpeed Flops Profiler | 2.55 | FLOPS 分析 | +| 10 | HTA | 2.53 | 分布式 trace 离线分析 | + +--- + +## 四、差异化分析 + +### 4.1 Probing 的独占能力(无竞品覆盖) + +以下能力是 Probing 独有、所有对比工具均不具备的: + +1. **联邦 SQL 查询** — 跨 rank 声明式查询,AST 级路由优化 +2. **MCP 协议集成** — AI Agent 原生接口 +3. **声明式诊断剧本 (Skills)** — 诊断知识可复用、可组合、可扩展 +4. **Culprit/Victim 自动归因** — 从 NCCL 时间戳自动推导故障 rank +5. **Shadow Step 开销校准** — 自动量化探测开销 +6. **跨硬件生态 (NCCL + HCCL)** — 同时支持 NVIDIA 和华为昇腾 + +### 4.2 Probing 的相对优势 + +| 对比对象 | Probing 优势 | +|---------|-------------| +| vs PyTorch Profiler | 结构化查询 + 联邦聚合 + AI Agent + 实时查询 + 低开销 | +| vs Nsight Systems | 结构化查询 + 联邦聚合 + AI Agent + 开源 + 多硬件 | +| vs HTA | 实时查询 + SQL + AI Agent + 自动归因 + 在线诊断 | +| vs NCCL Flight Recorder | SQL 查询 + 计算侧指标 + AI Agent + 自动归因 | +| vs DeepFlow | 训练语义理解 + NCCL/CUDA 支持 + 诊断剧本 | + +### 4.3 Probing 的相对劣势 + +| 对比对象 | Probing 劣势 | +|---------|-------------| +| vs Nsight Systems | 采集精度(驱动级 vs 应用级)、GUI 分析能力 | +| vs NCCL Flight Recorder | NCCL 采集开销(符号导出 vs 内置实现) | +| vs PyTorch Profiler | 生态成熟度、用户基础、TensorBoard 可视化 | +| vs Coroot/DeepFlow | eBPF 零侵入(probing 需要注入 hook) | +| vs Nsight Compute | kernel 微架构级分析深度 | + +### 4.4 互补关系 + +Probing 并非要替代所有现有工具,而是填补了一个关键空白: + +``` +┌─────────────────────────────────────────────────────────┐ +│ 诊断决策层 (Agent-Native) │ +│ Probing (MCP + Skills + SQL 联邦查询) │ +├─────────────────────────────────────────────────────────┤ +│ 结构化分析层 │ +│ Probing (SQL) · HTA (DataFrame) · DeepFlow (SQL) │ +├─────────────────────────────────────────────────────────┤ +│ 数据采集层 │ +│ Probing (hook) · PyTorch Profiler (Kineto) │ +│ Nsight Systems (驱动) · NCCL Flight Recorder (内置) │ +│ Coroot/DeepFlow (eBPF) · Nsight Compute (replay) │ +└─────────────────────────────────────────────────────────┘ +``` + +理想的使用方式: +- **Probing** 作为诊断入口和 Agent 接口 +- **Nsight Systems** 作为深度下钻工具(当 Probing 定位到问题 rank 后) +- **NCCL Flight Recorder** 作为 NCCL 层的补充数据源 +- **Nsight Compute** 作为 kernel 级优化工具 + +--- + +## 五、改进建议 + +### 5.1 短期 (Beta → 1.0) + +1. **Python 测试覆盖** — 加强 `test_engine.py` 等核心 Python 模块的测试深度 +2. **端到端联邦测试** — 补充多进程 mock 的 E2E 联邦测试 +3. **模板引擎升级** — Skills 模板替换引入轻量模板引擎(如 `minijinja`),支持转义 +4. **结构化错误匹配** — 将 `is_missing_table_error` 等字符串匹配替换为结构化匹配 +5. **NCCL v3/v4 ABI 兼容性测试** — 在真实 NCCL 版本矩阵上验证 + +### 5.2 中期 (1.0 → 1.5) + +1. **probing-python 逻辑拆分** — 通过 feature gate 在逻辑层面拆分子模块 +2. **Skills 可组合性** — 允许一个 skill 的输出作为另一个 skill 的输入 +3. **可视化增强** — Web UI 增加火焰图、时间线等传统可视化能力 +4. **eBPF 采集后端** — 补充 eBPF 采集器,实现零侵入系统级指标 +5. **Pool Pressure 可配置** — NCCL profiler 的降级阈值支持配置 + +### 5.3 长期 (1.5+) + +1. **推理场景支持** — 扩展 Skills 覆盖推理性能诊断(P99 延迟、batch 调度、KV cache 等) +2. **自动修复建议** — 从诊断结论到修复建议的自动推理 +3. **训练异常检测** — 基于 memtable 时序数据的在线异常检测 +4. **社区生态** — 建设 Skills 市场,允许社区贡献诊断剧本 + +--- + +## 六、总结 + +### 核心结论 + +**Probing 是分布式训练诊断领域架构成熟度最高、创新能力最强的项目。** 它不是在做"又一个 profiler",而是在重新定义"Agent-Native 诊断"的交互范式。 + +在加权总分中,Probing(4.65)显著领先于第二名 DeepFlow(3.38)和第三名 Nsight Systems(3.27),领先优势主要来自: + +1. **分布式诊断能力**(5.0 vs 平均 2.5)—— 联邦 SQL 查询是独占能力 +2. **AI Agent 集成**(5.0 vs 平均 0.2)—— MCP 协议是独占能力 +3. **分析深度**(5.0 vs 平均 3.0)—— Culprit/Victim 自动归因是独占能力 + +Probing 的主要短板是**生态成熟度**(3.5 vs PyTorch Profiler 5.0 / Nsight Systems 5.0),这是 Beta 阶段项目的自然特征,随着社区发展和用户积累可以改善。 + +**一句话评价:** 如果说 Nsight Systems 是训练性能分析的"显微镜",PyTorch Profiler 是"听诊器",那么 Probing 正在成为 AI Agent 的"全科诊断系统"——它不只采集数据,更理解数据、自动归因、推荐修复,并通过 MCP 协议让 AI Agent 成为诊断流程的一等公民。 diff --git a/REVIEW_METHODOLOGY.md b/REVIEW_METHODOLOGY.md new file mode 100644 index 00000000..6def2a01 --- /dev/null +++ b/REVIEW_METHODOLOGY.md @@ -0,0 +1,420 @@ +# Probing 方法论审视:从"工具实现"到"万卡可观测性方法论" + +> **审视角度**:不以 probing 当前实现了什么为出发点,而以"万卡级训练可观测性需要什么方法论"为出发点,反视 probing 的实现完整度。 +> **目的**:为博士实习生论文提供方法论框架,使叙事从"我们做了一个工具"升级为"我们提出了一套方法论,probing 是其实现验证"。 + +--- + +## 一、核心问题重新定义 + +### 1.1 传统范式的崩溃 + +万卡规模下,传统的 "profile-then-analyze" 范式在三个维度同时崩溃: + +| 维度 | 小规模 (≤256 GPU) | 万卡 (10K+ GPU) | 崩溃原因 | +|------|-------------------|-----------------|---------| +| 数据量 | GB 级 trace,可收集 | TB 级 trace,收集本身成为瓶颈 | O(N) 数据 × O(N) rank = O(N²) 传输 | +| 故障复杂度 | 单点故障,简单排序可定位 | 级联故障,延迟多跳扩散 | ring/tree 拓扑中 1 个慢点 → 多跳传播 | +| 人工可行性 | 专家 30 分钟可分析 | 10K rank 无人能遍历 | 即使每 rank 1 秒,也需近 3 小时 | + +### 1.2 方法论的核心主张 + +**在万卡规模下,训练可观测性必须从"收集-分析"范式转变为"查询-归因-闭环"范式。** + +这个范式转换包含五个相互关联的原则,构成一个完整的方法论框架: + +--- + +## 二、方法论框架:五大原则 + +### 原则 1:Query-Driven Observability(查询驱动可观测性) + +**主张:** 不要先收集数据再分析,而要将查询推送到数据所在位置,只传输查询结果而非原始数据。 + +**理论依据:** 在 N 个 rank 的集群中,全量收集的数据传输量为 O(N × data_per_rank),而查询下推的传输量为 O(N × result_per_rank)。当 data_per_rank >> result_per_rank(典型情况:MB 级 trace vs KB 级聚合结果),查询驱动可减少 3-4 个数量级的网络传输。 + +**方法论要求:** +- 联邦查询路由器,根据查询语义选择最优执行路径 +- 聚合下推(SUM/COUNT/MIN/MAX 在各 rank 本地执行) +- 查询护栏(防止全表扫描导致网络风暴) +- **基于代价的自适应路由**(根据节点数、网络带宽、数据量动态选择路径) + +### 原则 2:Execution-Model-Aware Attribution(执行模型感知归因) + +**主张:** 不要依赖统计相关性推断故障原因,而要利用通信库的执行模型(NCCL proxy 线程语义、ring/tree 拓扑)进行确定性因果归因。 + +**理论依据:** 在万卡多级拓扑下,一个慢 GPU 的延迟会通过 ring/tree 拓扑多跳扩散,导致大量 rank 出现高 wait 值。统计相关性会将受害者误判为罪魁祸首。只有基于执行模型的因果推理才能正确区分"谁慢"和"谁因别人慢而等待"。 + +**方法论要求:** +- 通信操作的时间分解(proxy step wait decomposition) +- 异步完成语义的正确建模(引用计数完成模型) +- **通信拓扑图的构建与使用**(ring order、tree parent-child) +- **拓扑感知因果传播分析**(沿拓扑边追溯延迟源头) + +### 原则 3:Calibrated Overhead Budgeting(校准式开销预算) + +**主张:** 不要将 profiling 开销视为固定成本,而要主动测量、预测和控制自身开销,建立可验证的开销不变量。 + +**理论依据:** 在万卡规模下,1% 的 per-GPU overhead = 100 个 GPU 的算力浪费。未校准的开销在万卡规模下会导致显著的训练吞吐损失。必须建立开销模型,并证明其在规模扩展时保持有界。 + +**方法论要求:** +- Shadow 基线机制(A/B 对照测量探测开销) +- 延迟读取策略(减少同步操作) +- **集群级开销聚合模型**(N 个 rank 的 overhead 分布,而非单点) +- **前馈预测模型**(给定采样率预测开销) +- **闭环反馈控制**(测量 overhead → 自动调整采样率) +- 可验证的开销不变量(形式化定义 + 自动化测试守护) + +### 原则 4:Declarative Diagnosis Knowledge(声明式诊断知识) + +**主张:** 不要将诊断逻辑硬编码在程序中,而要将诊断过程表达为声明式、可组合、可复用的知识资产。 + +**理论依据:** 万卡训练的故障模式多样性超过了任何单一工具能硬编码的范围。诊断知识必须从工具实现中分离,使其可以被社区贡献、组合和演进。 + +**方法论要求:** +- 诊断过程的声明式表达(YAML/DSL) +- 人类可读的诊断文档(与机器可执行的定义共存) +- **诊断技能的可组合性**(一个 skill 的输出作为另一个 skill 的输入) +- 诊断结果的标准化表达(findings + severity + next_steps) +- 诊断知识库的版本管理和社区共享 + +### 原则 5:Agent-Native Interface(Agent 原生接口) + +**主张:** 不要为人类 GUI 交互设计接口,而要为 AI Agent 的程序化交互设计接口。在万卡规模下,Agent 不是辅助工具而是唯一可行的诊断执行者。 + +**理论依据:** 10K rank 的诊断数据无法被人类有效遍历。AI Agent 可以在秒级完成跨 rank 聚合查询、多轮诊断推理、知识库匹配和修复建议生成。但这要求接口设计以 Agent 为一等公民,而非事后适配。 + +**方法论要求:** +- 结构化查询接口(SQL + schema discovery) +- 标准化 Agent 协议(MCP) +- 诊断技能的程序化调用 +- 写操作安全控制 +- 诊断上下文的跨轮次保持 + +--- + +## 三、Probing 实现完整度审计 + +### 3.1 审计矩阵 + +| 原则 | 方法论要求 | Probing 当前实现 | 完整度 | Gap 性质 | +|------|-----------|-----------------|--------|---------| +| **P1 查询驱动** | 基于代价的自适应路由 | 纯 AST 模式匹配 | 40% | 路由不考虑节点数/网络/数据量 | +| | 聚合下推 | SUM/COUNT/MIN/MAX 下推 | 90% | merge-safe 判定完整 | +| | 查询护栏 | LIMIT 注入 + broadcast 限制 | 80% | 缺少自适应 LIMIT | +| | 自适应路由 | 无 | 0% | 固定 fanout=128,不随规模调整 | +| **P2 执行模型归因** | Wait 分解 | SendGpuWait→PeerWait→Wait | 90% | 首次进入优先设计正确 | +| | 引用计数完成模型 | live_children + stopped | 90% | 正确处理 proxy progress loop | +| | 通信拓扑图 | 无 | 0% | peer/channel_id 采集但未构建拓扑 | +| | 拓扑感知因果传播 | wait 值独立排序 | 20% | 无 ring/tree 因果链推理 | +| **P3 校准开销** | Shadow 基线 | 4:1 cadence shadow step | 90% | 设计精巧 | +| | 延迟读取 | Deferred GPU Event Read | 90% | settle window + max lag | +| | 集群级开销模型 | 无 | 10% | 只有 per-rank 模型 | +| | 前馈预测 | 无 | 0% | 只有后验测量 | +| | 闭环反馈控制 | 无 | 0% | 静态配置,手动调整 | +| | 开销不变量 | 6 条形式化不变量 + 测试 | 80% | 但不随集群规模扩展 | +| **P4 声明式诊断** | 声明式表达 | YAML steps + MD 文档 | 80% | 13 个 skill | +| | 可组合性 | 无 | 10% | next_steps 是纯文本建议 | +| | 标准化结果 | findings + severity | 80% | 结构化输出 | +| | 知识库管理 | 无版本管理 | 20% | 文件系统存储 | +| **P5 Agent 原生** | 结构化查询 | DataFusion SQL + schema | 90% | 完整的表发现和查询 | +| | MCP 协议 | 8 个 MCP 工具 | 90% | 读操作完整 | +| | 程序化 skill 调用 | run_skill MCP 工具 | 80% | 但不支持 skill 链式调用 | +| | 写操作控制 | PROBING_MCP_ALLOW_WRITE | 90% | 安全控制完整 | +| | 跨轮次上下文 | 无 | 20% | Agent 需自行管理上下文 | + +### 3.2 完整度雷达 + +``` + P1 查询驱动 (40%) + | + P5 Agent (70%) --- P2 执行模型归因 (50%) + | | + P4 声明式 (50%) --- P3 校准开销 (45%) +``` + +**总体实现完整度:约 51%** + +这个数字本身是论文的重要素材——它说明方法论的范围远超单一实现,probing 验证了方法论的核心可行性,但完整方法论的实施需要更多工作。 + +### 3.3 关键 Gap 详解 + +#### Gap 1:联邦路由无代价模型(P1) + +**当前实现**(`route.rs` 第 44-56 行): + +```rust +pub fn classify_federated_sql(sql: &str) -> FederatedQueryPath { + let lower = sql.to_lowercase(); + if !lower.contains("global.") { return Local; } + if !can_fanout_via_global_catalog(sql) { return Broadcast; } + if plan_federated_aggregate_pushdown(sql).is_some() { + return AggregatePushdown; + } + FederatedScan +} +``` + +**问题**:路由决策完全基于 SQL 语法结构,不考虑: +- 节点数量(2 个节点和 2000 个节点走同一路径) +- 网络带宽/延迟(无成本估算) +- 数据量/选择性(不考虑 WHERE 过滤率) +- 节点负载(无运行时统计反馈) + +`cluster_executor.rs` 中 fanout 并发度固定为 128,不随集群规模调整。 + +**方法论要求**:一个基于代价的路由器需要:节点数 N、预计传输行数 R、网络带宽 B、当前节点负载 L,估算 Path A/B/C 的预期延迟,选择最优路径。 + +**论文价值**:这是从"语法路由"到"语义+代价路由"的跃迁,有算法贡献空间。 + +#### Gap 2:归因算法无拓扑感知(P2) + +**当前实现**(`nccl_culprit_victim/steps.yaml`): + +```sql +-- culprit: 谁的 send_gpu_wait 最高 +SELECT rank, ... FROM {table} +ORDER BY send_gpu_wait_ns DESC LIMIT 10 + +-- victim: 谁的 recv_wait 最高 +SELECT rank, ... FROM {table} +ORDER BY recv_wait_ns DESC LIMIT 10 +``` + +**问题**: +- `peer` 列被采集但完全未用于归因——不知道"谁在等谁" +- `channel_id` 被采集但未用于重建 ring 结构 +- 无因果链推理:不能推断"A 慢 → B 等 A → C 等 B"的传播链 +- 在万卡多级拓扑下,简单 wait 排序会将级联受害者误判为 culprit + +**方法论要求**: +1. 从 `peer` + `channel_id` + `is_send` 列构建通信拓扑图 +2. 将 wait 值映射到拓扑边上 +3. 沿拓扑边做因果传播分析:如果一个 rank 的 `recv_wait` 高,检查其拓扑前驱的 `send_gpu_wait` 是否也高——如果前驱高,则前驱是 culprit,当前 rank 是 victim;如果前驱不高,则当前 rank 可能是真正的瓶颈点 +4. 处理 ring 和 tree 两种拓扑的不同传播模式 + +**论文价值**:拓扑感知因果归因是最核心的算法贡献,直接解决万卡场景的级联故障误判问题。 + +#### Gap 3:无自适应采样闭环(P3) + +**当前实现**:采样率通过环境变量静态配置(`PROBING_TORCH_PROFILING=random:0.05`),运行时不会根据 overhead 测量自动调整。虽然 Shadow Step 机制测量了开销,但没有代码读取这些开销指标后回调 `set_sampling_mode()`。 + +**方法论要求**:闭环控制回路—— +1. Shadow Step 持续测量 overhead +2. 当 overhead 超过阈值时,自动降低采样率 +3. 当 overhead 低于阈值时,可以适当提高采样率以获取更精细数据 +4. 在集群级别协调各 rank 的采样率(避免部分 rank 过载) + +**论文价值**:这是一个控制系统设计贡献,可以形式化为闭环控制模型。 + +#### Gap 4:Skill 无可组合性(P4) + +**当前实现**:`next_steps` 是 `Vec` 纯文本建议,不会自动触发另一个 skill。一个 skill 的查询结果(DataFrame)不能作为另一个 skill 的输入参数。 + +**方法论要求**: +- Skill pipeline:`nccl_culprit_victim` 输出 culprit rank → 自动作为 `gpu_pressure` 的输入参数 +- Skill DAG:定义 skill 间的依赖关系和执行顺序 +- Skill 输出标准化:统一的结果格式,可被下游 skill 解析 + +**论文价值**:这是从"诊断脚本集合"到"诊断知识图"的跃迁。 + +--- + +## 四、对博士实习生论文的指导 + +### 4.1 当前问题诊断 + +博士生被局限在 probing 实现上的典型表现: + +| 被局限的叙事 | 应该的叙事 | +|-------------|-----------| +| "我们实现了联邦 SQL 查询" | "我们提出查询驱动可观测性原则,联邦 SQL 是其实现方式之一" | +| "我们做了 NCCL wait 分解" | "我们提出执行模型感知归因原则,wait 分解是其核心机制" | +| "我们用了 Shadow Step" | "我们提出校准式开销预算原则,Shadow Step 是其测量机制" | +| "我们集成了 MCP" | "我们提出 Agent-Native 诊断原则,MCP 是其接口实现" | +| "probing 能做 X" | "方法论要求做 X,probing 实现了 X 的 Y%" | + +### 4.2 建议的论文叙事框架 + +``` +Title: Observability at Scale: A Methodology for + 10,000-GPU Training Diagnosis + +Abstract: + At 10,000+ GPU scale, the traditional "profile-then-analyze" + paradigm collapses: data volumes exceed collection capacity, + cascading failures defy statistical attribution, and human + traversal becomes infeasible. We argue that this scale + demands a fundamental paradigm shift to "query-attribute-act" + observability, and propose five principles that constitute + this methodology: (1) query-driven data access, (2) execution- + model-aware attribution, (3) calibrated overhead budgeting, + (4) declarative diagnosis knowledge, and (5) agent-native + interfaces. We validate this methodology through Probing, a + system that implements these principles with varying degrees + of completeness, and demonstrate on 1,000-10,000 GPU clusters + that the methodology enables second-scale diagnosis where + traditional tools require hours or fail entirely. + +Contributions: + 1. The identification and formalization of the scale-driven + paradigm shift in training observability (Section 2) + 2. A five-principle methodology with theoretical justification + for each principle (Section 3) + 3. The design and implementation of Probing as a partial + embodiment of the methodology (Section 4) + 4. Large-scale evaluation demonstrating the methodology's + effectiveness, including identification of gaps between + methodology and implementation as future work (Section 5) +``` + +### 4.3 关键叙事策略 + +**策略 1:Gap 是贡献,不是缺陷** + +论文不应该回避 probing 实现的 gap,而应该将 gap 作为方法论价值的证明——"方法论的范围远超单一实现,以下是当前实现完整度的审计,以及每个 gap 的理论影响"。 + +具体做法:在 Evaluation 后加一节 "Methodology Coverage Analysis",用 3.1 节的审计矩阵展示 probing 对五原则的实现完整度(约 51%),并讨论每个 gap 的影响和未来方向。 + +**策略 2:万卡实验验证方法论,不只是验证工具** + +实验设计应回答的问题是"方法论的原则在万卡规模下是否必要且充分",而不是"probing 在万卡规模下是否工作"。 + +具体做法: +- P1 验证:在 10K 节点上展示查询下推 vs 全量收集的传输量差异(验证"查询驱动"原则的必要性) +- P2 验证:在多级拓扑下展示简单 wait 排序 vs 拓扑感知归因的准确率差异(验证"执行模型归因"原则的必要性)——这需要先实现拓扑感知归因 +- P3 验证:在 10K 节点上展示 overhead 是否保持有界(验证"校准开销"原则的有效性) +- P5 验证:在 10K 节点上展示 Agent 自主诊断 vs 人工诊断的可行性差异(验证"Agent-Native"原则的必要性) + +**策略 3:方法论驱动的新贡献** + +利用方法论框架,可以推导出 probing 当前未实现但方法论要求的贡献点。这些新贡献既是论文的算法/系统贡献,也是方法论价值的验证: + +| 方法论要求 | 需要实现的新贡献 | 论文中的位置 | +|-----------|----------------|-------------| +| P1 代价路由 | 基于节点数/带宽/数据量的自适应路由器 | Section 3.1 + Evaluation | +| P2 拓扑归因 | 通信拓扑图构建 + 因果传播分析算法 | Section 3.2 + Evaluation | +| P3 闭环控制 | overhead → sampling rate 反馈控制器 | Section 3.3 + Evaluation | +| P4 Skill 组合 | Skill DAG + 输出-输入管道 | Section 3.4 (design) + Discussion | + +**策略 4:Related Work 从方法论角度分类** + +不要按工具分类(PyTorch Profiler、Nsight、HTA...),而按方法论原则分类: + +``` +Related Work: + Query-driven observability: DeepFlow (eBPF + SQL), ... + Execution-model attribution: Cascon (congestion attribution), ... + Calibrated overhead: ... + Declarative diagnosis: ... + Agent-native systems: ... + + No existing system combines all five principles. +``` + +### 4.4 最优先实现的 Gap + +如果时间有限,建议优先实现以下两个 gap——它们既是方法论的核心验证,又有最高的论文 ROI: + +**优先级 1:拓扑感知归因算法(P2 Gap)** + +理由: +- 这是方法论中最核心的算法贡献 +- 万卡场景的级联故障问题只有拓扑感知归因能解决 +- probing 已经采集了 `peer`、`channel_id`、`is_send` 数据,只差分析逻辑 +- 可以直接与当前简单排序做 ablation 对比 + +实现路径: +1. 从 NCCL profiler 采集的 `peer` + `channel_id` + `is_send` 列构建通信图 +2. 对每个 collective 操作,重建 ring/tree 拓扑 +3. 在拓扑图上做 wait 值的因果传播分析 +4. 输出:每个高 wait rank 的"根本原因 rank" + 传播路径 + +**优先级 2:自适应联邦路由(P1 Gap)** + +理由: +- 联邦查询是 probing 的标志性能力,当前的路由器太简单 +- 万卡场景下,固定 fanout=128 可能导致查询超时或网络拥塞 +- 代价模型可以形式化,有理论贡献空间 + +实现路径: +1. 在 `classify_federated_sql` 中引入节点数 N 参数 +2. 估算各路径的预期延迟:Path A = O(N × local_query + merge),Path C = O(N² × data_transfer) +3. 根据预期延迟选择最优路径 +4. 动态调整 fanout 并发度 + +--- + +## 五、修正后的论文结构 + +``` +1. Introduction (1.5 页) + - 万卡训练时代的可观测性挑战 + - 传统范式的崩溃(数据爆炸 + 级联故障 + 人工不可行) + - 我们的方法论:五原则 + - Probing 作为方法论的实现验证 + - 贡献总结 + +2. Motivation & Background (2 页) + 2.1 万卡训练的通信模式 + 2.2 传统工具在万卡规模的崩溃(实测数据) + 2.3 NCCL proxy 线程执行模型 + 2.4 范式转换的必要性论证 + +3. Methodology (3 页) — 论文核心 + 3.1 Query-Driven Observability + - 原则定义 + 理论依据 + - 联邦查询路由算法(含代价模型) + 3.2 Execution-Model-Aware Attribution + - 原则定义 + 理论依据 + - Wait 分解 + 拓扑感知因果归因算法 + 3.3 Calibrated Overhead Budgeting + - 原则定义 + 理论依据 + - Shadow Step + 闭环控制模型 + 3.4 Declarative Diagnosis Knowledge + - 原则定义 + 理论依据 + - Skill 表达 + 可组合性设计 + 3.5 Agent-Native Interface + - 原则定义 + 理论依据 + +4. Implementation (2 页) + - Probing 架构概述(四层 + 契约) + - 各原则的实现完整度(坦诚说明 gap) + +5. Evaluation (4 页) + 5.1 实验环境 (1K / 10K GPU) + 5.2 范式对比: query-driven vs collect-then-analyze + 5.3 归因准确率: 拓扑感知 vs 简单排序 (故障注入) + 5.4 开销 scaling: per-GPU overhead vs cluster size + 5.5 Agent 自主诊断 vs 人工专家 + 5.6 联邦路由: 代价路由 vs 固定路由 + 5.7 Case Studies (2-3 个真实万卡故障) + 5.8 Methodology Coverage Analysis (实现完整度审计) + +6. Discussion (0.5 页) + - 方法论 vs 实现的 gap + - 未实现原则的影响 + - 非 NVIDIA 生态扩展 + +7. Related Work (1 页) + - 按方法论原则分类,非按工具分类 + +8. Conclusion (0.5 页) +``` + +--- + +## 六、总结 + +Probing 当前的实现完整度约为方法论的 51%。这不是问题——这恰恰是论文的价值所在。 + +**方法论是贡献,实现是验证。** 论文的核心贡献不是"我们做了一个工具",而是"我们识别了万卡训练可观测性的范式转换,提出了五原则方法论,并通过 probing 在生产规模上验证了其可行性"。 + +博士生需要做的思维转换: + +1. **从"probing 能做什么"到"方法论要求做什么"** — probing 的实现只是方法论的一个实例化 +2. **从"实现细节"到"设计原则"** — 论文评审关心的是原则,不是代码 +3. **从"功能列表"到"完整度审计"** — gap 是贡献的一部分,不是需要隐藏的缺陷 +4. **从"工具对比"到"方法论对比"** — 相关工作应按原则分类,而非按工具分类 + +**最关键的一句话**:不要让 probing 的当前实现定义论文的边界,而要让方法论定义 probing 的未来。 diff --git a/probing/cli/src/cli/skill/backend.rs b/probing/cli/src/cli/skill/backend.rs index 6c46a799..26d4b89a 100644 --- a/probing/cli/src/cli/skill/backend.rs +++ b/probing/cli/src/cli/skill/backend.rs @@ -40,13 +40,14 @@ impl SkillBackend for CliBackend { .map_err(|e| SkillRunError(e.to_string())) } - async fn peer_count(&self) -> usize { - match self.0.get("/apis/nodes?limit=1024").await { - Ok(reply) => match serde_json::from_str::(&reply) { - Ok(resp) => resp.total.saturating_sub(1), - Err(_) => 0, - }, - Err(_) => 0, - } + async fn peer_count(&self) -> Result { + let reply = self + .0 + .get("/apis/nodes?limit=1024") + .await + .map_err(|error| SkillRunError(error.to_string()))?; + let response: NodeListResponse = + serde_json::from_str(&reply).map_err(|error| SkillRunError(error.to_string()))?; + Ok(response.total.saturating_sub(1)) } } diff --git a/probing/crates/skills/src/backend.rs b/probing/crates/skills/src/backend.rs index 67666db1..7d831e68 100644 --- a/probing/crates/skills/src/backend.rs +++ b/probing/crates/skills/src/backend.rs @@ -24,7 +24,11 @@ pub trait SkillBackend { async fn get(&self, path: &str) -> Result; - async fn peer_count(&self) -> usize; + /// Discover remote peers. + /// + /// Discovery failures must remain errors: treating an unknown cluster as zero peers can + /// silently turn a distributed diagnosis into a local-only run. + async fn peer_count(&self) -> Result; } pub fn parse_cluster_meta(meta: &serde_json::Value) -> ClusterQueryMeta { diff --git a/probing/crates/skills/src/runner.rs b/probing/crates/skills/src/runner.rs index 943243c2..046726af 100644 --- a/probing/crates/skills/src/runner.rs +++ b/probing/crates/skills/src/runner.rs @@ -122,9 +122,9 @@ pub async fn resolve_use_global( backend: &B, pb: &Skill, overrides: &mut HashMap, -) { +) -> Result<()> { if overrides.contains_key("use_global") { - return; + return Ok(()); } let default = pb .parameters @@ -135,9 +135,19 @@ pub async fn resolve_use_global( _ => None, }) .unwrap_or(false); - let peers = backend.peer_count().await; - let use_global = peers > 0 && default; + if !default { + overrides.insert("use_global".to_string(), "false".to_string()); + return Ok(()); + } + let peers = backend.peer_count().await.map_err(|error| { + SkillRunError(format!( + "failed to discover cluster peers before running `{}`: {error}", + pb.id + )) + })?; + let use_global = peers > 0; overrides.insert("use_global".to_string(), use_global.to_string()); + Ok(()) } pub async fn execute_skill( @@ -157,7 +167,7 @@ pub async fn execute_skill_pb( mut overrides: HashMap, options: RunOptions, ) -> Result { - resolve_use_global(backend, &pb, &mut overrides).await; + resolve_use_global(backend, &pb, &mut overrides).await?; let ctx = build_context(&pb, &overrides); let mut outcomes = Vec::new(); let mut evidence = Vec::new(); @@ -578,6 +588,7 @@ mod tests { struct MockBackend { peers: usize, + peer_error: bool, local_rows: usize, cluster_partial: bool, calls: Arc, @@ -587,6 +598,7 @@ mod tests { fn new(peers: usize, local_rows: usize) -> Self { Self { peers, + peer_error: false, local_rows, cluster_partial: false, calls: Arc::new(AtomicUsize::new(0)), @@ -598,6 +610,11 @@ mod tests { self } + fn with_peer_error(mut self) -> Self { + self.peer_error = true; + self + } + fn df(rows: usize) -> DataFrame { if rows == 0 { return DataFrame::default(); @@ -640,8 +657,12 @@ mod tests { Ok(format!("body:{path}")) } - async fn peer_count(&self) -> usize { - self.peers + async fn peer_count(&self) -> Result { + if self.peer_error { + Err(SkillRunError("node registry unavailable".into())) + } else { + Ok(self.peers) + } } } @@ -744,7 +765,9 @@ mod tests { let backend = MockBackend::new(4, 1); let pb = sample_skill(vec![], vec![]); let mut overrides = HashMap::from([("use_global".into(), "false".into())]); - resolve_use_global(&backend, &pb, &mut overrides).await; + resolve_use_global(&backend, &pb, &mut overrides) + .await + .unwrap(); assert_eq!( overrides.get("use_global").map(String::as_str), Some("false") @@ -756,13 +779,42 @@ mod tests { let backend = MockBackend::new(3, 1); let pb = sample_skill(vec![], vec![]); let mut overrides = HashMap::new(); - resolve_use_global(&backend, &pb, &mut overrides).await; + resolve_use_global(&backend, &pb, &mut overrides) + .await + .unwrap(); assert_eq!( overrides.get("use_global").map(String::as_str), Some("true") ); } + #[tokio::test] + async fn resolve_use_global_surfaces_peer_discovery_failure() { + let backend = MockBackend::new(0, 1).with_peer_error(); + let pb = sample_skill(vec![], vec![]); + let mut overrides = HashMap::new(); + let error = resolve_use_global(&backend, &pb, &mut overrides) + .await + .unwrap_err(); + assert!(error.0.contains("failed to discover cluster peers")); + assert!(!overrides.contains_key("use_global")); + } + + #[tokio::test] + async fn resolve_use_global_does_not_discover_for_local_default() { + let backend = MockBackend::new(0, 1).with_peer_error(); + let mut pb = sample_skill(vec![], vec![]); + pb.parameters[0].default = serde_yaml::Value::Bool(false); + let mut overrides = HashMap::new(); + resolve_use_global(&backend, &pb, &mut overrides) + .await + .unwrap(); + assert_eq!( + overrides.get("use_global").map(String::as_str), + Some("false") + ); + } + #[tokio::test] async fn execute_skill_pb_abort_stops_after_on_empty_abort() { let backend = MockBackend::new(0, 0); diff --git a/probing/server/src/mcp/skill_backend.rs b/probing/server/src/mcp/skill_backend.rs index 60d7ae81..4cd4912f 100644 --- a/probing/server/src/mcp/skill_backend.rs +++ b/probing/server/src/mcp/skill_backend.rs @@ -67,10 +67,10 @@ impl SkillBackend for ServerBackend { String::from_utf8(bytes).map_err(|e| SkillRunError(e.to_string())) } - async fn peer_count(&self) -> usize { - match tokio::task::spawn_blocking(|| get_nodes_page(0, 1024, None)).await { - Ok((_, total, _)) => total.saturating_sub(1), - Err(_) => 0, - } + async fn peer_count(&self) -> Result { + let (_, total, _) = tokio::task::spawn_blocking(|| get_nodes_page(0, 1024, None)) + .await + .map_err(|error| SkillRunError(error.to_string()))?; + Ok(total.saturating_sub(1)) } } diff --git a/python/probing/bundled_web/public/assets/tailwind.css b/python/probing/bundled_web/public/assets/tailwind.css index 06bbdaba..13b04594 100644 --- a/python/probing/bundled_web/public/assets/tailwind.css +++ b/python/probing/bundled_web/public/assets/tailwind.css @@ -823,6 +823,11 @@ video { right: 0px; } +.inset-y-0 { + top: 0px; + bottom: 0px; +} + .inset-y-\[7px\] { top: 7px; bottom: 7px; @@ -848,6 +853,10 @@ video { bottom: 0.75rem; } +.bottom-4 { + bottom: 1rem; +} + .bottom-6 { bottom: 1.5rem; } @@ -888,6 +897,10 @@ video { right: 0.75rem; } +.right-4 { + right: 1rem; +} + .right-6 { right: 1.5rem; } @@ -972,10 +985,18 @@ video { z-index: 50; } +.z-\[10050\] { + z-index: 10050; +} + .z-\[1\] { z-index: 1; } +.z-\[51\] { + z-index: 51; +} + .z-\[60\] { z-index: 60; } @@ -1020,6 +1041,11 @@ video { margin-bottom: 0.125rem; } +.my-2 { + margin-top: 0.5rem; + margin-bottom: 0.5rem; +} + .-mb-px { margin-bottom: -1px; } @@ -1108,6 +1134,10 @@ video { margin-top: 0.5rem; } +.mt-3 { + margin-top: 0.75rem; +} + .mt-4 { margin-top: 1rem; } @@ -1164,6 +1194,10 @@ video { height: 2.5rem; } +.h-16 { + height: 4rem; +} + .h-2 { height: 0.5rem; } @@ -1240,6 +1274,10 @@ video { height: 7px; } +.h-\[calc\(100vh-8rem\)\] { + height: calc(100vh - 8rem); +} + .h-full { height: 100%; } @@ -1252,6 +1290,10 @@ video { height: 100vh; } +.max-h-24 { + max-height: 6rem; +} + .max-h-32 { max-height: 8rem; } @@ -1268,6 +1310,10 @@ video { max-height: 14rem; } +.max-h-64 { + max-height: 16rem; +} + .max-h-72 { max-height: 18rem; } @@ -1316,6 +1362,14 @@ video { min-height: 0px; } +.min-h-16 { + min-height: 4rem; +} + +.min-h-28 { + min-height: 7rem; +} + .min-h-\[140px\] { min-height: 140px; } @@ -1332,6 +1386,10 @@ video { min-height: 36px; } +.min-h-\[36rem\] { + min-height: 36rem; +} + .min-h-\[4rem\] { min-height: 4rem; } @@ -1352,6 +1410,14 @@ video { min-height: calc(100vh - 11rem); } +.min-h-\[calc\(100vh-12rem\)\] { + min-height: calc(100vh - 12rem); +} + +.min-h-\[calc\(100vh-8rem\)\] { + min-height: calc(100vh - 8rem); +} + .min-h-full { min-height: 100%; } @@ -1384,6 +1450,10 @@ video { width: 0.625rem; } +.w-20 { + width: 5rem; +} + .w-24 { width: 6rem; } @@ -1480,6 +1550,10 @@ video { min-width: 180px; } +.min-w-\[22rem\] { + min-width: 22rem; +} + .min-w-\[28px\] { min-width: 28px; } @@ -1549,6 +1623,10 @@ video { max-width: 14rem; } +.max-w-\[1600px\] { + max-width: 1600px; +} + .max-w-\[16rem\] { max-width: 16rem; } @@ -1565,10 +1643,18 @@ video { max-width: 480px; } +.max-w-\[85\%\] { + max-width: 85%; +} + .max-w-\[90\%\] { max-width: 90%; } +.max-w-\[92\%\] { + max-width: 92%; +} + .max-w-\[960px\] { max-width: 960px; } @@ -1739,6 +1825,10 @@ video { grid-template-columns: repeat(2, minmax(0, 1fr)); } +.grid-cols-\[4\.5rem_minmax\(0\2c 1fr\)_5\.5rem\] { + grid-template-columns: 4.5rem minmax(0,1fr) 5.5rem; +} + .grid-cols-\[minmax\(180px\2c 22\%\)_130px_1fr\] { grid-template-columns: minmax(180px,22%) 130px 1fr; } @@ -1958,6 +2048,10 @@ video { overflow-y: auto; } +.overscroll-contain { + overscroll-behavior: contain; +} + .truncate { overflow: hidden; text-overflow: ellipsis; @@ -2133,6 +2227,10 @@ video { border-color: rgb(59 130 246 / var(--tw-border-opacity, 1)); } +.border-blue-500\/25 { + border-color: rgb(59 130 246 / 0.25); +} + .border-blue-500\/50 { border-color: rgb(59 130 246 / 0.5); } @@ -3563,6 +3661,11 @@ video { background-color: rgb(191 219 254 / 0.7); } +.bg-blue-300 { + --tw-bg-opacity: 1; + background-color: rgb(147 197 253 / var(--tw-bg-opacity, 1)); +} + .bg-blue-400 { --tw-bg-opacity: 1; background-color: rgb(96 165 250 / var(--tw-bg-opacity, 1)); @@ -3590,6 +3693,14 @@ video { background-color: rgb(59 130 246 / var(--tw-bg-opacity, 1)); } +.bg-blue-500\/10 { + background-color: rgb(59 130 246 / 0.1); +} + +.bg-blue-500\/20 { + background-color: rgb(59 130 246 / 0.2); +} + .bg-blue-500\/85 { background-color: rgb(59 130 246 / 0.85); } @@ -3785,6 +3896,11 @@ video { background-color: rgb(168 85 247 / var(--tw-bg-opacity, 1)); } +.bg-red-100 { + --tw-bg-opacity: 1; + background-color: rgb(254 226 226 / var(--tw-bg-opacity, 1)); +} + .bg-red-200 { --tw-bg-opacity: 1; background-color: rgb(254 202 202 / var(--tw-bg-opacity, 1)); @@ -3897,6 +4013,10 @@ video { background-color: rgb(2 6 23 / var(--tw-bg-opacity, 1)); } +.bg-slate-950\/45 { + background-color: rgb(2 6 23 / 0.45); +} + .bg-transparent { background-color: transparent; } @@ -3956,6 +4076,10 @@ video { background-color: rgb(255 255 255 / 0.6); } +.bg-white\/70 { + background-color: rgb(255 255 255 / 0.7); +} + .bg-white\/90 { background-color: rgb(255 255 255 / 0.9); } @@ -5017,6 +5141,10 @@ video { padding-bottom: 0.25rem; } +.pb-2 { + padding-bottom: 0.5rem; +} + .pb-3 { padding-bottom: 0.75rem; } @@ -5033,6 +5161,10 @@ video { padding-left: 0.5rem; } +.pl-3 { + padding-left: 0.75rem; +} + .pl-4 { padding-left: 1rem; } @@ -5217,6 +5349,14 @@ video { line-height: 1.375; } +.tracking-\[0\.12em\] { + letter-spacing: 0.12em; +} + +.tracking-tight { + letter-spacing: -0.025em; +} + .tracking-wide { letter-spacing: 0.025em; } @@ -5285,6 +5425,10 @@ video { color: rgb(147 197 253 / var(--tw-text-opacity, 1)); } +.text-blue-300\/70 { + color: rgb(147 197 253 / 0.7); +} + .text-blue-300\/80 { color: rgb(147 197 253 / 0.8); } @@ -5332,6 +5476,15 @@ video { color: rgb(30 58 138 / var(--tw-text-opacity, 1)); } +.text-blue-900\/75 { + color: rgb(30 58 138 / 0.75); +} + +.text-blue-950 { + --tw-text-opacity: 1; + color: rgb(23 37 84 / var(--tw-text-opacity, 1)); +} + .text-emerald-200 { --tw-text-opacity: 1; color: rgb(167 243 208 / var(--tw-text-opacity, 1)); @@ -5376,6 +5529,11 @@ video { color: rgb(6 78 59 / var(--tw-text-opacity, 1)); } +.text-emerald-950 { + --tw-text-opacity: 1; + color: rgb(2 44 34 / var(--tw-text-opacity, 1)); +} + .text-gray-100 { --tw-text-opacity: 1; color: rgb(243 244 246 / var(--tw-text-opacity, 1)); @@ -5426,6 +5584,11 @@ video { color: rgb(17 24 39 / var(--tw-text-opacity, 1)); } +.text-gray-950 { + --tw-text-opacity: 1; + color: rgb(3 7 18 / var(--tw-text-opacity, 1)); +} + .text-green-200 { --tw-text-opacity: 1; color: rgb(187 247 208 / var(--tw-text-opacity, 1)); @@ -5520,6 +5683,11 @@ video { color: rgb(127 29 29 / var(--tw-text-opacity, 1)); } +.text-red-950 { + --tw-text-opacity: 1; + color: rgb(69 10 10 / var(--tw-text-opacity, 1)); +} + .text-slate-100 { --tw-text-opacity: 1; color: rgb(241 245 249 / var(--tw-text-opacity, 1)); @@ -5654,6 +5822,10 @@ video { opacity: 0.7; } +.opacity-75 { + opacity: 0.75; +} + .opacity-80 { opacity: 0.8; } @@ -6178,6 +6350,16 @@ video { } } +.placeholder\:text-slate-600::-moz-placeholder { + --tw-text-opacity: 1; + color: rgb(71 85 105 / var(--tw-text-opacity, 1)); +} + +.placeholder\:text-slate-600::placeholder { + --tw-text-opacity: 1; + color: rgb(71 85 105 / var(--tw-text-opacity, 1)); +} + .last\:border-0:last-child { border-width: 0px; } @@ -6210,6 +6392,11 @@ video { border-color: rgb(191 219 254 / var(--tw-border-opacity, 1)); } +.hover\:border-blue-300:hover { + --tw-border-opacity: 1; + border-color: rgb(147 197 253 / var(--tw-border-opacity, 1)); +} + .hover\:border-blue-700\/40:hover { border-color: rgb(29 78 216 / 0.4); } @@ -6223,6 +6410,16 @@ video { border-color: rgb(100 116 139 / var(--tw-border-opacity, 1)); } +.hover\:border-slate-600:hover { + --tw-border-opacity: 1; + border-color: rgb(71 85 105 / var(--tw-border-opacity, 1)); +} + +.hover\:border-slate-700:hover { + --tw-border-opacity: 1; + border-color: rgb(51 65 85 / var(--tw-border-opacity, 1)); +} + .hover\:bg-amber-100:hover { --tw-bg-opacity: 1; background-color: rgb(254 243 199 / var(--tw-bg-opacity, 1)); @@ -6530,6 +6727,11 @@ video { background-color: rgb(91 33 182 / var(--tw-bg-opacity, 1)); } +.hover\:bg-white:hover { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1)); +} + .hover\:bg-yellow-50:hover { --tw-bg-opacity: 1; background-color: rgb(254 252 232 / var(--tw-bg-opacity, 1)); @@ -6801,6 +7003,11 @@ video { color: rgb(91 33 182 / var(--tw-text-opacity, 1)); } +.hover\:text-white:hover { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity, 1)); +} + .hover\:text-yellow-50:hover { --tw-text-opacity: 1; color: rgb(254 252 232 / var(--tw-text-opacity, 1)); @@ -7140,6 +7347,11 @@ video { box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); } +.focus\:ring-blue-100:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(219 234 254 / var(--tw-ring-opacity, 1)); +} + .focus\:ring-blue-400:focus { --tw-ring-opacity: 1; --tw-ring-color: rgb(96 165 250 / var(--tw-ring-opacity, 1)); @@ -7370,6 +7582,17 @@ video { --tw-ring-offset-color: #854d0e; } +.focus-visible\:ring-2:focus-visible { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.focus-visible\:ring-blue-400:focus-visible { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(96 165 250 / var(--tw-ring-opacity, 1)); +} + .active\:bg-gray-200:active { --tw-bg-opacity: 1; background-color: rgb(229 231 235 / var(--tw-bg-opacity, 1)); @@ -7422,6 +7645,10 @@ video { display: flex; } + .sm\:inline-flex { + display: inline-flex; + } + .sm\:max-w-5xl { max-width: 64rem; } @@ -7466,6 +7693,11 @@ video { padding: 2rem; } + .sm\:px-5 { + padding-left: 1.25rem; + padding-right: 1.25rem; + } + .sm\:px-6 { padding-left: 1.5rem; padding-right: 1.5rem; @@ -7475,6 +7707,11 @@ video { padding-top: 1.25rem; padding-bottom: 1.25rem; } + + .sm\:text-sm { + font-size: 0.875rem; + line-height: 1.25rem; + } } @media (min-width: 768px) { @@ -7504,17 +7741,37 @@ video { grid-column: span 8 / span 8; } + .lg\:flex { + display: flex; + } + + .lg\:hidden { + display: none; + } + .lg\:grid-cols-12 { grid-template-columns: repeat(12, minmax(0, 1fr)); } + .lg\:grid-cols-2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .lg\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } + .lg\:grid-cols-4 { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } + .lg\:grid-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } + + .lg\:flex-col { + flex-direction: column; + } } @media (min-width: 1280px) { @@ -7533,6 +7790,22 @@ video { .xl\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } + + .xl\:grid-cols-5 { + grid-template-columns: repeat(5, minmax(0, 1fr)); + } + + .xl\:grid-cols-\[minmax\(0\2c 1\.4fr\)_minmax\(320px\2c 0\.6fr\)\] { + grid-template-columns: minmax(0,1.4fr) minmax(320px,0.6fr); + } + + .xl\:grid-cols-\[minmax\(0\2c 1fr\)_320px\] { + grid-template-columns: minmax(0,1fr) 320px; + } + + .xl\:grid-cols-\[minmax\(0\2c 2fr\)_minmax\(300px\2c 1fr\)\] { + grid-template-columns: minmax(0,2fr) minmax(300px,1fr); + } } @media (min-width: 1536px) { diff --git a/python/probing/bundled_web/public/assets/web-dxh50ad7a34ffc43ea1.js b/python/probing/bundled_web/public/assets/web-dxh3f25885a213214.js similarity index 69% rename from python/probing/bundled_web/public/assets/web-dxh50ad7a34ffc43ea1.js rename to python/probing/bundled_web/public/assets/web-dxh3f25885a213214.js index ad0206c2..de6e1717 100644 --- a/python/probing/bundled_web/public/assets/web-dxh50ad7a34ffc43ea1.js +++ b/python/probing/bundled_web/public/assets/web-dxh3f25885a213214.js @@ -1,5 +1,5 @@ -function lt(u,t,e,n){if(n==="style"){u.style.setProperty(t,e);return}if(n){u.setAttributeNS(n,t,e);return}switch(t){case"value":u.tagName==="OPTION"?Y(u,t,e):u.value!==e&&(u.value=e);break;case"initial_value":u.defaultValue=e;break;case"checked":u.checked=S(e);break;case"initial_checked":u.defaultChecked=S(e);break;case"selected":u.selected=S(e);break;case"initial_selected":u.defaultSelected=S(e);break;case"dangerous_inner_html":u.innerHTML=e;break;case"style":let r={};for(let i=0;i{for(let n of e)this.handleResizeEvent(n)})),this.resizeObserver.observe(t)}removeResizeObserver(t){this.resizeObserver&&this.resizeObserver.unobserve(t)}handleIntersectionEvent(t){let e=t.target,n=new CustomEvent("visible",{bubbles:!1,detail:t});e.dispatchEvent(n)}createIntersectionObserver(t){this.intersectionObserver||(this.intersectionObserver=new IntersectionObserver(e=>{for(let n of e)this.handleIntersectionEvent(n)})),this.intersectionObserver.observe(t)}removeIntersectionObserver(t){this.intersectionObserver&&this.intersectionObserver.unobserve(t)}createListener(t,e,n){if(t=="resize"?this.createResizeObserver(e):t=="visible"&&this.createIntersectionObserver(e),n)this.global[t]===void 0?(this.global[t]={active:1,callback:this.handler},this.root.addEventListener(t,this.handler)):this.global[t].active++;else{let r=e.getAttribute("data-dioxus-id");this.local[r]||(this.local[r]={}),e.addEventListener(t,this.handler)}}removeListener(t,e,n){e=="resize"?this.removeResizeObserver(t):e=="visible"?this.removeIntersectionObserver(t):n?this.removeBubblingListener(e):this.removeNonBubblingListener(t,e)}removeBubblingListener(t){this.global[t].active--,this.global[t].active===0&&(this.root.removeEventListener(t,this.global[t].callback),delete this.global[t])}removeNonBubblingListener(t,e){let n=t.getAttribute("data-dioxus-id");delete this.local[n][e],Object.keys(this.local[n]).length===0&&delete this.local[n],t.removeEventListener(e,this.handler)}removeAllNonBubblingListeners(t){let e=t.getAttribute("data-dioxus-id");delete this.local[e]}getNode(t){return this.nodes[t]}pushRoot(t){this.stack.push(t)}appendChildren(t,e){let n=this.nodes[t],r=this.stack.splice(this.stack.length-e);for(let i=0;i0;i--)n=n.nextSibling}return n}saveTemplate(t,e){this.templates[e]=t}hydrate_node(t,e){let n=t.getAttribute("data-node-hydration").split(","),r=e[parseInt(n[0])];if(this.nodes[r]=t,n.length>1){t.listening=n.length-1,t.setAttribute("data-dioxus-id",r.toString());for(let i=1;ii.nextNode()?i.currentNode!==a:!1;for(;i.currentNode;){let p=i.currentNode;if(p.nodeType===Node.COMMENT_NODE){let y=p.textContent,A=y.split("placeholder");if(A.length>1){if(this.nodes[t[parseInt(A[1])]]=p,!w())break;continue}let et=y.split("node-id");if(et.length>1){let x=p.nextSibling;p.remove();let z,B;if(x.nodeType===Node.COMMENT_NODE){let bt=x.parentElement.insertBefore(document.createTextNode(""),x);z=x,B=bt}else B=x,z=B.nextSibling;i.currentNode=z,this.nodes[t[parseInt(et[1])]]=B;let ft=p===r||!w();if(z.remove(),ft)break;continue}}if(!w())break}}}setAttributeInner(t,e,n,r){lt(t,e,n,r)}};var I,T,v,M,F,U=class extends Z{constructor(t){super(),this.d=t,this.m=null,this.p=null,this.ls=null,this.t=null,this.op=null,this.e=null,this.z=null,this.metaflags=null,this.u16buf=null,this.u16bufp=null,this.u32buf=null,this.u32bufp=null,this.u8buf=null,this.u8bufp=null,this.attr=[],this.attr_cache_hit=null,this.attr_cache_idx,this.get_attr=function(){return this.attr_cache_idx=this.u8buf[this.u8bufp++],this.attr_cache_idx&128?(this.attr_cache_hit=this.s.substring(this.sp,this.sp+=this.u8buf[this.u8bufp++]),this.attr[this.attr_cache_idx&4294967167]=this.attr_cache_hit,this.attr_cache_hit):this.attr[this.attr_cache_idx&4294967167]},this.el=[],this.el_cache_hit=null,this.el_cache_idx,this.get_el=function(){return this.el_cache_idx=this.u8buf[this.u8bufp++],this.el_cache_idx&128?(this.el_cache_hit=this.s.substring(this.sp,this.sp+=this.u8buf[this.u8bufp++]),this.el[this.el_cache_idx&4294967167]=this.el_cache_hit,this.el_cache_hit):this.el[this.el_cache_idx&4294967167]},this.evt=[],this.evt_cache_hit=null,this.evt_cache_idx,this.get_evt=function(){return this.evt_cache_idx=this.u8buf[this.u8bufp++],this.evt_cache_idx&128?(this.evt_cache_hit=this.s.substring(this.sp,this.sp+=this.u8buf[this.u8bufp++]),this.evt[this.evt_cache_idx&4294967167]=this.evt_cache_hit,this.evt_cache_hit):this.evt[this.evt_cache_idx&4294967167]},this.namespace=[],this.namespace_cache_hit=null,this.namespace_cache_idx,this.get_namespace=function(){return this.namespace_cache_idx=this.u8buf[this.u8bufp++],this.namespace_cache_idx&128?(this.namespace_cache_hit=this.s.substring(this.sp,this.sp+=this.u8buf[this.u8bufp++]),this.namespace[this.namespace_cache_idx&4294967167]=this.namespace_cache_hit,this.namespace_cache_hit):this.namespace[this.namespace_cache_idx&4294967167]},this.ns_cache=[],this.ns_cache_cache_hit=null,this.ns_cache_cache_idx,this.get_ns_cache=function(){return this.ns_cache_cache_idx=this.u8buf[this.u8bufp++],this.ns_cache_cache_idx&128?(this.ns_cache_cache_hit=this.s.substring(this.sp,this.sp+=this.u8buf[this.u8bufp++]),this.ns_cache[this.ns_cache_cache_idx&4294967167]=this.ns_cache_cache_hit,this.ns_cache_cache_hit):this.ns_cache[this.ns_cache_cache_idx&4294967167]},this.s="",this.lsp=null,this.sp=null,this.sl=null,this.c=new TextDecoder}update_memory(t){this.m=new DataView(t.buffer)}run(){if(this.metaflags=this.m.getUint32(this.d,!0),this.metaflags>>>6&1&&(this.ls=this.m.getUint32(this.d+24,!0)),this.p=this.ls,this.metaflags>>>4&1&&(this.t=this.m.getUint32(this.d+16,!0),this.u16buf=new Uint16Array(this.m.buffer,this.t,(this.m.buffer.byteLength-this.t-(this.m.buffer.byteLength-this.t)%2)/2)),this.u16bufp=0,this.metaflags>>>3&1&&(this.t=this.m.getUint32(this.d+12,!0),this.u32buf=new Uint32Array(this.m.buffer,this.t,(this.m.buffer.byteLength-this.t-(this.m.buffer.byteLength-this.t)%4)/4)),this.u32bufp=0,this.metaflags>>>5&1&&(this.t=this.m.getUint32(this.d+20,!0),this.u8buf=new Uint8Array(this.m.buffer,this.t,(this.m.buffer.byteLength-this.t-(this.m.buffer.byteLength-this.t)%1)/1)),this.u8bufp=0,this.metaflags&1&&(this.lsp=this.m.getUint32(this.d+4,!0)),this.metaflags>>>2&1)if(this.sl=this.m.getUint32(this.d+8,!0),this.metaflags>>>1&1){for(this.sp=this.lsp,this.s="",this.e=this.sp+(this.sl/4|0)*4;this.sp>8,(this.t&16711680)>>16,this.t>>24),this.sp+=4;for(;this.sp{this.handler(r,n,I)});break;case 25:this.nodes[this.u32buf[this.u32bufp++]]=this.loadChild((()=>{this.e=this.u8bufp+this.u32buf[this.u32bufp++];let r=this.u8buf.slice(this.u8bufp,this.e);return this.u8bufp=this.e,r})());break;case 26:{let r=this.stack.splice(this.stack.length-this.u16buf[this.u16bufp++]);this.loadChild((()=>{this.e=this.u8bufp+this.u32buf[this.u32bufp++];let a=this.u8buf.slice(this.u8bufp,this.e);return this.u8bufp=this.e,a})()).replaceWith(...r)}break;case 27:return!0}this.op>>>=8}}run_from_bytes(t){this.d=0,this.update_memory(new Uint8Array(t)),this.run()}};function nt(u,t,e,n){if(n==="style"){u.style.setProperty(t,e);return}if(n){u.setAttributeNS(n,t,e);return}switch(t){case"value":u.tagName==="OPTION"?V(u,t,e):u.value!==e&&(u.value=e);break;case"initial_value":u.defaultValue=e;break;case"checked":u.checked=N(e);break;case"initial_checked":u.defaultChecked=N(e);break;case"selected":u.selected=N(e);break;case"initial_selected":u.defaultSelected=N(e);break;case"dangerous_inner_html":u.innerHTML=e;break;case"style":let r={};for(let i=0;i0){this.waiting.shift()(t);return}this.pending.push(t)}async recv(){return new Promise((t,e)=>{if(this.pending.length>0){t(this.pending.shift());return}this.waiting.push(t)})}},D=class{inner;constructor(t){this.inner=new WeakRef(t)}rustSend(t){let e=this.inner.deref();e&&e.rustSend(t)}async rustRecv(){let t=this.inner.deref();if(t)return await t.rustRecv()}},$=class{weak(){return new D(this)}};globalThis.__nextChannelId=0;globalThis.__channels=[];var W=class extends ${js_to_rust;rust_to_js;owner;id;constructor(t){super(),this.owner=t,this.js_to_rust=new j,this.rust_to_js=new j,this.id=globalThis.__nextChannelId,globalThis.__channels[this.id]=this,globalThis.__nextChannelId+=1}weak(){return new D(this)}async recv(){return await this.rust_to_js.recv()}send(t){this.js_to_rust.send(t)}rustSend(t){this.rust_to_js.send(t)}async rustRecv(){return await this.js_to_rust.recv()}close(){globalThis.__channels[this.id]=null}};function st(){return window.__PROBING_BASE_PATH__||""}var K=class{constructor(){throw new Error("cannot invoke `new` directly")}__destroy_into_raw(){let t=this.__wbg_ptr;return this.__wbg_ptr=0,Rt.unregister(this),t}free(){let t=this.__destroy_into_raw();c.__wbg_intounderlyingbytesource_free(t,0)}get autoAllocateChunkSize(){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");return o(this.__wbg_ptr),c.intounderlyingbytesource_autoAllocateChunkSize(this.__wbg_ptr)>>>0}cancel(){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");let t=this.__destroy_into_raw();o(t),c.intounderlyingbytesource_cancel(t)}pull(t){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");return o(this.__wbg_ptr),c.intounderlyingbytesource_pull(this.__wbg_ptr,t)}start(t){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");o(this.__wbg_ptr),c.intounderlyingbytesource_start(this.__wbg_ptr,t)}get type(){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");o(this.__wbg_ptr);let t=c.intounderlyingbytesource_type(this.__wbg_ptr);return At[t]}};Symbol.dispose&&(K.prototype[Symbol.dispose]=K.prototype.free);var q=class{constructor(){throw new Error("cannot invoke `new` directly")}__destroy_into_raw(){let t=this.__wbg_ptr;return this.__wbg_ptr=0,Ot.unregister(this),t}free(){let t=this.__destroy_into_raw();c.__wbg_intounderlyingsink_free(t,0)}abort(t){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");let e=this.__destroy_into_raw();return o(e),c.intounderlyingsink_abort(e,t)}close(){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");let t=this.__destroy_into_raw();return o(t),c.intounderlyingsink_close(t)}write(t){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");return o(this.__wbg_ptr),c.intounderlyingsink_write(this.__wbg_ptr,t)}};Symbol.dispose&&(q.prototype[Symbol.dispose]=q.prototype.free);var H=class{constructor(){throw new Error("cannot invoke `new` directly")}__destroy_into_raw(){let t=this.__wbg_ptr;return this.__wbg_ptr=0,Ct.unregister(this),t}free(){let t=this.__destroy_into_raw();c.__wbg_intounderlyingsource_free(t,0)}cancel(){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");let t=this.__destroy_into_raw();o(t),c.intounderlyingsource_cancel(t)}pull(t){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");return o(this.__wbg_ptr),c.intounderlyingsource_pull(this.__wbg_ptr,t)}};Symbol.dispose&&(H.prototype[Symbol.dispose]=H.prototype.free);var L=class u{constructor(){throw new Error("cannot invoke `new` directly")}static __wrap(t){let e=Object.create(u.prototype);return e.__wbg_ptr=t,ct.register(e,e.__wbg_ptr,e),e}__destroy_into_raw(){let t=this.__wbg_ptr;return this.__wbg_ptr=0,ct.unregister(this),t}free(){let t=this.__destroy_into_raw();c.__wbg_jsowner_free(t,0)}};Symbol.dispose&&(L.prototype[Symbol.dispose]=L.prototype.free);function tt(){return{__proto__:null,"./web_bg.js":{__proto__:null,__wbg_Error_92b29b0548f8b746:function(){return s(function(t,e){return Error(l(t,e))},arguments)},__wbg_String_8564e559799eccda:function(){return s(function(t,e){let n=String(e),r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg___wbindgen_bigint_get_as_i64_d968e41184ae354f:function(t,e){let n=e,r=typeof n=="bigint"?n:void 0;g(r)||Lt(r),_().setBigInt64(t+8,g(r)?BigInt(0):r,!0),_().setInt32(t+0,!g(r),!0)},__wbg___wbindgen_boolean_get_fa956cfa2d1bd751:function(t){let e=t,n=typeof e=="boolean"?e:void 0;return g(n)||b(n),g(n)?16777215:n?1:0},__wbg___wbindgen_debug_string_c25d447a39f5578f:function(t,e){let n=Q(e),r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},__wbg___wbindgen_in_aca499c5de7ff5e5:function(t,e){let n=t in e;return b(n),n},__wbg___wbindgen_is_bigint_2f76dc55065b4273:function(t){let e=typeof t=="bigint";return b(e),e},__wbg___wbindgen_is_function_1ff95bcc5517c252:function(t){let e=typeof t=="function";return b(e),e},__wbg___wbindgen_is_object_a27215656b807791:function(t){let e=t,n=typeof e=="object"&&e!==null;return b(n),n},__wbg___wbindgen_is_string_ea5e6cc2e4141dfe:function(t){let e=typeof t=="string";return b(e),e},__wbg___wbindgen_is_undefined_c05833b95a3cf397:function(t){let e=t===void 0;return b(e),e},__wbg___wbindgen_jsval_eq_e659fcf7b0e32763:function(t,e){let n=t===e;return b(n),n},__wbg___wbindgen_jsval_loose_eq_db4c3b15f63fc170:function(t,e){let n=t==e;return b(n),n},__wbg___wbindgen_memory_de265df8aadd6273:function(){return c.memory},__wbg___wbindgen_number_get_394265ed1e1b84ee:function(t,e){let n=e,r=typeof n=="number"?n:void 0;g(r)||o(r),_().setFloat64(t+8,g(r)?0:r,!0),_().setInt32(t+0,!g(r),!0)},__wbg___wbindgen_string_get_b0ca35b86a603356:function(t,e){let n=e,r=typeof n=="string"?n:void 0;var i=g(r)?0:h(r,c.__wbindgen_malloc,c.__wbindgen_realloc),a=d;_().setInt32(t+4,a,!0),_().setInt32(t+0,i,!0)},__wbg___wbindgen_throw_344f42d3211c4765:function(t,e){throw new Error(l(t,e))},__wbg__wbg_cb_unref_fffb441def202758:function(){return s(function(t){t._wbg_cb_unref()},arguments)},__wbg_abort_8bae0f33e7833997:function(){return s(function(t){t.abort()},arguments)},__wbg_abort_eee9248a6d680839:function(){return s(function(t,e){t.abort(e)},arguments)},__wbg_activeElement_4bc99dc1a7094c27:function(){return s(function(t){let e=t.activeElement;return g(e)?0:m(e)},arguments)},__wbg_addEventListener_d85450ee1320c989:function(){return f(function(t,e,n,r){t.addEventListener(l(e,n),r)},arguments)},__wbg_altKey_50f830d1793a2eea:function(){return s(function(t){let e=t.altKey;return b(e),e},arguments)},__wbg_altKey_c5e44fde6beb66ef:function(){return s(function(t){let e=t.altKey;return b(e),e},arguments)},__wbg_altKey_f3e24c4c9cfcf271:function(){return s(function(t){let e=t.altKey;return b(e),e},arguments)},__wbg_animationName_e80680fbfd3da8a2:function(){return s(function(t,e){let n=e.animationName,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_appendChild_f553e8704c4f14a6:function(){return f(function(t,e){return t.appendChild(e)},arguments)},__wbg_append_01c74e5c6b58aa64:function(){return f(function(t,e,n,r,i){t.append(l(e,n),l(r,i))},arguments)},__wbg_append_58377ae3be2fb5ef:function(){return f(function(t,e,n,r,i,a){t.append(l(e,n),r,l(i,a))},arguments)},__wbg_append_8e24caa53c80c631:function(){return f(function(t,e,n,r,i){t.append(l(e,n),l(r,i))},arguments)},__wbg_append_91733ec40ee3b1f9:function(){return f(function(t,e,n,r){t.append(l(e,n),r)},arguments)},__wbg_arrayBuffer_3b637f0fa65c5351:function(){return f(function(t){return t.arrayBuffer()},arguments)},__wbg_arrayBuffer_a158e423a87ee756:function(){return s(function(t){return t.arrayBuffer()},arguments)},__wbg_back_939cbdbdfad8aff7:function(){return f(function(t){t.back()},arguments)},__wbg_blockSize_5af477b962b2b031:function(){return s(function(t){return t.blockSize},arguments)},__wbg_blur_e902dcc79406e89c:function(){return f(function(t){t.blur()},arguments)},__wbg_body_40ec34e0a2931fe8:function(){return s(function(t){let e=t.body;return g(e)?0:m(e)},arguments)},__wbg_borderBoxSize_ff7f5405dcc6554e:function(){return s(function(t){return t.borderBoxSize},arguments)},__wbg_boundingClientRect_0776888095b16b8c:function(){return s(function(t){return t.boundingClientRect},arguments)},__wbg_bubbles_07bec919f30033ab:function(){return s(function(t){let e=t.bubbles;return b(e),e},arguments)},__wbg_buffer_54b87055582c8a81:function(){return s(function(t){return t.buffer},arguments)},__wbg_button_f6a9a7b725f1838e:function(){return s(function(t){let e=t.button;return o(e),e},arguments)},__wbg_buttons_d8acd46cf8f40ae9:function(){return s(function(t){let e=t.buttons;return o(e),e},arguments)},__wbg_byobRequest_06b654bb15590436:function(){return s(function(t){let e=t.byobRequest;return g(e)?0:m(e)},arguments)},__wbg_byteLength_41862ca4020b9c43:function(){return s(function(t){let e=t.byteLength;return o(e),e},arguments)},__wbg_byteOffset_d42e18c4441f628b:function(){return s(function(t){let e=t.byteOffset;return o(e),e},arguments)},__wbg_call_8a2dd23819f8a60a:function(){return f(function(t,e){return t.call(e)},arguments)},__wbg_call_a6e5c5dce5018821:function(){return f(function(t,e,n){return t.call(e,n)},arguments)},__wbg_changedTouches_dbf6eeabddd3c2da:function(){return s(function(t){return t.changedTouches},arguments)},__wbg_charCodeAt_2a30bc7c17474cc6:function(){return s(function(t,e){return t.charCodeAt(e>>>0)},arguments)},__wbg_checkValidity_3a31dcce278f31a1:function(){return s(function(t){let e=t.checkValidity();return b(e),e},arguments)},__wbg_checked_596d0d7b35f55a01:function(){return s(function(t){let e=t.checked;return b(e),e},arguments)},__wbg_clearData_1297d08581746c08:function(){return f(function(t,e,n){t.clearData(l(e,n))},arguments)},__wbg_clearData_a7a19d854ec1a3b7:function(){return f(function(t){t.clearData()},arguments)},__wbg_clearInterval_16e8cbbce92291d0:function(){return s(function(t){return clearInterval(t)},arguments)},__wbg_clearTimeout_113b1cde814ec762:function(){return s(function(t){return clearTimeout(t)},arguments)},__wbg_clearTimeout_333bba87532ab9d3:function(){return s(function(t){return clearTimeout(t)},arguments)},__wbg_clearTimeout_6b8d9a38b9263d65:function(){return s(function(t){return clearTimeout(t)},arguments)},__wbg_clientHeight_994541cde34d3ca0:function(){return s(function(t){let e=t.clientHeight;return o(e),e},arguments)},__wbg_clientWidth_6852617da948be39:function(){return s(function(t){let e=t.clientWidth;return o(e),e},arguments)},__wbg_clientX_a7dcb4081126cd4b:function(){return s(function(t){let e=t.clientX;return o(e),e},arguments)},__wbg_clientX_c396b0fb11d601d3:function(){return s(function(t){let e=t.clientX;return o(e),e},arguments)},__wbg_clientY_a4650836fdf58f01:function(){return s(function(t){let e=t.clientY;return o(e),e},arguments)},__wbg_clientY_c0560910b20ee192:function(){return s(function(t){let e=t.clientY;return o(e),e},arguments)},__wbg_close_249a23304523681b:function(){return f(function(t){t.close()},arguments)},__wbg_close_72d318d9c16e83ef:function(){return f(function(t){t.close()},arguments)},__wbg_code_89c999e407c79eef:function(){return s(function(t,e){let n=e.code,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_contentBoxSize_74fbbc51859ff90e:function(){return s(function(t){return t.contentBoxSize},arguments)},__wbg_createComment_003419d0740789d4:function(){return s(function(t,e,n){return t.createComment(l(e,n))},arguments)},__wbg_createElementNS_013b3fb26f4796ec:function(){return f(function(t,e,n,r,i){return t.createElementNS(e===0?void 0:l(e,n),l(r,i))},arguments)},__wbg_createElement_fcbc0805de826d62:function(){return f(function(t,e,n){return t.createElement(l(e,n))},arguments)},__wbg_createObjectURL_416e527781e6fd6d:function(){return f(function(t,e){let n=URL.createObjectURL(e),r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_createTextNode_4dad5b18435dda7c:function(){return s(function(t,e,n){return t.createTextNode(l(e,n))},arguments)},__wbg_ctrlKey_2e52816fa7160097:function(){return s(function(t){let e=t.ctrlKey;return b(e),e},arguments)},__wbg_ctrlKey_50bd8324959ca786:function(){return s(function(t){let e=t.ctrlKey;return b(e),e},arguments)},__wbg_ctrlKey_57171169eab54da6:function(){return s(function(t){let e=t.ctrlKey;return b(e),e},arguments)},__wbg_dataTransfer_c1c4745cee7e05f1:function(){return s(function(t){let e=t.dataTransfer;return g(e)?0:m(e)},arguments)},__wbg_data_f994b1bb75d8337a:function(){return s(function(t,e){let n=e.data;var r=g(n)?0:h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_deltaMode_d869228efd74f393:function(){return s(function(t){let e=t.deltaMode;return o(e),e},arguments)},__wbg_deltaX_5d829ffba565ed10:function(){return s(function(t){return t.deltaX},arguments)},__wbg_deltaY_6cfce8f8da250c23:function(){return s(function(t){return t.deltaY},arguments)},__wbg_deltaZ_42c86f225c34aa04:function(){return s(function(t){return t.deltaZ},arguments)},__wbg_detail_a90dcd774780ebf6:function(){return s(function(t){return t.detail},arguments)},__wbg_documentElement_b7ec99417969bfbc:function(){return s(function(t){let e=t.documentElement;return g(e)?0:m(e)},arguments)},__wbg_document_179650d6cb13c263:function(){return s(function(t){let e=t.document;return g(e)?0:m(e)},arguments)},__wbg_done_89b2b13e91a60321:function(){return s(function(t){let e=t.done;return b(e),e},arguments)},__wbg_dropEffect_8187d3b019f3e6bd:function(){return s(function(t,e){let n=e.dropEffect,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_effectAllowed_ca2550f3a73fb833:function(){return s(function(t,e){let n=e.effectAllowed,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_elapsedTime_0330f570ff694c6f:function(){return s(function(t){return t.elapsedTime},arguments)},__wbg_elapsedTime_4c2a1fd1473438d6:function(){return s(function(t){return t.elapsedTime},arguments)},__wbg_enqueue_6d83b4c6281bafd6:function(){return f(function(t,e){t.enqueue(e)},arguments)},__wbg_entries_015dc610cd81ede0:function(){return s(function(t){return Object.entries(t)},arguments)},__wbg_entries_8ddbe5d352d85237:function(){return s(function(t){return t.entries()},arguments)},__wbg_entries_900cefd6f70eb290:function(){return s(function(t){return t.entries()},arguments)},__wbg_error_744744ff0c9861e6:function(){return s(function(t){console.error(t)},arguments)},__wbg_fetch_074561c3e313c86f:function(){return s(function(t){return fetch(t)},arguments)},__wbg_fetch_9dad4fe911207b37:function(){return s(function(t){return fetch(t)},arguments)},__wbg_fetch_b5951fc96f52f786:function(){return s(function(t,e){return t.fetch(e)},arguments)},__wbg_files_116196bc012ac3c8:function(){return s(function(t){let e=t.files;return g(e)?0:m(e)},arguments)},__wbg_files_a4eb87e5e4343c46:function(){return s(function(t){let e=t.files;return g(e)?0:m(e)},arguments)},__wbg_focus_2f77051f98540625:function(){return f(function(t){t.focus()},arguments)},__wbg_force_368c1897f399d783:function(){return s(function(t){return t.force},arguments)},__wbg_forward_4bb54c7f45451c64:function(){return f(function(t){t.forward()},arguments)},__wbg_getAsFile_adead4fd4f4ce592:function(){return f(function(t){let e=t.getAsFile();return g(e)?0:m(e)},arguments)},__wbg_getAttribute_5a601ba4718b922a:function(){return s(function(t,e,n,r){let i=e.getAttribute(l(n,r));var a=g(i)?0:h(i,c.__wbindgen_malloc,c.__wbindgen_realloc),w=d;_().setInt32(t+4,w,!0),_().setInt32(t+0,a,!0)},arguments)},__wbg_getBoundingClientRect_e828e6c31c66dea6:function(){return s(function(t){return t.getBoundingClientRect()},arguments)},__wbg_getData_fcb88fae21d94f1e:function(){return f(function(t,e,n,r){let i=e.getData(l(n,r)),a=h(i,c.__wbindgen_malloc,c.__wbindgen_realloc),w=d;_().setInt32(t+4,w,!0),_().setInt32(t+0,a,!0)},arguments)},__wbg_getElementById_1cbd8f06dbe8eb8e:function(){return s(function(t,e,n){let r=t.getElementById(l(e,n));return g(r)?0:m(r)},arguments)},__wbg_getHours_9f6561095682ce51:function(){return s(function(t){let e=t.getHours();return o(e),e},arguments)},__wbg_getItem_b96269ddc16cf24a:function(){return f(function(t,e,n,r){let i=e.getItem(l(n,r));var a=g(i)?0:h(i,c.__wbindgen_malloc,c.__wbindgen_realloc),w=d;_().setInt32(t+4,w,!0),_().setInt32(t+0,a,!0)},arguments)},__wbg_getMinutes_b0d5cd90bf9b8f22:function(){return s(function(t){let e=t.getMinutes();return o(e),e},arguments)},__wbg_getNode_2f3b1f608db7c9d0:function(){return s(function(t,e){return t.getNode(e>>>0)},arguments)},__wbg_getSeconds_40c565b3a6cb05fe:function(){return s(function(t){let e=t.getSeconds();return o(e),e},arguments)},__wbg_get_507a50627bffa49b:function(){return s(function(t,e){return t[e>>>0]},arguments)},__wbg_get_757c867e2520bbc4:function(){return s(function(t,e){let n=t[e>>>0];return g(n)?0:m(n)},arguments)},__wbg_get_78f252d074a84d0b:function(){return f(function(t,e){return Reflect.get(t,e)},arguments)},__wbg_get_base_path_39628b0b6ddfa96a:function(){return s(function(t){let e=st(),n=h(e,c.__wbindgen_malloc,c.__wbindgen_realloc),r=d;_().setInt32(t+4,r,!0),_().setInt32(t+0,n,!0)},arguments)},__wbg_get_c7eb1f358a7654df:function(){return f(function(t,e){return Reflect.get(t,e)},arguments)},__wbg_get_e73985d6689d2245:function(){return s(function(t,e){let n=t[e>>>0];return g(n)?0:m(n)},arguments)},__wbg_get_select_data_60af93fcbe2f391c:function(){return s(function(t,e){let n=rt(e),r=Mt(n,c.__wbindgen_malloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_get_unchecked_6e0ad6d2a41b06f6:function(){return s(function(t,e){return t[e>>>0]},arguments)},__wbg_has_8374cf06984d8bfc:function(){return f(function(t,e){let n=Reflect.has(t,e);return b(n),n},arguments)},__wbg_hash_508149c4291ec8c2:function(){return f(function(t,e){let n=e.hash,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_head_41a60f9034e0b41a:function(){return s(function(t){let e=t.head;return g(e)?0:m(e)},arguments)},__wbg_headers_cf9c80f30e2a4eff:function(){return s(function(t){return t.headers},arguments)},__wbg_height_6f29ab40ae50636d:function(){return s(function(t){let e=t.height;return o(e),e},arguments)},__wbg_height_96c07d9559d0200a:function(){return s(function(t){return t.height},arguments)},__wbg_height_9f27216001e3c804:function(){return s(function(t){return t.height},arguments)},__wbg_hidden_c08eb1c29c138ab0:function(){return s(function(t){let e=t.hidden;return b(e),e},arguments)},__wbg_history_e648b4314d9b256e:function(){return f(function(t){return t.history},arguments)},__wbg_identifier_d30bb260fab6b02a:function(){return s(function(t){let e=t.identifier;return o(e),e},arguments)},__wbg_initialize_169e37fbdd472b20:function(){return s(function(t,e,n){t.initialize(e,n)},arguments)},__wbg_inlineSize_3c8412828bef21eb:function(){return s(function(t){return t.inlineSize},arguments)},__wbg_instanceof_AnimationEvent_3a83c3d21fbd4d01:function(){return s(function(t){let e;try{e=t instanceof AnimationEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_ArrayBuffer_4480b9e0068a8adb:function(){return s(function(t){let e;try{e=t instanceof ArrayBuffer}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Blob_c6523f92a32c8695:function(){return s(function(t){let e;try{e=t instanceof Blob}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_CompositionEvent_6fef075df3b5dbf4:function(){return s(function(t){let e;try{e=t instanceof CompositionEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_CustomEvent_9b848ed45794fd3e:function(){return s(function(t){let e;try{e=t instanceof CustomEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Document_d1955f84f5d0351c:function(){return s(function(t){let e;try{e=t instanceof Document}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_DragEvent_7bd2cb4c087838f2:function(){return s(function(t){let e;try{e=t instanceof DragEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Element_beebfaab75d12d9d:function(){return s(function(t){let e;try{e=t instanceof Element}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Event_512f3841fa744d1e:function(){return s(function(t){let e;try{e=t instanceof Event}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_File_ee62de53bca2e697:function(){return s(function(t){let e;try{e=t instanceof File}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_FocusEvent_cadb56dad3dfd4ac:function(){return s(function(t){let e;try{e=t instanceof FocusEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_HtmlElement_4493a09212d3586f:function(){return s(function(t){let e;try{e=t instanceof HTMLElement}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_HtmlFormElement_ebf2bd35b418e93e:function(){return s(function(t){let e;try{e=t instanceof HTMLFormElement}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_HtmlInputElement_ad3be04339d0e4df:function(){return s(function(t){let e;try{e=t instanceof HTMLInputElement}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_HtmlSelectElement_b4698f847dc49da5:function(){return s(function(t){let e;try{e=t instanceof HTMLSelectElement}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_HtmlTextAreaElement_37795f65e16b7ed0:function(){return s(function(t){let e;try{e=t instanceof HTMLTextAreaElement}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_KeyboardEvent_be49f2d8e15d587a:function(){return s(function(t){let e;try{e=t instanceof KeyboardEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Map_e5b5e3db98422fcc:function(){return s(function(t){let e;try{e=t instanceof Map}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_MouseEvent_89eddfc6203c1749:function(){return s(function(t){let e;try{e=t instanceof MouseEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Node_d29e7ded486fd76a:function(){return s(function(t){let e;try{e=t instanceof Node}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_PointerEvent_8ef1feb51407c0ed:function(){return s(function(t){let e;try{e=t instanceof PointerEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Response_c8b64b2256f01bec:function(){return s(function(t){let e;try{e=t instanceof Response}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_TouchEvent_62e9e212135a784b:function(){return s(function(t){let e;try{e=t instanceof TouchEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_TransitionEvent_a1842850468877e4:function(){return s(function(t){let e;try{e=t instanceof TransitionEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Uint8Array_309b927aaf7a3fc7:function(){return s(function(t){let e;try{e=t instanceof Uint8Array}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_WheelEvent_8a8f43ee9318fcd4:function(){return s(function(t){let e;try{e=t instanceof WheelEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Window_05ba1ee4f6781663:function(){return s(function(t){let e;try{e=t instanceof Window}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_intersectionRatio_7c65292cc5ad712c:function(){return s(function(t){return t.intersectionRatio},arguments)},__wbg_intersectionRect_be1020a3be2ed245:function(){return s(function(t){return t.intersectionRect},arguments)},__wbg_isArray_0677c962b281d01a:function(){return s(function(t){let e=Array.isArray(t);return b(e),e},arguments)},__wbg_isComposing_919a0fdf6ac030c9:function(){return s(function(t){let e=t.isComposing;return b(e),e},arguments)},__wbg_isIntersecting_fc6d9529a49c5d62:function(){return s(function(t){let e=t.isIntersecting;return b(e),e},arguments)},__wbg_isPrimary_e59b27f91017e844:function(){return s(function(t){let e=t.isPrimary;return b(e),e},arguments)},__wbg_isSafeInteger_04f36e4056f1b851:function(){return s(function(t){let e=Number.isSafeInteger(t);return b(e),e},arguments)},__wbg_item_74998074fc497f92:function(){return s(function(t,e){let n=t.item(e>>>0);return g(n)?0:m(n)},arguments)},__wbg_items_350b6f2d566d3def:function(){return s(function(t){return t.items},arguments)},__wbg_iterator_6f722e4a93058b71:function(){return s(function(){return Symbol.iterator},arguments)},__wbg_key_803dca86cdcfa8dd:function(){return s(function(t,e){let n=e.key,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_kind_c494ca014c671a6f:function(){return s(function(t,e){let n=e.kind,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_lastModified_41250e8004d0f7ce:function(){return s(function(t){return t.lastModified},arguments)},__wbg_left_7e76a74d0db1754f:function(){return s(function(t){return t.left},arguments)},__wbg_length_02c64e687322fa34:function(){return s(function(t){let e=t.length;return o(e),e},arguments)},__wbg_length_1f0964f4a5e2c6d8:function(){return s(function(t){let e=t.length;return o(e),e},arguments)},__wbg_length_370319915dc99107:function(){return s(function(t){let e=t.length;return o(e),e},arguments)},__wbg_length_e08fc23135c66d6f:function(){return s(function(t){let e=t.length;return o(e),e},arguments)},__wbg_length_eea4bfa35e75c87c:function(){return s(function(t){let e=t.length;return o(e),e},arguments)},__wbg_length_ef21514bf74fe712:function(){return s(function(t){let e=t.length;return o(e),e},arguments)},__wbg_localStorage_5bf6ce3f8e51412a:function(){return f(function(t){let e=t.localStorage;return g(e)?0:m(e)},arguments)},__wbg_location_8f24df2c257fb974:function(){return s(function(t){let e=t.location;return o(e),e},arguments)},__wbg_location_c9a2271428996698:function(){return s(function(t){return t.location},arguments)},__wbg_log_0c201ade58bb55e1:function(){return s(function(t,e,n,r,i,a,w,p){let y,A;try{y=t,A=e,console.log(l(t,e),l(n,r),l(i,a),l(w,p))}finally{c.__wbindgen_free(y,A,1)}},arguments)},__wbg_log_ce2c4456b290c5e7:function(){return s(function(t,e){let n,r;try{n=t,r=e,console.log(l(t,e))}finally{c.__wbindgen_free(n,r,1)}},arguments)},__wbg_mark_b4d943f3bc2d2404:function(){return s(function(t,e){performance.mark(l(t,e))},arguments)},__wbg_measure_84362959e621a2c1:function(){return f(function(t,e,n,r){let i,a,w,p;try{i=t,a=e,w=n,p=r,performance.measure(l(t,e),l(n,r))}finally{c.__wbindgen_free(i,a,1),c.__wbindgen_free(w,p,1)}},arguments)},__wbg_metaKey_7a85debd51844822:function(){return s(function(t){let e=t.metaKey;return b(e),e},arguments)},__wbg_metaKey_d961c7572a9f84f5:function(){return s(function(t){let e=t.metaKey;return b(e),e},arguments)},__wbg_metaKey_f934f09e37889d70:function(){return s(function(t){let e=t.metaKey;return b(e),e},arguments)},__wbg_name_14e920dc23fffd96:function(){return s(function(t,e){let n=e.name,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_name_d7d79f5466e37447:function(){return s(function(t,e){let n=e.name,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_new_0912d735e8fbc1d3:function(){return f(function(){return new FormData},arguments)},__wbg_new_0_3da9e97f24fc69be:function(){return s(function(){return new Date},arguments)},__wbg_new_0d809930cd1354c6:function(){return f(function(){return new Headers},arguments)},__wbg_new_22598f2b091dadf2:function(){return s(function(t){return new W(L.__wrap(t))},arguments)},__wbg_new_26bdcffba762c064:function(){return s(function(t){return new U(t>>>0)},arguments)},__wbg_new_32b398fb48b6d94a:function(){return s(function(){return new Array},arguments)},__wbg_new_41e6f99b2fd20423:function(){return f(function(){return new FileReader},arguments)},__wbg_new_4339b2a2675a03e3:function(){return f(function(){return new AbortController},arguments)},__wbg_new_7796ffc7ed656783:function(){return s(function(){return new Map},arguments)},__wbg_new_9792ad3275d1dd31:function(){return f(function(){return new DataTransfer},arguments)},__wbg_new_b667d279fd5aa943:function(){return s(function(t,e){return new Error(l(t,e))},arguments)},__wbg_new_cd45aabdf6073e84:function(){return s(function(t){return new Uint8Array(t)},arguments)},__wbg_new_da52cf8fe3429cb2:function(){return s(function(){return new Object},arguments)},__wbg_new_from_slice_77cdfb7977362f3c:function(){return s(function(t,e){return new Uint8Array(J(t,e))},arguments)},__wbg_new_typed_1824d93f294193e5:function(){return s(function(t,e){try{var n={a:t,b:e},r=(a,w)=>{let p=n.a;n.a=0;try{return It(p,n.b,a,w)}finally{n.a=p}};return new Promise(r)}finally{n.a=0}},arguments)},__wbg_new_with_args_200d82645b6544eb:function(){return s(function(t,e,n,r){return new Function(l(t,e),l(n,r))},arguments)},__wbg_new_with_byte_offset_and_length_54c7724ee3ec7d82:function(){return s(function(t,e,n){return new Uint8Array(t,e>>>0,n>>>0)},arguments)},__wbg_new_with_form_e4ca634e481666c7:function(){return f(function(t){return new FormData(t)},arguments)},__wbg_new_with_str_and_init_d95cbe11ce28e65e:function(){return f(function(t,e,n){return new Request(l(t,e),n)},arguments)},__wbg_new_with_str_sequence_and_options_9db076dc44ddbeb0:function(){return f(function(t,e){return new Blob(t,e)},arguments)},__wbg_new_with_u8_array_sequence_and_options_2c1900e5a5c93850:function(){return f(function(t,e){return new Blob(t,e)},arguments)},__wbg_next_6dbf2c0ac8cde20f:function(){return s(function(t){return t.next},arguments)},__wbg_next_71f2aa1cb3d1e37e:function(){return f(function(t){return t.next()},arguments)},__wbg_now_86c0d4ba3fa605b8:function(){return s(function(){return Date.now()},arguments)},__wbg_offsetX_fdc5eb20edabaadb:function(){return s(function(t){let e=t.offsetX;return o(e),e},arguments)},__wbg_offsetY_0a05e99022d21c5b:function(){return s(function(t){let e=t.offsetY;return o(e),e},arguments)},__wbg_open_221b279749ba2e4e:function(){return f(function(t,e,n,r,i){let a=t.open(l(e,n),l(r,i));return g(a)?0:m(a)},arguments)},__wbg_origin_ed66c06e67ad2049:function(){return f(function(t,e){let n=e.origin,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_ownerDocument_5a7a5473f8709b3e:function(){return s(function(t){let e=t.ownerDocument;return g(e)?0:m(e)},arguments)},__wbg_pageX_56e23ef1ade65aa7:function(){return s(function(t){let e=t.pageX;return o(e),e},arguments)},__wbg_pageX_9c5f057472795ea1:function(){return s(function(t){let e=t.pageX;return o(e),e},arguments)},__wbg_pageY_12d134258ad141c4:function(){return s(function(t){let e=t.pageY;return o(e),e},arguments)},__wbg_pageY_d421aa8cfce954d6:function(){return s(function(t){let e=t.pageY;return o(e),e},arguments)},__wbg_parentElement_5030754e30795652:function(){return s(function(t){let e=t.parentElement;return g(e)?0:m(e)},arguments)},__wbg_pathname_d27a358088ce7b2b:function(){return f(function(t,e){let n=e.pathname,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_pointerId_ea33d2695be12e7f:function(){return s(function(t){let e=t.pointerId;return o(e),e},arguments)},__wbg_pointerType_d5e932608aa61bb6:function(){return s(function(t,e){let n=e.pointerType,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_pressure_9a7845d9744ae9f4:function(){return s(function(t){return t.pressure},arguments)},__wbg_preventDefault_b64888c857500682:function(){return s(function(t){t.preventDefault()},arguments)},__wbg_propertyName_835d4a18e8327b10:function(){return s(function(t,e){let n=e.propertyName,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_prototypesetcall_4770620bbe4688a0:function(){return s(function(t,e,n){Uint8Array.prototype.set.call(J(t,e),n)},arguments)},__wbg_pseudoElement_174adc902d41a1c1:function(){return s(function(t,e){let n=e.pseudoElement,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_pseudoElement_6013088f8877903f:function(){return s(function(t,e){let n=e.pseudoElement,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_pushState_3d01701623122bc8:function(){return f(function(t,e,n,r,i,a){t.pushState(e,l(n,r),i===0?void 0:l(i,a))},arguments)},__wbg_push_d2ae3af0c1217ae6:function(){return s(function(t,e){let n=t.push(e);return o(n),n},arguments)},__wbg_queueMicrotask_0ab5b2d2393e99b9:function(){return s(function(t){return t.queueMicrotask},arguments)},__wbg_queueMicrotask_6a09b7bc46549209:function(){return s(function(t){queueMicrotask(t)},arguments)},__wbg_radiusX_06f8dad66dfba7a4:function(){return s(function(t){let e=t.radiusX;return o(e),e},arguments)},__wbg_radiusY_0658ca1fd998f494:function(){return s(function(t){let e=t.radiusY;return o(e),e},arguments)},__wbg_readAsArrayBuffer_7db0a55c6c3a2b4e:function(){return f(function(t,e){t.readAsArrayBuffer(e)},arguments)},__wbg_readAsText_a8f6dfc210ba1a8e:function(){return f(function(t,e){t.readAsText(e)},arguments)},__wbg_removeAttribute_1e7d2c409776d836:function(){return f(function(t,e,n){t.removeAttribute(l(e,n))},arguments)},__wbg_removeEventListener_a3f23c70077bdcc1:function(){return f(function(t,e,n,r){t.removeEventListener(l(e,n),r)},arguments)},__wbg_removeItem_78e03a38da96e0ae:function(){return f(function(t,e,n){t.removeItem(l(e,n))},arguments)},__wbg_repeat_4e131e99bff9b9f4:function(){return s(function(t){let e=t.repeat;return b(e),e},arguments)},__wbg_replaceState_9a0a4a53d3bf3439:function(){return f(function(t,e,n,r,i,a){t.replaceState(e,l(n,r),i===0?void 0:l(i,a))},arguments)},__wbg_requestAnimationFrame_1a85deeab66448c2:function(){return f(function(t,e){let n=t.requestAnimationFrame(e);return o(n),n},arguments)},__wbg_resolve_2191a4dfe481c25b:function(){return s(function(t){return Promise.resolve(t)},arguments)},__wbg_respond_510e32df8aeb6817:function(){return f(function(t,e){t.respond(e>>>0)},arguments)},__wbg_result_53fd7283ffc3cdb8:function(){return f(function(t){return t.result},arguments)},__wbg_rootBounds_f45f30011740fdb2:function(){return s(function(t){let e=t.rootBounds;return g(e)?0:m(e)},arguments)},__wbg_rotationAngle_d0a0b686498034d7:function(){return s(function(t){return t.rotationAngle},arguments)},__wbg_run_9f0b5ec848bddc2d:function(){return s(function(t){t.run()},arguments)},__wbg_rustRecv_ce812a5965920185:function(){return s(function(t){return t.rustRecv()},arguments)},__wbg_rustSend_27a0ddfb6f0fa952:function(){return s(function(t,e){t.rustSend(e)},arguments)},__wbg_saveTemplate_4aa5c34bf8b14cc9:function(){return s(function(t,e,n,r){var i=zt(e,n).slice();c.__wbindgen_free(e,n*4,4),t.saveTemplate(i,r)},arguments)},__wbg_screenX_0a3f7a47942676bd:function(){return s(function(t){let e=t.screenX;return o(e),e},arguments)},__wbg_screenX_bd1fb25d48033c9c:function(){return s(function(t){let e=t.screenX;return o(e),e},arguments)},__wbg_screenY_30eadec06612b80f:function(){return s(function(t){let e=t.screenY;return o(e),e},arguments)},__wbg_screenY_7e467250657a3c56:function(){return s(function(t){let e=t.screenY;return o(e),e},arguments)},__wbg_scrollHeight_8cf19eb16ebc9b9b:function(){return s(function(t){let e=t.scrollHeight;return o(e),e},arguments)},__wbg_scrollIntoView_d8b806f471b7418e:function(){return s(function(t,e){t.scrollIntoView(e)},arguments)},__wbg_scrollLeft_5be50f489b342a09:function(){return s(function(t){let e=t.scrollLeft;return o(e),e},arguments)},__wbg_scrollTo_cac0dff19f631942:function(){return s(function(t,e,n){t.scrollTo(e,n)},arguments)},__wbg_scrollTop_b3effa9c5de14d21:function(){return s(function(t){let e=t.scrollTop;return o(e),e},arguments)},__wbg_scrollWidth_38006a7134cdfeff:function(){return s(function(t){let e=t.scrollWidth;return o(e),e},arguments)},__wbg_scrollX_9da7f7defce2297e:function(){return f(function(t){return t.scrollX},arguments)},__wbg_scrollY_b4c56e98c6d976ad:function(){return f(function(t){return t.scrollY},arguments)},__wbg_scroll_4a3297b235bee8de:function(){return s(function(t,e){t.scroll(e)},arguments)},__wbg_search_af2555aa41bd23cc:function(){return f(function(t,e){let n=e.search,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_setAttributeInner_11a30d36aa43287e:function(){return s(function(t,e,n,r,i,a){nt(t,l(e,n),r,i===0?void 0:l(i,a))},arguments)},__wbg_setAttribute_71039043be82d098:function(){return f(function(t,e,n,r,i){t.setAttribute(l(e,n),l(r,i))},arguments)},__wbg_setData_19a2f9f5b313cbd6:function(){return f(function(t,e,n,r,i){t.setData(l(e,n),l(r,i))},arguments)},__wbg_setInterval_84b64f01452a246e:function(){return f(function(t,e){return setInterval(t,e)},arguments)},__wbg_setItem_364a11cf21db9039:function(){return f(function(t,e,n,r,i){t.setItem(l(e,n),l(r,i))},arguments)},__wbg_setProperty_e4e51b1b1d681d15:function(){return f(function(t,e,n,r,i){t.setProperty(l(e,n),l(r,i))},arguments)},__wbg_setTimeout_3a808dd861dd3c12:function(){return s(function(t,e){return setTimeout(t,e)},arguments)},__wbg_setTimeout_ef24d2fc3ad97385:function(){return f(function(t,e){return setTimeout(t,e)},arguments)},__wbg_setTimeout_f757f00851f76c42:function(){return s(function(t,e){return setTimeout(t,e)},arguments)},__wbg_set_4d7dd76f3dae2926:function(){return s(function(t,e,n){t.set(J(e,n))},arguments)},__wbg_set_575dd786d51585f8:function(){return s(function(t,e,n){return t.set(e,n)},arguments)},__wbg_set_6be42768c690e380:function(){return s(function(t,e,n){t[e]=n},arguments)},__wbg_set_8a16b38e4805b298:function(){return s(function(t,e,n){t[e>>>0]=n},arguments)},__wbg_set_behavior_af2ac621388b739f:function(){return s(function(t,e){t.behavior=ut[e]},arguments)},__wbg_set_behavior_f9f984e684b645bc:function(){return s(function(t,e){t.behavior=ut[e]},arguments)},__wbg_set_block_8135b3acafa1ca88:function(){return s(function(t,e){t.block=it[e]},arguments)},__wbg_set_body_029f2d171e0a005f:function(){return s(function(t,e){t.body=e},arguments)},__wbg_set_cache_b4a740b195c051f4:function(){return s(function(t,e){t.cache=xt[e]},arguments)},__wbg_set_credentials_bb34a40189e3b43b:function(){return s(function(t,e){t.credentials=Tt[e]},arguments)},__wbg_set_dropEffect_ee044779833a313d:function(){return s(function(t,e,n){t.dropEffect=l(e,n)},arguments)},__wbg_set_effectAllowed_70e1a79093efb47f:function(){return s(function(t,e,n){t.effectAllowed=l(e,n)},arguments)},__wbg_set_headers_9c61d123c3ee1f10:function(){return s(function(t,e){t.headers=e},arguments)},__wbg_set_href_960e4284e5cae151:function(){return f(function(t,e,n){t.href=l(e,n)},arguments)},__wbg_set_inline_77b0fb4f96d76814:function(){return s(function(t,e){t.inline=it[e]},arguments)},__wbg_set_left_18508443258534ad:function(){return s(function(t,e){t.left=e},arguments)},__wbg_set_method_5532d59b92d76467:function(){return s(function(t,e,n){t.method=l(e,n)},arguments)},__wbg_set_mode_66c79886ad78fc05:function(){return s(function(t,e){t.mode=St[e]},arguments)},__wbg_set_onload_4dc1f96725e4138c:function(){return s(function(t,e){t.onload=e},arguments)},__wbg_set_scrollRestoration_29b3e9dc74898bc5:function(){return f(function(t,e){t.scrollRestoration=Nt[e]},arguments)},__wbg_set_signal_c4ef8faddb4c1446:function(){return s(function(t,e){t.signal=e},arguments)},__wbg_set_textContent_54dcad83ae15772d:function(){return s(function(t,e,n){t.textContent=e===0?void 0:l(e,n)},arguments)},__wbg_set_top_29926a592a2d228a:function(){return s(function(t,e){t.top=e},arguments)},__wbg_set_type_8ce203e412e28cf6:function(){return s(function(t,e,n){t.type=l(e,n)},arguments)},__wbg_shiftKey_42866b295d317445:function(){return s(function(t){let e=t.shiftKey;return b(e),e},arguments)},__wbg_shiftKey_9bcb8bdd60c2f152:function(){return s(function(t){let e=t.shiftKey;return b(e),e},arguments)},__wbg_shiftKey_9f797da486b2ade8:function(){return s(function(t){let e=t.shiftKey;return b(e),e},arguments)},__wbg_signal_dad7cb35193abd31:function(){return s(function(t){return t.signal},arguments)},__wbg_size_6304a694765921a9:function(){return s(function(t){return t.size},arguments)},__wbg_state_edcc5b2da67f07f2:function(){return f(function(t){return t.state},arguments)},__wbg_static_accessor_GLOBAL_4ef717fb391d88b7:function(){return s(function(){let t=typeof global>"u"?null:global;return g(t)?0:m(t)},arguments)},__wbg_static_accessor_GLOBAL_THIS_8d1badc68b5a74f4:function(){return s(function(){let t=typeof globalThis>"u"?null:globalThis;return g(t)?0:m(t)},arguments)},__wbg_static_accessor_SELF_146583524fe1469b:function(){return s(function(){let t=typeof self>"u"?null:self;return g(t)?0:m(t)},arguments)},__wbg_static_accessor_WINDOW_f2829a2234d7819e:function(){return s(function(){let t=typeof window>"u"?null:window;return g(t)?0:m(t)},arguments)},__wbg_status_c45b3b9b3033184a:function(){return s(function(t){let e=t.status;return o(e),e},arguments)},__wbg_stringify_b54333f60f1e4dad:function(){return f(function(t){return JSON.stringify(t)},arguments)},__wbg_style_6657aed849e5d757:function(){return s(function(t){return t.style},arguments)},__wbg_tagName_d99c8072027f3c98:function(){return s(function(t,e){let n=e.tagName,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_tangentialPressure_979a239d3db31d90:function(){return s(function(t){return t.tangentialPressure},arguments)},__wbg_targetTouches_3e9bdb053b2d5023:function(){return s(function(t){return t.targetTouches},arguments)},__wbg_target_e759594a8d965ed7:function(){return s(function(t){let e=t.target;return g(e)?0:m(e)},arguments)},__wbg_textContent_37277f66248f39e6:function(){return s(function(t,e){let n=e.textContent;var r=g(n)?0:h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_text_d3a29f7525a132c3:function(){return f(function(t){return t.text()},arguments)},__wbg_then_16d107c451e9905d:function(){return s(function(t,e,n){return t.then(e,n)},arguments)},__wbg_then_6ec10ae38b3e92f7:function(){return s(function(t,e){return t.then(e)},arguments)},__wbg_tiltX_1327e8185e612854:function(){return s(function(t){let e=t.tiltX;return o(e),e},arguments)},__wbg_tiltY_b44744ee36b60a24:function(){return s(function(t){let e=t.tiltY;return o(e),e},arguments)},__wbg_time_2e33e99ff5e53342:function(){return s(function(t){return t.time},arguments)},__wbg_top_fe120acfa924a430:function(){return s(function(t){return t.top},arguments)},__wbg_touches_a631c50f1b367753:function(){return s(function(t){return t.touches},arguments)},__wbg_twist_6cc18194426f8a4f:function(){return s(function(t){let e=t.twist;return o(e),e},arguments)},__wbg_type_06f2150affb3c059:function(){return s(function(t,e){let n=e.type,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_type_9d13c17ea2611dd0:function(){return s(function(t,e){let n=e.type,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_type_c1987e7fbaf7340e:function(){return s(function(t,e){let n=e.type,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_update_memory_ddf6b41a329aec73:function(){return s(function(t,e){t.update_memory(e)},arguments)},__wbg_url_abdb8fb08377f8c0:function(){return s(function(t,e){let n=e.url,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_value_1f687dfa7d6c3d08:function(){return s(function(t,e){let n=e.value,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_value_a5d5488a9589444a:function(){return s(function(t){return t.value},arguments)},__wbg_value_c40f8f7227bb3a9e:function(){return s(function(t,e){let n=e.value,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_value_d7621df0105931d8:function(){return s(function(t,e){let n=e.value,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_view_21f1d4a4f175dfa9:function(){return s(function(t){let e=t.view;return g(e)?0:m(e)},arguments)},__wbg_weak_4a47d74ffa0a7f96:function(){return s(function(t){return t.weak()},arguments)},__wbg_width_16032a5bda5e6fa9:function(){return s(function(t){let e=t.width;return o(e),e},arguments)},__wbg_width_20c45c895834b83f:function(){return s(function(t){return t.width},arguments)},__wbg_width_219185400361db86:function(){return s(function(t){return t.width},arguments)},__wbg_x_71553b4e719d215a:function(){return s(function(t){return t.x},arguments)},__wbg_y_111b04aa46dc0f86:function(){return s(function(t){return t.y},arguments)},__wbindgen_cast_0000000000000001:function(){return s(function(t,e){return k(t,e,Et)},arguments)},__wbindgen_cast_0000000000000002:function(){return s(function(t,e){return k(t,e,yt)},arguments)},__wbindgen_cast_0000000000000003:function(){return s(function(t,e){return k(t,e,vt)},arguments)},__wbindgen_cast_0000000000000004:function(){return s(function(t,e){return Bt(t,e,kt)},arguments)},__wbindgen_cast_0000000000000005:function(){return s(function(t,e){return k(t,e,ht)},arguments)},__wbindgen_cast_0000000000000006:function(){return s(function(t,e){return k(t,e,wt)},arguments)},__wbindgen_cast_0000000000000007:function(){return s(function(t,e){return k(t,e,mt)},arguments)},__wbindgen_cast_0000000000000008:function(){return s(function(t,e){return k(t,e,pt)},arguments)},__wbindgen_cast_0000000000000009:function(){return s(function(t){return t},arguments)},__wbindgen_cast_000000000000000a:function(){return s(function(t){return t},arguments)},__wbindgen_cast_000000000000000b:function(){return s(function(t,e){return l(t,e)},arguments)},__wbindgen_cast_000000000000000c:function(){return s(function(t){return BigInt.asUintN(64,t)},arguments)},__wbindgen_init_externref_table:function(){let t=c.__wbindgen_externrefs,e=t.grow(4);t.set(0,void 0),t.set(e+0,void 0),t.set(e+1,null),t.set(e+2,!0),t.set(e+3,!1)}}}}function ht(u,t){o(u),o(t),c._ZN12wasm_bindgen7convert8closures1_6invoke17h790c723772977d15E(u,t)}function wt(u,t){o(u),o(t),c._ZN12wasm_bindgen7convert8closures1_6invoke17h59cad6d2488dca29E(u,t)}function mt(u,t){o(u),o(t),c._ZN12wasm_bindgen7convert8closures1_6invoke17h9761498151360b23E(u,t)}function pt(u,t){o(u),o(t),c._ZN12wasm_bindgen7convert8closures1_6invoke17h8e4f100a6c778e58E(u,t)}function yt(u,t,e){o(u),o(t),c._ZN12wasm_bindgen7convert8closures1_6invoke17h7dd8c6f9e9c12966E(u,t,e)}function vt(u,t,e){o(u),o(t),c._ZN12wasm_bindgen7convert8closures1_6invoke17hd9e6853fc436a5f1E(u,t,e)}function kt(u,t,e){o(u),o(t),c._ZN12wasm_bindgen7convert8closures1_1_6invoke17h3dab76294ffea566E(u,t,e)}function Et(u,t,e){o(u),o(t);let n=c._ZN12wasm_bindgen7convert8closures1_6invoke17hceaf1cd31a005417E(u,t,e);if(n[1])throw Ft(n[0])}function It(u,t,e,n){o(u),o(t),c._ZN12wasm_bindgen7convert8closures1_6invoke17h04eb02ab906308ebE(u,t,e,n)}var At=["bytes"],xt=["default","no-store","reload","no-cache","force-cache","only-if-cached"],Tt=["omit","same-origin","include"],St=["same-origin","no-cors","cors","navigate"],ut=["auto","instant","smooth"],it=["start","center","end","nearest"],Nt=["auto","manual"],Rt=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(u=>c.__wbg_intounderlyingbytesource_free(u,1)),Ot=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(u=>c.__wbg_intounderlyingsink_free(u,1)),Ct=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(u=>c.__wbg_intounderlyingsource_free(u,1)),ct=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(u=>c.__wbg_jsowner_free(u,1));function m(u){let t=c.__externref_table_alloc();return c.__wbindgen_externrefs.set(t,u),t}function Lt(u){if(typeof u!="bigint")throw new Error(`expected a bigint argument, found ${typeof u}`)}function b(u){if(typeof u!="boolean")throw new Error(`expected a boolean argument, found ${typeof u}`)}function o(u){if(typeof u!="number")throw new Error(`expected a number argument, found ${typeof u}`)}var X=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(u=>c.__wbindgen_destroy_closure(u.a,u.b));function Q(u){let t=typeof u;if(t=="number"||t=="boolean"||u==null)return`${u}`;if(t=="string")return`"${u}"`;if(t=="symbol"){let r=u.description;return r==null?"Symbol":`Symbol(${r})`}if(t=="function"){let r=u.name;return typeof r=="string"&&r.length>0?`Function(${r})`:"Function"}if(Array.isArray(u)){let r=u.length,i="[";r>0&&(i+=Q(u[0]));for(let a=1;a1)n=e[1];else return toString.call(u);if(n=="Object")try{return"Object("+JSON.stringify(u)+")"}catch{return"Object"}return u instanceof Error?`${u.name}: ${u.message} -${u.stack}`:n}function zt(u,t){u=u>>>0;let e=_(),n=[];for(let r=u;r>>0,O().subarray(u/1,u/1+t)}var E=null;function _(){return(E===null||E.buffer.detached===!0||E.buffer.detached===void 0&&E.buffer!==c.memory.buffer)&&(E=new DataView(c.memory.buffer)),E}function l(u,t){return jt(u>>>0,t)}var R=null;function O(){return(R===null||R.byteLength===0)&&(R=new Uint8Array(c.memory.buffer)),R}function f(u,t){try{return u.apply(this,t)}catch(e){let n=m(e);c.__wbindgen_exn_store(n)}}function g(u){return u==null}function s(u,t){try{return u.apply(this,t)}catch(e){let n=(function(){try{return e instanceof Error?`${e.message} +function lt(u,t,e,n){if(n==="style"){u.style.setProperty(t,e);return}if(n){u.setAttributeNS(n,t,e);return}switch(t){case"value":u.tagName==="OPTION"?Y(u,t,e):u.value!==e&&(u.value=e);break;case"initial_value":u.defaultValue=e;break;case"checked":u.checked=S(e);break;case"initial_checked":u.defaultChecked=S(e);break;case"selected":u.selected=S(e);break;case"initial_selected":u.defaultSelected=S(e);break;case"dangerous_inner_html":u.innerHTML=e;break;case"style":let r={};for(let i=0;i{for(let n of e)this.handleResizeEvent(n)})),this.resizeObserver.observe(t)}removeResizeObserver(t){this.resizeObserver&&this.resizeObserver.unobserve(t)}handleIntersectionEvent(t){let e=t.target,n=new CustomEvent("visible",{bubbles:!1,detail:t});e.dispatchEvent(n)}createIntersectionObserver(t){this.intersectionObserver||(this.intersectionObserver=new IntersectionObserver(e=>{for(let n of e)this.handleIntersectionEvent(n)})),this.intersectionObserver.observe(t)}removeIntersectionObserver(t){this.intersectionObserver&&this.intersectionObserver.unobserve(t)}createListener(t,e,n){if(t=="resize"?this.createResizeObserver(e):t=="visible"&&this.createIntersectionObserver(e),n)this.global[t]===void 0?(this.global[t]={active:1,callback:this.handler},this.root.addEventListener(t,this.handler)):this.global[t].active++;else{let r=e.getAttribute("data-dioxus-id");this.local[r]||(this.local[r]={}),e.addEventListener(t,this.handler)}}removeListener(t,e,n){e=="resize"?this.removeResizeObserver(t):e=="visible"?this.removeIntersectionObserver(t):n?this.removeBubblingListener(e):this.removeNonBubblingListener(t,e)}removeBubblingListener(t){this.global[t].active--,this.global[t].active===0&&(this.root.removeEventListener(t,this.global[t].callback),delete this.global[t])}removeNonBubblingListener(t,e){let n=t.getAttribute("data-dioxus-id");delete this.local[n][e],Object.keys(this.local[n]).length===0&&delete this.local[n],t.removeEventListener(e,this.handler)}removeAllNonBubblingListeners(t){let e=t.getAttribute("data-dioxus-id");delete this.local[e]}getNode(t){return this.nodes[t]}pushRoot(t){this.stack.push(t)}appendChildren(t,e){let n=this.nodes[t],r=this.stack.splice(this.stack.length-e);for(let i=0;i0;i--)n=n.nextSibling}return n}saveTemplate(t,e){this.templates[e]=t}hydrate_node(t,e){let n=t.getAttribute("data-node-hydration").split(","),r=e[parseInt(n[0])];if(this.nodes[r]=t,n.length>1){t.listening=n.length-1,t.setAttribute("data-dioxus-id",r.toString());for(let i=1;ii.nextNode()?i.currentNode!==f:!1;for(;i.currentNode;){let p=i.currentNode;if(p.nodeType===Node.COMMENT_NODE){let y=p.textContent,A=y.split("placeholder");if(A.length>1){if(this.nodes[t[parseInt(A[1])]]=p,!w())break;continue}let et=y.split("node-id");if(et.length>1){let x=p.nextSibling;p.remove();let z,B;if(x.nodeType===Node.COMMENT_NODE){let bt=x.parentElement.insertBefore(document.createTextNode(""),x);z=x,B=bt}else B=x,z=B.nextSibling;i.currentNode=z,this.nodes[t[parseInt(et[1])]]=B;let ft=p===r||!w();if(z.remove(),ft)break;continue}}if(!w())break}}}setAttributeInner(t,e,n,r){lt(t,e,n,r)}};var I,T,v,M,F,U=class extends Z{constructor(t){super(),this.d=t,this.m=null,this.p=null,this.ls=null,this.t=null,this.op=null,this.e=null,this.z=null,this.metaflags=null,this.u16buf=null,this.u16bufp=null,this.u32buf=null,this.u32bufp=null,this.u8buf=null,this.u8bufp=null,this.attr=[],this.attr_cache_hit=null,this.attr_cache_idx,this.get_attr=function(){return this.attr_cache_idx=this.u8buf[this.u8bufp++],this.attr_cache_idx&128?(this.attr_cache_hit=this.s.substring(this.sp,this.sp+=this.u8buf[this.u8bufp++]),this.attr[this.attr_cache_idx&4294967167]=this.attr_cache_hit,this.attr_cache_hit):this.attr[this.attr_cache_idx&4294967167]},this.el=[],this.el_cache_hit=null,this.el_cache_idx,this.get_el=function(){return this.el_cache_idx=this.u8buf[this.u8bufp++],this.el_cache_idx&128?(this.el_cache_hit=this.s.substring(this.sp,this.sp+=this.u8buf[this.u8bufp++]),this.el[this.el_cache_idx&4294967167]=this.el_cache_hit,this.el_cache_hit):this.el[this.el_cache_idx&4294967167]},this.evt=[],this.evt_cache_hit=null,this.evt_cache_idx,this.get_evt=function(){return this.evt_cache_idx=this.u8buf[this.u8bufp++],this.evt_cache_idx&128?(this.evt_cache_hit=this.s.substring(this.sp,this.sp+=this.u8buf[this.u8bufp++]),this.evt[this.evt_cache_idx&4294967167]=this.evt_cache_hit,this.evt_cache_hit):this.evt[this.evt_cache_idx&4294967167]},this.namespace=[],this.namespace_cache_hit=null,this.namespace_cache_idx,this.get_namespace=function(){return this.namespace_cache_idx=this.u8buf[this.u8bufp++],this.namespace_cache_idx&128?(this.namespace_cache_hit=this.s.substring(this.sp,this.sp+=this.u8buf[this.u8bufp++]),this.namespace[this.namespace_cache_idx&4294967167]=this.namespace_cache_hit,this.namespace_cache_hit):this.namespace[this.namespace_cache_idx&4294967167]},this.ns_cache=[],this.ns_cache_cache_hit=null,this.ns_cache_cache_idx,this.get_ns_cache=function(){return this.ns_cache_cache_idx=this.u8buf[this.u8bufp++],this.ns_cache_cache_idx&128?(this.ns_cache_cache_hit=this.s.substring(this.sp,this.sp+=this.u8buf[this.u8bufp++]),this.ns_cache[this.ns_cache_cache_idx&4294967167]=this.ns_cache_cache_hit,this.ns_cache_cache_hit):this.ns_cache[this.ns_cache_cache_idx&4294967167]},this.s="",this.lsp=null,this.sp=null,this.sl=null,this.c=new TextDecoder}update_memory(t){this.m=new DataView(t.buffer)}run(){if(this.metaflags=this.m.getUint32(this.d,!0),this.metaflags>>>6&1&&(this.ls=this.m.getUint32(this.d+24,!0)),this.p=this.ls,this.metaflags>>>4&1&&(this.t=this.m.getUint32(this.d+16,!0),this.u16buf=new Uint16Array(this.m.buffer,this.t,(this.m.buffer.byteLength-this.t-(this.m.buffer.byteLength-this.t)%2)/2)),this.u16bufp=0,this.metaflags>>>3&1&&(this.t=this.m.getUint32(this.d+12,!0),this.u32buf=new Uint32Array(this.m.buffer,this.t,(this.m.buffer.byteLength-this.t-(this.m.buffer.byteLength-this.t)%4)/4)),this.u32bufp=0,this.metaflags>>>5&1&&(this.t=this.m.getUint32(this.d+20,!0),this.u8buf=new Uint8Array(this.m.buffer,this.t,(this.m.buffer.byteLength-this.t-(this.m.buffer.byteLength-this.t)%1)/1)),this.u8bufp=0,this.metaflags&1&&(this.lsp=this.m.getUint32(this.d+4,!0)),this.metaflags>>>2&1)if(this.sl=this.m.getUint32(this.d+8,!0),this.metaflags>>>1&1){for(this.sp=this.lsp,this.s="",this.e=this.sp+(this.sl/4|0)*4;this.sp>8,(this.t&16711680)>>16,this.t>>24),this.sp+=4;for(;this.sp{this.handler(r,n,I)});break;case 25:this.nodes[this.u32buf[this.u32bufp++]]=this.loadChild((()=>{this.e=this.u8bufp+this.u32buf[this.u32bufp++];let r=this.u8buf.slice(this.u8bufp,this.e);return this.u8bufp=this.e,r})());break;case 26:{let r=this.stack.splice(this.stack.length-this.u16buf[this.u16bufp++]);this.loadChild((()=>{this.e=this.u8bufp+this.u32buf[this.u32bufp++];let f=this.u8buf.slice(this.u8bufp,this.e);return this.u8bufp=this.e,f})()).replaceWith(...r)}break;case 27:return!0}this.op>>>=8}}run_from_bytes(t){this.d=0,this.update_memory(new Uint8Array(t)),this.run()}};function nt(u,t,e,n){if(n==="style"){u.style.setProperty(t,e);return}if(n){u.setAttributeNS(n,t,e);return}switch(t){case"value":u.tagName==="OPTION"?V(u,t,e):u.value!==e&&(u.value=e);break;case"initial_value":u.defaultValue=e;break;case"checked":u.checked=N(e);break;case"initial_checked":u.defaultChecked=N(e);break;case"selected":u.selected=N(e);break;case"initial_selected":u.defaultSelected=N(e);break;case"dangerous_inner_html":u.innerHTML=e;break;case"style":let r={};for(let i=0;i0){this.waiting.shift()(t);return}this.pending.push(t)}async recv(){return new Promise((t,e)=>{if(this.pending.length>0){t(this.pending.shift());return}this.waiting.push(t)})}},D=class{inner;constructor(t){this.inner=new WeakRef(t)}rustSend(t){let e=this.inner.deref();e&&e.rustSend(t)}async rustRecv(){let t=this.inner.deref();if(t)return await t.rustRecv()}},$=class{weak(){return new D(this)}};globalThis.__nextChannelId=0;globalThis.__channels=[];var W=class extends ${js_to_rust;rust_to_js;owner;id;constructor(t){super(),this.owner=t,this.js_to_rust=new j,this.rust_to_js=new j,this.id=globalThis.__nextChannelId,globalThis.__channels[this.id]=this,globalThis.__nextChannelId+=1}weak(){return new D(this)}async recv(){return await this.rust_to_js.recv()}send(t){this.js_to_rust.send(t)}rustSend(t){this.rust_to_js.send(t)}async rustRecv(){return await this.js_to_rust.recv()}close(){globalThis.__channels[this.id]=null}};function st(){return window.__PROBING_BASE_PATH__||""}var K=class{constructor(){throw new Error("cannot invoke `new` directly")}__destroy_into_raw(){let t=this.__wbg_ptr;return this.__wbg_ptr=0,Rt.unregister(this),t}free(){let t=this.__destroy_into_raw();c.__wbg_intounderlyingbytesource_free(t,0)}get autoAllocateChunkSize(){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");return o(this.__wbg_ptr),c.intounderlyingbytesource_autoAllocateChunkSize(this.__wbg_ptr)>>>0}cancel(){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");let t=this.__destroy_into_raw();o(t),c.intounderlyingbytesource_cancel(t)}pull(t){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");return o(this.__wbg_ptr),c.intounderlyingbytesource_pull(this.__wbg_ptr,t)}start(t){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");o(this.__wbg_ptr),c.intounderlyingbytesource_start(this.__wbg_ptr,t)}get type(){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");o(this.__wbg_ptr);let t=c.intounderlyingbytesource_type(this.__wbg_ptr);return At[t]}};Symbol.dispose&&(K.prototype[Symbol.dispose]=K.prototype.free);var q=class{constructor(){throw new Error("cannot invoke `new` directly")}__destroy_into_raw(){let t=this.__wbg_ptr;return this.__wbg_ptr=0,Ot.unregister(this),t}free(){let t=this.__destroy_into_raw();c.__wbg_intounderlyingsink_free(t,0)}abort(t){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");let e=this.__destroy_into_raw();return o(e),c.intounderlyingsink_abort(e,t)}close(){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");let t=this.__destroy_into_raw();return o(t),c.intounderlyingsink_close(t)}write(t){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");return o(this.__wbg_ptr),c.intounderlyingsink_write(this.__wbg_ptr,t)}};Symbol.dispose&&(q.prototype[Symbol.dispose]=q.prototype.free);var H=class{constructor(){throw new Error("cannot invoke `new` directly")}__destroy_into_raw(){let t=this.__wbg_ptr;return this.__wbg_ptr=0,Ct.unregister(this),t}free(){let t=this.__destroy_into_raw();c.__wbg_intounderlyingsource_free(t,0)}cancel(){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");let t=this.__destroy_into_raw();o(t),c.intounderlyingsource_cancel(t)}pull(t){if(this.__wbg_ptr==0)throw new Error("Attempt to use a moved value");return o(this.__wbg_ptr),c.intounderlyingsource_pull(this.__wbg_ptr,t)}};Symbol.dispose&&(H.prototype[Symbol.dispose]=H.prototype.free);var L=class u{constructor(){throw new Error("cannot invoke `new` directly")}static __wrap(t){let e=Object.create(u.prototype);return e.__wbg_ptr=t,ct.register(e,e.__wbg_ptr,e),e}__destroy_into_raw(){let t=this.__wbg_ptr;return this.__wbg_ptr=0,ct.unregister(this),t}free(){let t=this.__destroy_into_raw();c.__wbg_jsowner_free(t,0)}};Symbol.dispose&&(L.prototype[Symbol.dispose]=L.prototype.free);function tt(){return{__proto__:null,"./web_bg.js":{__proto__:null,__wbg_Error_92b29b0548f8b746:function(){return s(function(t,e){return Error(l(t,e))},arguments)},__wbg_String_8564e559799eccda:function(){return s(function(t,e){let n=String(e),r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg___wbindgen_bigint_get_as_i64_d968e41184ae354f:function(t,e){let n=e,r=typeof n=="bigint"?n:void 0;g(r)||Lt(r),_().setBigInt64(t+8,g(r)?BigInt(0):r,!0),_().setInt32(t+0,!g(r),!0)},__wbg___wbindgen_boolean_get_fa956cfa2d1bd751:function(t){let e=t,n=typeof e=="boolean"?e:void 0;return g(n)||b(n),g(n)?16777215:n?1:0},__wbg___wbindgen_debug_string_c25d447a39f5578f:function(t,e){let n=Q(e),r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},__wbg___wbindgen_in_aca499c5de7ff5e5:function(t,e){let n=t in e;return b(n),n},__wbg___wbindgen_is_bigint_2f76dc55065b4273:function(t){let e=typeof t=="bigint";return b(e),e},__wbg___wbindgen_is_function_1ff95bcc5517c252:function(t){let e=typeof t=="function";return b(e),e},__wbg___wbindgen_is_object_a27215656b807791:function(t){let e=t,n=typeof e=="object"&&e!==null;return b(n),n},__wbg___wbindgen_is_string_ea5e6cc2e4141dfe:function(t){let e=typeof t=="string";return b(e),e},__wbg___wbindgen_is_undefined_c05833b95a3cf397:function(t){let e=t===void 0;return b(e),e},__wbg___wbindgen_jsval_eq_e659fcf7b0e32763:function(t,e){let n=t===e;return b(n),n},__wbg___wbindgen_jsval_loose_eq_db4c3b15f63fc170:function(t,e){let n=t==e;return b(n),n},__wbg___wbindgen_memory_de265df8aadd6273:function(){return c.memory},__wbg___wbindgen_number_get_394265ed1e1b84ee:function(t,e){let n=e,r=typeof n=="number"?n:void 0;g(r)||o(r),_().setFloat64(t+8,g(r)?0:r,!0),_().setInt32(t+0,!g(r),!0)},__wbg___wbindgen_string_get_b0ca35b86a603356:function(t,e){let n=e,r=typeof n=="string"?n:void 0;var i=g(r)?0:h(r,c.__wbindgen_malloc,c.__wbindgen_realloc),f=d;_().setInt32(t+4,f,!0),_().setInt32(t+0,i,!0)},__wbg___wbindgen_throw_344f42d3211c4765:function(t,e){throw new Error(l(t,e))},__wbg__wbg_cb_unref_fffb441def202758:function(){return s(function(t){t._wbg_cb_unref()},arguments)},__wbg_abort_8bae0f33e7833997:function(){return s(function(t){t.abort()},arguments)},__wbg_abort_eee9248a6d680839:function(){return s(function(t,e){t.abort(e)},arguments)},__wbg_activeElement_4bc99dc1a7094c27:function(){return s(function(t){let e=t.activeElement;return g(e)?0:m(e)},arguments)},__wbg_addEventListener_d85450ee1320c989:function(){return a(function(t,e,n,r){t.addEventListener(l(e,n),r)},arguments)},__wbg_altKey_50f830d1793a2eea:function(){return s(function(t){let e=t.altKey;return b(e),e},arguments)},__wbg_altKey_c5e44fde6beb66ef:function(){return s(function(t){let e=t.altKey;return b(e),e},arguments)},__wbg_altKey_f3e24c4c9cfcf271:function(){return s(function(t){let e=t.altKey;return b(e),e},arguments)},__wbg_animationName_e80680fbfd3da8a2:function(){return s(function(t,e){let n=e.animationName,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_appendChild_f553e8704c4f14a6:function(){return a(function(t,e){return t.appendChild(e)},arguments)},__wbg_append_01c74e5c6b58aa64:function(){return a(function(t,e,n,r,i){t.append(l(e,n),l(r,i))},arguments)},__wbg_append_58377ae3be2fb5ef:function(){return a(function(t,e,n,r,i,f){t.append(l(e,n),r,l(i,f))},arguments)},__wbg_append_8e24caa53c80c631:function(){return a(function(t,e,n,r,i){t.append(l(e,n),l(r,i))},arguments)},__wbg_append_91733ec40ee3b1f9:function(){return a(function(t,e,n,r){t.append(l(e,n),r)},arguments)},__wbg_arrayBuffer_3b637f0fa65c5351:function(){return a(function(t){return t.arrayBuffer()},arguments)},__wbg_arrayBuffer_a158e423a87ee756:function(){return s(function(t){return t.arrayBuffer()},arguments)},__wbg_back_939cbdbdfad8aff7:function(){return a(function(t){t.back()},arguments)},__wbg_blockSize_5af477b962b2b031:function(){return s(function(t){return t.blockSize},arguments)},__wbg_blur_e902dcc79406e89c:function(){return a(function(t){t.blur()},arguments)},__wbg_body_40ec34e0a2931fe8:function(){return s(function(t){let e=t.body;return g(e)?0:m(e)},arguments)},__wbg_borderBoxSize_ff7f5405dcc6554e:function(){return s(function(t){return t.borderBoxSize},arguments)},__wbg_boundingClientRect_0776888095b16b8c:function(){return s(function(t){return t.boundingClientRect},arguments)},__wbg_bubbles_07bec919f30033ab:function(){return s(function(t){let e=t.bubbles;return b(e),e},arguments)},__wbg_buffer_54b87055582c8a81:function(){return s(function(t){return t.buffer},arguments)},__wbg_button_f6a9a7b725f1838e:function(){return s(function(t){let e=t.button;return o(e),e},arguments)},__wbg_buttons_d8acd46cf8f40ae9:function(){return s(function(t){let e=t.buttons;return o(e),e},arguments)},__wbg_byobRequest_06b654bb15590436:function(){return s(function(t){let e=t.byobRequest;return g(e)?0:m(e)},arguments)},__wbg_byteLength_41862ca4020b9c43:function(){return s(function(t){let e=t.byteLength;return o(e),e},arguments)},__wbg_byteOffset_d42e18c4441f628b:function(){return s(function(t){let e=t.byteOffset;return o(e),e},arguments)},__wbg_call_8a2dd23819f8a60a:function(){return a(function(t,e){return t.call(e)},arguments)},__wbg_call_a6e5c5dce5018821:function(){return a(function(t,e,n){return t.call(e,n)},arguments)},__wbg_changedTouches_dbf6eeabddd3c2da:function(){return s(function(t){return t.changedTouches},arguments)},__wbg_charCodeAt_2a30bc7c17474cc6:function(){return s(function(t,e){return t.charCodeAt(e>>>0)},arguments)},__wbg_checkValidity_3a31dcce278f31a1:function(){return s(function(t){let e=t.checkValidity();return b(e),e},arguments)},__wbg_checked_596d0d7b35f55a01:function(){return s(function(t){let e=t.checked;return b(e),e},arguments)},__wbg_clearData_1297d08581746c08:function(){return a(function(t,e,n){t.clearData(l(e,n))},arguments)},__wbg_clearData_a7a19d854ec1a3b7:function(){return a(function(t){t.clearData()},arguments)},__wbg_clearInterval_16e8cbbce92291d0:function(){return s(function(t){return clearInterval(t)},arguments)},__wbg_clearTimeout_113b1cde814ec762:function(){return s(function(t){return clearTimeout(t)},arguments)},__wbg_clearTimeout_333bba87532ab9d3:function(){return s(function(t){return clearTimeout(t)},arguments)},__wbg_clearTimeout_6b8d9a38b9263d65:function(){return s(function(t){return clearTimeout(t)},arguments)},__wbg_clientHeight_994541cde34d3ca0:function(){return s(function(t){let e=t.clientHeight;return o(e),e},arguments)},__wbg_clientWidth_6852617da948be39:function(){return s(function(t){let e=t.clientWidth;return o(e),e},arguments)},__wbg_clientX_a7dcb4081126cd4b:function(){return s(function(t){let e=t.clientX;return o(e),e},arguments)},__wbg_clientX_c396b0fb11d601d3:function(){return s(function(t){let e=t.clientX;return o(e),e},arguments)},__wbg_clientY_a4650836fdf58f01:function(){return s(function(t){let e=t.clientY;return o(e),e},arguments)},__wbg_clientY_c0560910b20ee192:function(){return s(function(t){let e=t.clientY;return o(e),e},arguments)},__wbg_close_249a23304523681b:function(){return a(function(t){t.close()},arguments)},__wbg_close_72d318d9c16e83ef:function(){return a(function(t){t.close()},arguments)},__wbg_code_89c999e407c79eef:function(){return s(function(t,e){let n=e.code,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_contentBoxSize_74fbbc51859ff90e:function(){return s(function(t){return t.contentBoxSize},arguments)},__wbg_createComment_003419d0740789d4:function(){return s(function(t,e,n){return t.createComment(l(e,n))},arguments)},__wbg_createElementNS_013b3fb26f4796ec:function(){return a(function(t,e,n,r,i){return t.createElementNS(e===0?void 0:l(e,n),l(r,i))},arguments)},__wbg_createElement_fcbc0805de826d62:function(){return a(function(t,e,n){return t.createElement(l(e,n))},arguments)},__wbg_createObjectURL_416e527781e6fd6d:function(){return a(function(t,e){let n=URL.createObjectURL(e),r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_createTextNode_4dad5b18435dda7c:function(){return s(function(t,e,n){return t.createTextNode(l(e,n))},arguments)},__wbg_ctrlKey_2e52816fa7160097:function(){return s(function(t){let e=t.ctrlKey;return b(e),e},arguments)},__wbg_ctrlKey_50bd8324959ca786:function(){return s(function(t){let e=t.ctrlKey;return b(e),e},arguments)},__wbg_ctrlKey_57171169eab54da6:function(){return s(function(t){let e=t.ctrlKey;return b(e),e},arguments)},__wbg_dataTransfer_c1c4745cee7e05f1:function(){return s(function(t){let e=t.dataTransfer;return g(e)?0:m(e)},arguments)},__wbg_data_f994b1bb75d8337a:function(){return s(function(t,e){let n=e.data;var r=g(n)?0:h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_deltaMode_d869228efd74f393:function(){return s(function(t){let e=t.deltaMode;return o(e),e},arguments)},__wbg_deltaX_5d829ffba565ed10:function(){return s(function(t){return t.deltaX},arguments)},__wbg_deltaY_6cfce8f8da250c23:function(){return s(function(t){return t.deltaY},arguments)},__wbg_deltaZ_42c86f225c34aa04:function(){return s(function(t){return t.deltaZ},arguments)},__wbg_detail_a90dcd774780ebf6:function(){return s(function(t){return t.detail},arguments)},__wbg_documentElement_b7ec99417969bfbc:function(){return s(function(t){let e=t.documentElement;return g(e)?0:m(e)},arguments)},__wbg_document_179650d6cb13c263:function(){return s(function(t){let e=t.document;return g(e)?0:m(e)},arguments)},__wbg_done_89b2b13e91a60321:function(){return s(function(t){let e=t.done;return b(e),e},arguments)},__wbg_dropEffect_8187d3b019f3e6bd:function(){return s(function(t,e){let n=e.dropEffect,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_effectAllowed_ca2550f3a73fb833:function(){return s(function(t,e){let n=e.effectAllowed,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_elapsedTime_0330f570ff694c6f:function(){return s(function(t){return t.elapsedTime},arguments)},__wbg_elapsedTime_4c2a1fd1473438d6:function(){return s(function(t){return t.elapsedTime},arguments)},__wbg_enqueue_6d83b4c6281bafd6:function(){return a(function(t,e){t.enqueue(e)},arguments)},__wbg_entries_015dc610cd81ede0:function(){return s(function(t){return Object.entries(t)},arguments)},__wbg_entries_8ddbe5d352d85237:function(){return s(function(t){return t.entries()},arguments)},__wbg_entries_900cefd6f70eb290:function(){return s(function(t){return t.entries()},arguments)},__wbg_error_744744ff0c9861e6:function(){return s(function(t){console.error(t)},arguments)},__wbg_fetch_074561c3e313c86f:function(){return s(function(t){return fetch(t)},arguments)},__wbg_fetch_9dad4fe911207b37:function(){return s(function(t){return fetch(t)},arguments)},__wbg_fetch_b5951fc96f52f786:function(){return s(function(t,e){return t.fetch(e)},arguments)},__wbg_files_116196bc012ac3c8:function(){return s(function(t){let e=t.files;return g(e)?0:m(e)},arguments)},__wbg_files_a4eb87e5e4343c46:function(){return s(function(t){let e=t.files;return g(e)?0:m(e)},arguments)},__wbg_focus_2f77051f98540625:function(){return a(function(t){t.focus()},arguments)},__wbg_force_368c1897f399d783:function(){return s(function(t){return t.force},arguments)},__wbg_forward_4bb54c7f45451c64:function(){return a(function(t){t.forward()},arguments)},__wbg_getAsFile_adead4fd4f4ce592:function(){return a(function(t){let e=t.getAsFile();return g(e)?0:m(e)},arguments)},__wbg_getAttribute_5a601ba4718b922a:function(){return s(function(t,e,n,r){let i=e.getAttribute(l(n,r));var f=g(i)?0:h(i,c.__wbindgen_malloc,c.__wbindgen_realloc),w=d;_().setInt32(t+4,w,!0),_().setInt32(t+0,f,!0)},arguments)},__wbg_getBoundingClientRect_e828e6c31c66dea6:function(){return s(function(t){return t.getBoundingClientRect()},arguments)},__wbg_getData_fcb88fae21d94f1e:function(){return a(function(t,e,n,r){let i=e.getData(l(n,r)),f=h(i,c.__wbindgen_malloc,c.__wbindgen_realloc),w=d;_().setInt32(t+4,w,!0),_().setInt32(t+0,f,!0)},arguments)},__wbg_getElementById_1cbd8f06dbe8eb8e:function(){return s(function(t,e,n){let r=t.getElementById(l(e,n));return g(r)?0:m(r)},arguments)},__wbg_getHours_9f6561095682ce51:function(){return s(function(t){let e=t.getHours();return o(e),e},arguments)},__wbg_getItem_b96269ddc16cf24a:function(){return a(function(t,e,n,r){let i=e.getItem(l(n,r));var f=g(i)?0:h(i,c.__wbindgen_malloc,c.__wbindgen_realloc),w=d;_().setInt32(t+4,w,!0),_().setInt32(t+0,f,!0)},arguments)},__wbg_getMinutes_b0d5cd90bf9b8f22:function(){return s(function(t){let e=t.getMinutes();return o(e),e},arguments)},__wbg_getNode_2f3b1f608db7c9d0:function(){return s(function(t,e){return t.getNode(e>>>0)},arguments)},__wbg_getSeconds_40c565b3a6cb05fe:function(){return s(function(t){let e=t.getSeconds();return o(e),e},arguments)},__wbg_get_507a50627bffa49b:function(){return s(function(t,e){return t[e>>>0]},arguments)},__wbg_get_757c867e2520bbc4:function(){return s(function(t,e){let n=t[e>>>0];return g(n)?0:m(n)},arguments)},__wbg_get_78f252d074a84d0b:function(){return a(function(t,e){return Reflect.get(t,e)},arguments)},__wbg_get_base_path_39628b0b6ddfa96a:function(){return s(function(t){let e=st(),n=h(e,c.__wbindgen_malloc,c.__wbindgen_realloc),r=d;_().setInt32(t+4,r,!0),_().setInt32(t+0,n,!0)},arguments)},__wbg_get_c7eb1f358a7654df:function(){return a(function(t,e){return Reflect.get(t,e)},arguments)},__wbg_get_e73985d6689d2245:function(){return s(function(t,e){let n=t[e>>>0];return g(n)?0:m(n)},arguments)},__wbg_get_select_data_60af93fcbe2f391c:function(){return s(function(t,e){let n=rt(e),r=Mt(n,c.__wbindgen_malloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_get_unchecked_6e0ad6d2a41b06f6:function(){return s(function(t,e){return t[e>>>0]},arguments)},__wbg_has_8374cf06984d8bfc:function(){return a(function(t,e){let n=Reflect.has(t,e);return b(n),n},arguments)},__wbg_hash_508149c4291ec8c2:function(){return a(function(t,e){let n=e.hash,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_head_41a60f9034e0b41a:function(){return s(function(t){let e=t.head;return g(e)?0:m(e)},arguments)},__wbg_headers_cf9c80f30e2a4eff:function(){return s(function(t){return t.headers},arguments)},__wbg_height_6f29ab40ae50636d:function(){return s(function(t){let e=t.height;return o(e),e},arguments)},__wbg_height_96c07d9559d0200a:function(){return s(function(t){return t.height},arguments)},__wbg_height_9f27216001e3c804:function(){return s(function(t){return t.height},arguments)},__wbg_hidden_c08eb1c29c138ab0:function(){return s(function(t){let e=t.hidden;return b(e),e},arguments)},__wbg_history_e648b4314d9b256e:function(){return a(function(t){return t.history},arguments)},__wbg_identifier_d30bb260fab6b02a:function(){return s(function(t){let e=t.identifier;return o(e),e},arguments)},__wbg_initialize_169e37fbdd472b20:function(){return s(function(t,e,n){t.initialize(e,n)},arguments)},__wbg_inlineSize_3c8412828bef21eb:function(){return s(function(t){return t.inlineSize},arguments)},__wbg_instanceof_AnimationEvent_3a83c3d21fbd4d01:function(){return s(function(t){let e;try{e=t instanceof AnimationEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_ArrayBuffer_4480b9e0068a8adb:function(){return s(function(t){let e;try{e=t instanceof ArrayBuffer}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Blob_c6523f92a32c8695:function(){return s(function(t){let e;try{e=t instanceof Blob}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_CompositionEvent_6fef075df3b5dbf4:function(){return s(function(t){let e;try{e=t instanceof CompositionEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_CustomEvent_9b848ed45794fd3e:function(){return s(function(t){let e;try{e=t instanceof CustomEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Document_d1955f84f5d0351c:function(){return s(function(t){let e;try{e=t instanceof Document}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_DragEvent_7bd2cb4c087838f2:function(){return s(function(t){let e;try{e=t instanceof DragEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Element_beebfaab75d12d9d:function(){return s(function(t){let e;try{e=t instanceof Element}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Event_512f3841fa744d1e:function(){return s(function(t){let e;try{e=t instanceof Event}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_File_ee62de53bca2e697:function(){return s(function(t){let e;try{e=t instanceof File}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_FocusEvent_cadb56dad3dfd4ac:function(){return s(function(t){let e;try{e=t instanceof FocusEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_HtmlElement_4493a09212d3586f:function(){return s(function(t){let e;try{e=t instanceof HTMLElement}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_HtmlFormElement_ebf2bd35b418e93e:function(){return s(function(t){let e;try{e=t instanceof HTMLFormElement}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_HtmlInputElement_ad3be04339d0e4df:function(){return s(function(t){let e;try{e=t instanceof HTMLInputElement}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_HtmlSelectElement_b4698f847dc49da5:function(){return s(function(t){let e;try{e=t instanceof HTMLSelectElement}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_HtmlTextAreaElement_37795f65e16b7ed0:function(){return s(function(t){let e;try{e=t instanceof HTMLTextAreaElement}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_KeyboardEvent_be49f2d8e15d587a:function(){return s(function(t){let e;try{e=t instanceof KeyboardEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Map_e5b5e3db98422fcc:function(){return s(function(t){let e;try{e=t instanceof Map}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_MouseEvent_89eddfc6203c1749:function(){return s(function(t){let e;try{e=t instanceof MouseEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Node_d29e7ded486fd76a:function(){return s(function(t){let e;try{e=t instanceof Node}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_PointerEvent_8ef1feb51407c0ed:function(){return s(function(t){let e;try{e=t instanceof PointerEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Response_c8b64b2256f01bec:function(){return s(function(t){let e;try{e=t instanceof Response}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_TouchEvent_62e9e212135a784b:function(){return s(function(t){let e;try{e=t instanceof TouchEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_TransitionEvent_a1842850468877e4:function(){return s(function(t){let e;try{e=t instanceof TransitionEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Uint8Array_309b927aaf7a3fc7:function(){return s(function(t){let e;try{e=t instanceof Uint8Array}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_WheelEvent_8a8f43ee9318fcd4:function(){return s(function(t){let e;try{e=t instanceof WheelEvent}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_instanceof_Window_05ba1ee4f6781663:function(){return s(function(t){let e;try{e=t instanceof Window}catch{e=!1}let n=e;return b(n),n},arguments)},__wbg_intersectionRatio_7c65292cc5ad712c:function(){return s(function(t){return t.intersectionRatio},arguments)},__wbg_intersectionRect_be1020a3be2ed245:function(){return s(function(t){return t.intersectionRect},arguments)},__wbg_isArray_0677c962b281d01a:function(){return s(function(t){let e=Array.isArray(t);return b(e),e},arguments)},__wbg_isComposing_919a0fdf6ac030c9:function(){return s(function(t){let e=t.isComposing;return b(e),e},arguments)},__wbg_isIntersecting_fc6d9529a49c5d62:function(){return s(function(t){let e=t.isIntersecting;return b(e),e},arguments)},__wbg_isPrimary_e59b27f91017e844:function(){return s(function(t){let e=t.isPrimary;return b(e),e},arguments)},__wbg_isSafeInteger_04f36e4056f1b851:function(){return s(function(t){let e=Number.isSafeInteger(t);return b(e),e},arguments)},__wbg_item_74998074fc497f92:function(){return s(function(t,e){let n=t.item(e>>>0);return g(n)?0:m(n)},arguments)},__wbg_items_350b6f2d566d3def:function(){return s(function(t){return t.items},arguments)},__wbg_iterator_6f722e4a93058b71:function(){return s(function(){return Symbol.iterator},arguments)},__wbg_key_803dca86cdcfa8dd:function(){return s(function(t,e){let n=e.key,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_kind_c494ca014c671a6f:function(){return s(function(t,e){let n=e.kind,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_lastModified_41250e8004d0f7ce:function(){return s(function(t){return t.lastModified},arguments)},__wbg_left_7e76a74d0db1754f:function(){return s(function(t){return t.left},arguments)},__wbg_length_02c64e687322fa34:function(){return s(function(t){let e=t.length;return o(e),e},arguments)},__wbg_length_1f0964f4a5e2c6d8:function(){return s(function(t){let e=t.length;return o(e),e},arguments)},__wbg_length_370319915dc99107:function(){return s(function(t){let e=t.length;return o(e),e},arguments)},__wbg_length_e08fc23135c66d6f:function(){return s(function(t){let e=t.length;return o(e),e},arguments)},__wbg_length_eea4bfa35e75c87c:function(){return s(function(t){let e=t.length;return o(e),e},arguments)},__wbg_length_ef21514bf74fe712:function(){return s(function(t){let e=t.length;return o(e),e},arguments)},__wbg_localStorage_5bf6ce3f8e51412a:function(){return a(function(t){let e=t.localStorage;return g(e)?0:m(e)},arguments)},__wbg_location_8f24df2c257fb974:function(){return s(function(t){let e=t.location;return o(e),e},arguments)},__wbg_location_c9a2271428996698:function(){return s(function(t){return t.location},arguments)},__wbg_log_0c201ade58bb55e1:function(){return s(function(t,e,n,r,i,f,w,p){let y,A;try{y=t,A=e,console.log(l(t,e),l(n,r),l(i,f),l(w,p))}finally{c.__wbindgen_free(y,A,1)}},arguments)},__wbg_log_ce2c4456b290c5e7:function(){return s(function(t,e){let n,r;try{n=t,r=e,console.log(l(t,e))}finally{c.__wbindgen_free(n,r,1)}},arguments)},__wbg_mark_b4d943f3bc2d2404:function(){return s(function(t,e){performance.mark(l(t,e))},arguments)},__wbg_measure_84362959e621a2c1:function(){return a(function(t,e,n,r){let i,f,w,p;try{i=t,f=e,w=n,p=r,performance.measure(l(t,e),l(n,r))}finally{c.__wbindgen_free(i,f,1),c.__wbindgen_free(w,p,1)}},arguments)},__wbg_metaKey_7a85debd51844822:function(){return s(function(t){let e=t.metaKey;return b(e),e},arguments)},__wbg_metaKey_d961c7572a9f84f5:function(){return s(function(t){let e=t.metaKey;return b(e),e},arguments)},__wbg_metaKey_f934f09e37889d70:function(){return s(function(t){let e=t.metaKey;return b(e),e},arguments)},__wbg_name_14e920dc23fffd96:function(){return s(function(t,e){let n=e.name,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_name_d7d79f5466e37447:function(){return s(function(t,e){let n=e.name,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_new_0912d735e8fbc1d3:function(){return a(function(){return new FormData},arguments)},__wbg_new_0_3da9e97f24fc69be:function(){return s(function(){return new Date},arguments)},__wbg_new_0d809930cd1354c6:function(){return a(function(){return new Headers},arguments)},__wbg_new_22598f2b091dadf2:function(){return s(function(t){return new W(L.__wrap(t))},arguments)},__wbg_new_26bdcffba762c064:function(){return s(function(t){return new U(t>>>0)},arguments)},__wbg_new_32b398fb48b6d94a:function(){return s(function(){return new Array},arguments)},__wbg_new_41e6f99b2fd20423:function(){return a(function(){return new FileReader},arguments)},__wbg_new_4339b2a2675a03e3:function(){return a(function(){return new AbortController},arguments)},__wbg_new_7796ffc7ed656783:function(){return s(function(){return new Map},arguments)},__wbg_new_9792ad3275d1dd31:function(){return a(function(){return new DataTransfer},arguments)},__wbg_new_b667d279fd5aa943:function(){return s(function(t,e){return new Error(l(t,e))},arguments)},__wbg_new_cd45aabdf6073e84:function(){return s(function(t){return new Uint8Array(t)},arguments)},__wbg_new_da52cf8fe3429cb2:function(){return s(function(){return new Object},arguments)},__wbg_new_from_slice_77cdfb7977362f3c:function(){return s(function(t,e){return new Uint8Array(J(t,e))},arguments)},__wbg_new_typed_1824d93f294193e5:function(){return s(function(t,e){try{var n={a:t,b:e},r=(f,w)=>{let p=n.a;n.a=0;try{return It(p,n.b,f,w)}finally{n.a=p}};return new Promise(r)}finally{n.a=0}},arguments)},__wbg_new_with_args_200d82645b6544eb:function(){return s(function(t,e,n,r){return new Function(l(t,e),l(n,r))},arguments)},__wbg_new_with_byte_offset_and_length_54c7724ee3ec7d82:function(){return s(function(t,e,n){return new Uint8Array(t,e>>>0,n>>>0)},arguments)},__wbg_new_with_form_e4ca634e481666c7:function(){return a(function(t){return new FormData(t)},arguments)},__wbg_new_with_str_and_init_d95cbe11ce28e65e:function(){return a(function(t,e,n){return new Request(l(t,e),n)},arguments)},__wbg_new_with_str_sequence_and_options_9db076dc44ddbeb0:function(){return a(function(t,e){return new Blob(t,e)},arguments)},__wbg_new_with_u8_array_sequence_and_options_2c1900e5a5c93850:function(){return a(function(t,e){return new Blob(t,e)},arguments)},__wbg_next_6dbf2c0ac8cde20f:function(){return s(function(t){return t.next},arguments)},__wbg_next_71f2aa1cb3d1e37e:function(){return a(function(t){return t.next()},arguments)},__wbg_now_86c0d4ba3fa605b8:function(){return s(function(){return Date.now()},arguments)},__wbg_offsetX_fdc5eb20edabaadb:function(){return s(function(t){let e=t.offsetX;return o(e),e},arguments)},__wbg_offsetY_0a05e99022d21c5b:function(){return s(function(t){let e=t.offsetY;return o(e),e},arguments)},__wbg_open_221b279749ba2e4e:function(){return a(function(t,e,n,r,i){let f=t.open(l(e,n),l(r,i));return g(f)?0:m(f)},arguments)},__wbg_origin_ed66c06e67ad2049:function(){return a(function(t,e){let n=e.origin,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_ownerDocument_5a7a5473f8709b3e:function(){return s(function(t){let e=t.ownerDocument;return g(e)?0:m(e)},arguments)},__wbg_pageX_56e23ef1ade65aa7:function(){return s(function(t){let e=t.pageX;return o(e),e},arguments)},__wbg_pageX_9c5f057472795ea1:function(){return s(function(t){let e=t.pageX;return o(e),e},arguments)},__wbg_pageY_12d134258ad141c4:function(){return s(function(t){let e=t.pageY;return o(e),e},arguments)},__wbg_pageY_d421aa8cfce954d6:function(){return s(function(t){let e=t.pageY;return o(e),e},arguments)},__wbg_parentElement_5030754e30795652:function(){return s(function(t){let e=t.parentElement;return g(e)?0:m(e)},arguments)},__wbg_pathname_d27a358088ce7b2b:function(){return a(function(t,e){let n=e.pathname,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_pointerId_ea33d2695be12e7f:function(){return s(function(t){let e=t.pointerId;return o(e),e},arguments)},__wbg_pointerType_d5e932608aa61bb6:function(){return s(function(t,e){let n=e.pointerType,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_pressure_9a7845d9744ae9f4:function(){return s(function(t){return t.pressure},arguments)},__wbg_preventDefault_b64888c857500682:function(){return s(function(t){t.preventDefault()},arguments)},__wbg_propertyName_835d4a18e8327b10:function(){return s(function(t,e){let n=e.propertyName,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_prototypesetcall_4770620bbe4688a0:function(){return s(function(t,e,n){Uint8Array.prototype.set.call(J(t,e),n)},arguments)},__wbg_pseudoElement_174adc902d41a1c1:function(){return s(function(t,e){let n=e.pseudoElement,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_pseudoElement_6013088f8877903f:function(){return s(function(t,e){let n=e.pseudoElement,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_pushState_3d01701623122bc8:function(){return a(function(t,e,n,r,i,f){t.pushState(e,l(n,r),i===0?void 0:l(i,f))},arguments)},__wbg_push_d2ae3af0c1217ae6:function(){return s(function(t,e){let n=t.push(e);return o(n),n},arguments)},__wbg_queueMicrotask_0ab5b2d2393e99b9:function(){return s(function(t){return t.queueMicrotask},arguments)},__wbg_queueMicrotask_6a09b7bc46549209:function(){return s(function(t){queueMicrotask(t)},arguments)},__wbg_radiusX_06f8dad66dfba7a4:function(){return s(function(t){let e=t.radiusX;return o(e),e},arguments)},__wbg_radiusY_0658ca1fd998f494:function(){return s(function(t){let e=t.radiusY;return o(e),e},arguments)},__wbg_readAsArrayBuffer_7db0a55c6c3a2b4e:function(){return a(function(t,e){t.readAsArrayBuffer(e)},arguments)},__wbg_readAsText_a8f6dfc210ba1a8e:function(){return a(function(t,e){t.readAsText(e)},arguments)},__wbg_reload_83ac0dd969ac6d23:function(){return a(function(t){t.reload()},arguments)},__wbg_removeAttribute_1e7d2c409776d836:function(){return a(function(t,e,n){t.removeAttribute(l(e,n))},arguments)},__wbg_removeEventListener_a3f23c70077bdcc1:function(){return a(function(t,e,n,r){t.removeEventListener(l(e,n),r)},arguments)},__wbg_removeItem_78e03a38da96e0ae:function(){return a(function(t,e,n){t.removeItem(l(e,n))},arguments)},__wbg_repeat_4e131e99bff9b9f4:function(){return s(function(t){let e=t.repeat;return b(e),e},arguments)},__wbg_replaceState_9a0a4a53d3bf3439:function(){return a(function(t,e,n,r,i,f){t.replaceState(e,l(n,r),i===0?void 0:l(i,f))},arguments)},__wbg_requestAnimationFrame_1a85deeab66448c2:function(){return a(function(t,e){let n=t.requestAnimationFrame(e);return o(n),n},arguments)},__wbg_resolve_2191a4dfe481c25b:function(){return s(function(t){return Promise.resolve(t)},arguments)},__wbg_respond_510e32df8aeb6817:function(){return a(function(t,e){t.respond(e>>>0)},arguments)},__wbg_result_53fd7283ffc3cdb8:function(){return a(function(t){return t.result},arguments)},__wbg_rootBounds_f45f30011740fdb2:function(){return s(function(t){let e=t.rootBounds;return g(e)?0:m(e)},arguments)},__wbg_rotationAngle_d0a0b686498034d7:function(){return s(function(t){return t.rotationAngle},arguments)},__wbg_run_9f0b5ec848bddc2d:function(){return s(function(t){t.run()},arguments)},__wbg_rustRecv_ce812a5965920185:function(){return s(function(t){return t.rustRecv()},arguments)},__wbg_rustSend_27a0ddfb6f0fa952:function(){return s(function(t,e){t.rustSend(e)},arguments)},__wbg_saveTemplate_4aa5c34bf8b14cc9:function(){return s(function(t,e,n,r){var i=zt(e,n).slice();c.__wbindgen_free(e,n*4,4),t.saveTemplate(i,r)},arguments)},__wbg_screenX_0a3f7a47942676bd:function(){return s(function(t){let e=t.screenX;return o(e),e},arguments)},__wbg_screenX_bd1fb25d48033c9c:function(){return s(function(t){let e=t.screenX;return o(e),e},arguments)},__wbg_screenY_30eadec06612b80f:function(){return s(function(t){let e=t.screenY;return o(e),e},arguments)},__wbg_screenY_7e467250657a3c56:function(){return s(function(t){let e=t.screenY;return o(e),e},arguments)},__wbg_scrollHeight_8cf19eb16ebc9b9b:function(){return s(function(t){let e=t.scrollHeight;return o(e),e},arguments)},__wbg_scrollIntoView_d8b806f471b7418e:function(){return s(function(t,e){t.scrollIntoView(e)},arguments)},__wbg_scrollLeft_5be50f489b342a09:function(){return s(function(t){let e=t.scrollLeft;return o(e),e},arguments)},__wbg_scrollTo_cac0dff19f631942:function(){return s(function(t,e,n){t.scrollTo(e,n)},arguments)},__wbg_scrollTop_b3effa9c5de14d21:function(){return s(function(t){let e=t.scrollTop;return o(e),e},arguments)},__wbg_scrollWidth_38006a7134cdfeff:function(){return s(function(t){let e=t.scrollWidth;return o(e),e},arguments)},__wbg_scrollX_9da7f7defce2297e:function(){return a(function(t){return t.scrollX},arguments)},__wbg_scrollY_b4c56e98c6d976ad:function(){return a(function(t){return t.scrollY},arguments)},__wbg_scroll_4a3297b235bee8de:function(){return s(function(t,e){t.scroll(e)},arguments)},__wbg_search_af2555aa41bd23cc:function(){return a(function(t,e){let n=e.search,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_setAttributeInner_11a30d36aa43287e:function(){return s(function(t,e,n,r,i,f){nt(t,l(e,n),r,i===0?void 0:l(i,f))},arguments)},__wbg_setAttribute_71039043be82d098:function(){return a(function(t,e,n,r,i){t.setAttribute(l(e,n),l(r,i))},arguments)},__wbg_setData_19a2f9f5b313cbd6:function(){return a(function(t,e,n,r,i){t.setData(l(e,n),l(r,i))},arguments)},__wbg_setInterval_84b64f01452a246e:function(){return a(function(t,e){return setInterval(t,e)},arguments)},__wbg_setItem_364a11cf21db9039:function(){return a(function(t,e,n,r,i){t.setItem(l(e,n),l(r,i))},arguments)},__wbg_setProperty_e4e51b1b1d681d15:function(){return a(function(t,e,n,r,i){t.setProperty(l(e,n),l(r,i))},arguments)},__wbg_setTimeout_3a808dd861dd3c12:function(){return s(function(t,e){return setTimeout(t,e)},arguments)},__wbg_setTimeout_ef24d2fc3ad97385:function(){return a(function(t,e){return setTimeout(t,e)},arguments)},__wbg_setTimeout_f757f00851f76c42:function(){return s(function(t,e){return setTimeout(t,e)},arguments)},__wbg_set_4d7dd76f3dae2926:function(){return s(function(t,e,n){t.set(J(e,n))},arguments)},__wbg_set_575dd786d51585f8:function(){return s(function(t,e,n){return t.set(e,n)},arguments)},__wbg_set_6be42768c690e380:function(){return s(function(t,e,n){t[e]=n},arguments)},__wbg_set_8a16b38e4805b298:function(){return s(function(t,e,n){t[e>>>0]=n},arguments)},__wbg_set_behavior_af2ac621388b739f:function(){return s(function(t,e){t.behavior=ut[e]},arguments)},__wbg_set_behavior_f9f984e684b645bc:function(){return s(function(t,e){t.behavior=ut[e]},arguments)},__wbg_set_block_8135b3acafa1ca88:function(){return s(function(t,e){t.block=it[e]},arguments)},__wbg_set_body_029f2d171e0a005f:function(){return s(function(t,e){t.body=e},arguments)},__wbg_set_cache_b4a740b195c051f4:function(){return s(function(t,e){t.cache=xt[e]},arguments)},__wbg_set_credentials_bb34a40189e3b43b:function(){return s(function(t,e){t.credentials=Tt[e]},arguments)},__wbg_set_dropEffect_ee044779833a313d:function(){return s(function(t,e,n){t.dropEffect=l(e,n)},arguments)},__wbg_set_effectAllowed_70e1a79093efb47f:function(){return s(function(t,e,n){t.effectAllowed=l(e,n)},arguments)},__wbg_set_headers_9c61d123c3ee1f10:function(){return s(function(t,e){t.headers=e},arguments)},__wbg_set_href_960e4284e5cae151:function(){return a(function(t,e,n){t.href=l(e,n)},arguments)},__wbg_set_inline_77b0fb4f96d76814:function(){return s(function(t,e){t.inline=it[e]},arguments)},__wbg_set_left_18508443258534ad:function(){return s(function(t,e){t.left=e},arguments)},__wbg_set_method_5532d59b92d76467:function(){return s(function(t,e,n){t.method=l(e,n)},arguments)},__wbg_set_mode_66c79886ad78fc05:function(){return s(function(t,e){t.mode=St[e]},arguments)},__wbg_set_onload_4dc1f96725e4138c:function(){return s(function(t,e){t.onload=e},arguments)},__wbg_set_scrollRestoration_29b3e9dc74898bc5:function(){return a(function(t,e){t.scrollRestoration=Nt[e]},arguments)},__wbg_set_search_6f7cde7f191dc1a1:function(){return a(function(t,e,n){t.search=l(e,n)},arguments)},__wbg_set_signal_c4ef8faddb4c1446:function(){return s(function(t,e){t.signal=e},arguments)},__wbg_set_textContent_54dcad83ae15772d:function(){return s(function(t,e,n){t.textContent=e===0?void 0:l(e,n)},arguments)},__wbg_set_top_29926a592a2d228a:function(){return s(function(t,e){t.top=e},arguments)},__wbg_set_type_8ce203e412e28cf6:function(){return s(function(t,e,n){t.type=l(e,n)},arguments)},__wbg_shiftKey_42866b295d317445:function(){return s(function(t){let e=t.shiftKey;return b(e),e},arguments)},__wbg_shiftKey_9bcb8bdd60c2f152:function(){return s(function(t){let e=t.shiftKey;return b(e),e},arguments)},__wbg_shiftKey_9f797da486b2ade8:function(){return s(function(t){let e=t.shiftKey;return b(e),e},arguments)},__wbg_signal_dad7cb35193abd31:function(){return s(function(t){return t.signal},arguments)},__wbg_size_6304a694765921a9:function(){return s(function(t){return t.size},arguments)},__wbg_state_edcc5b2da67f07f2:function(){return a(function(t){return t.state},arguments)},__wbg_static_accessor_GLOBAL_4ef717fb391d88b7:function(){return s(function(){let t=typeof global>"u"?null:global;return g(t)?0:m(t)},arguments)},__wbg_static_accessor_GLOBAL_THIS_8d1badc68b5a74f4:function(){return s(function(){let t=typeof globalThis>"u"?null:globalThis;return g(t)?0:m(t)},arguments)},__wbg_static_accessor_SELF_146583524fe1469b:function(){return s(function(){let t=typeof self>"u"?null:self;return g(t)?0:m(t)},arguments)},__wbg_static_accessor_WINDOW_f2829a2234d7819e:function(){return s(function(){let t=typeof window>"u"?null:window;return g(t)?0:m(t)},arguments)},__wbg_status_c45b3b9b3033184a:function(){return s(function(t){let e=t.status;return o(e),e},arguments)},__wbg_stringify_b54333f60f1e4dad:function(){return a(function(t){return JSON.stringify(t)},arguments)},__wbg_style_6657aed849e5d757:function(){return s(function(t){return t.style},arguments)},__wbg_tagName_d99c8072027f3c98:function(){return s(function(t,e){let n=e.tagName,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_tangentialPressure_979a239d3db31d90:function(){return s(function(t){return t.tangentialPressure},arguments)},__wbg_targetTouches_3e9bdb053b2d5023:function(){return s(function(t){return t.targetTouches},arguments)},__wbg_target_e759594a8d965ed7:function(){return s(function(t){let e=t.target;return g(e)?0:m(e)},arguments)},__wbg_textContent_37277f66248f39e6:function(){return s(function(t,e){let n=e.textContent;var r=g(n)?0:h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_text_d3a29f7525a132c3:function(){return a(function(t){return t.text()},arguments)},__wbg_then_16d107c451e9905d:function(){return s(function(t,e,n){return t.then(e,n)},arguments)},__wbg_then_6ec10ae38b3e92f7:function(){return s(function(t,e){return t.then(e)},arguments)},__wbg_tiltX_1327e8185e612854:function(){return s(function(t){let e=t.tiltX;return o(e),e},arguments)},__wbg_tiltY_b44744ee36b60a24:function(){return s(function(t){let e=t.tiltY;return o(e),e},arguments)},__wbg_time_2e33e99ff5e53342:function(){return s(function(t){return t.time},arguments)},__wbg_top_fe120acfa924a430:function(){return s(function(t){return t.top},arguments)},__wbg_touches_a631c50f1b367753:function(){return s(function(t){return t.touches},arguments)},__wbg_twist_6cc18194426f8a4f:function(){return s(function(t){let e=t.twist;return o(e),e},arguments)},__wbg_type_06f2150affb3c059:function(){return s(function(t,e){let n=e.type,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_type_9d13c17ea2611dd0:function(){return s(function(t,e){let n=e.type,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_type_c1987e7fbaf7340e:function(){return s(function(t,e){let n=e.type,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_update_memory_ddf6b41a329aec73:function(){return s(function(t,e){t.update_memory(e)},arguments)},__wbg_url_abdb8fb08377f8c0:function(){return s(function(t,e){let n=e.url,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_value_1f687dfa7d6c3d08:function(){return s(function(t,e){let n=e.value,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_value_a5d5488a9589444a:function(){return s(function(t){return t.value},arguments)},__wbg_value_c40f8f7227bb3a9e:function(){return s(function(t,e){let n=e.value,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_value_d7621df0105931d8:function(){return s(function(t,e){let n=e.value,r=h(n,c.__wbindgen_malloc,c.__wbindgen_realloc),i=d;_().setInt32(t+4,i,!0),_().setInt32(t+0,r,!0)},arguments)},__wbg_view_21f1d4a4f175dfa9:function(){return s(function(t){let e=t.view;return g(e)?0:m(e)},arguments)},__wbg_weak_4a47d74ffa0a7f96:function(){return s(function(t){return t.weak()},arguments)},__wbg_width_16032a5bda5e6fa9:function(){return s(function(t){let e=t.width;return o(e),e},arguments)},__wbg_width_20c45c895834b83f:function(){return s(function(t){return t.width},arguments)},__wbg_width_219185400361db86:function(){return s(function(t){return t.width},arguments)},__wbg_x_71553b4e719d215a:function(){return s(function(t){return t.x},arguments)},__wbg_y_111b04aa46dc0f86:function(){return s(function(t){return t.y},arguments)},__wbindgen_cast_0000000000000001:function(){return s(function(t,e){return k(t,e,Et)},arguments)},__wbindgen_cast_0000000000000002:function(){return s(function(t,e){return k(t,e,yt)},arguments)},__wbindgen_cast_0000000000000003:function(){return s(function(t,e){return k(t,e,vt)},arguments)},__wbindgen_cast_0000000000000004:function(){return s(function(t,e){return Bt(t,e,kt)},arguments)},__wbindgen_cast_0000000000000005:function(){return s(function(t,e){return k(t,e,ht)},arguments)},__wbindgen_cast_0000000000000006:function(){return s(function(t,e){return k(t,e,wt)},arguments)},__wbindgen_cast_0000000000000007:function(){return s(function(t,e){return k(t,e,mt)},arguments)},__wbindgen_cast_0000000000000008:function(){return s(function(t,e){return k(t,e,pt)},arguments)},__wbindgen_cast_0000000000000009:function(){return s(function(t){return t},arguments)},__wbindgen_cast_000000000000000a:function(){return s(function(t){return t},arguments)},__wbindgen_cast_000000000000000b:function(){return s(function(t,e){return l(t,e)},arguments)},__wbindgen_cast_000000000000000c:function(){return s(function(t){return BigInt.asUintN(64,t)},arguments)},__wbindgen_init_externref_table:function(){let t=c.__wbindgen_externrefs,e=t.grow(4);t.set(0,void 0),t.set(e+0,void 0),t.set(e+1,null),t.set(e+2,!0),t.set(e+3,!1)}}}}function ht(u,t){o(u),o(t),c._ZN12wasm_bindgen7convert8closures1_6invoke17h790c723772977d15E(u,t)}function wt(u,t){o(u),o(t),c._ZN12wasm_bindgen7convert8closures1_6invoke17h59cad6d2488dca29E(u,t)}function mt(u,t){o(u),o(t),c._ZN12wasm_bindgen7convert8closures1_6invoke17h9761498151360b23E(u,t)}function pt(u,t){o(u),o(t),c._ZN12wasm_bindgen7convert8closures1_6invoke17h8e4f100a6c778e58E(u,t)}function yt(u,t,e){o(u),o(t),c._ZN12wasm_bindgen7convert8closures1_6invoke17h7dd8c6f9e9c12966E(u,t,e)}function vt(u,t,e){o(u),o(t),c._ZN12wasm_bindgen7convert8closures1_6invoke17hd9e6853fc436a5f1E(u,t,e)}function kt(u,t,e){o(u),o(t),c._ZN12wasm_bindgen7convert8closures1_1_6invoke17h3dab76294ffea566E(u,t,e)}function Et(u,t,e){o(u),o(t);let n=c._ZN12wasm_bindgen7convert8closures1_6invoke17hceaf1cd31a005417E(u,t,e);if(n[1])throw Ft(n[0])}function It(u,t,e,n){o(u),o(t),c._ZN12wasm_bindgen7convert8closures1_6invoke17h04eb02ab906308ebE(u,t,e,n)}var At=["bytes"],xt=["default","no-store","reload","no-cache","force-cache","only-if-cached"],Tt=["omit","same-origin","include"],St=["same-origin","no-cors","cors","navigate"],ut=["auto","instant","smooth"],it=["start","center","end","nearest"],Nt=["auto","manual"],Rt=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(u=>c.__wbg_intounderlyingbytesource_free(u,1)),Ot=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(u=>c.__wbg_intounderlyingsink_free(u,1)),Ct=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(u=>c.__wbg_intounderlyingsource_free(u,1)),ct=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(u=>c.__wbg_jsowner_free(u,1));function m(u){let t=c.__externref_table_alloc();return c.__wbindgen_externrefs.set(t,u),t}function Lt(u){if(typeof u!="bigint")throw new Error(`expected a bigint argument, found ${typeof u}`)}function b(u){if(typeof u!="boolean")throw new Error(`expected a boolean argument, found ${typeof u}`)}function o(u){if(typeof u!="number")throw new Error(`expected a number argument, found ${typeof u}`)}var X=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(u=>c.__wbindgen_destroy_closure(u.a,u.b));function Q(u){let t=typeof u;if(t=="number"||t=="boolean"||u==null)return`${u}`;if(t=="string")return`"${u}"`;if(t=="symbol"){let r=u.description;return r==null?"Symbol":`Symbol(${r})`}if(t=="function"){let r=u.name;return typeof r=="string"&&r.length>0?`Function(${r})`:"Function"}if(Array.isArray(u)){let r=u.length,i="[";r>0&&(i+=Q(u[0]));for(let f=1;f1)n=e[1];else return toString.call(u);if(n=="Object")try{return"Object("+JSON.stringify(u)+")"}catch{return"Object"}return u instanceof Error?`${u.name}: ${u.message} +${u.stack}`:n}function zt(u,t){u=u>>>0;let e=_(),n=[];for(let r=u;r>>0,O().subarray(u/1,u/1+t)}var E=null;function _(){return(E===null||E.buffer.detached===!0||E.buffer.detached===void 0&&E.buffer!==c.memory.buffer)&&(E=new DataView(c.memory.buffer)),E}function l(u,t){return jt(u>>>0,t)}var R=null;function O(){return(R===null||R.byteLength===0)&&(R=new Uint8Array(c.memory.buffer)),R}function a(u,t){try{return u.apply(this,t)}catch(e){let n=m(e);c.__wbindgen_exn_store(n)}}function g(u){return u==null}function s(u,t){try{return u.apply(this,t)}catch(e){let n=(function(){try{return e instanceof Error?`${e.message} Stack: -${e.stack}`:e.toString()}catch{return""}})();throw console.error("wasm-bindgen: imported JS function that was not marked as `catch` threw an error:",n),e}}function Bt(u,t,e){let n={a:u,b:t,cnt:1},r=(...i)=>{n.cnt++;try{return e(n.a,n.b,...i)}finally{r._wbg_cb_unref()}};return r._wbg_cb_unref=()=>{--n.cnt===0&&(c.__wbindgen_destroy_closure(n.a,n.b),n.a=0,X.unregister(n))},X.register(r,n,n),r}function k(u,t,e){let n={a:u,b:t,cnt:1},r=(...i)=>{n.cnt++;let a=n.a;n.a=0;try{return e(a,n.b,...i)}finally{n.a=a,r._wbg_cb_unref()}};return r._wbg_cb_unref=()=>{--n.cnt===0&&(c.__wbindgen_destroy_closure(n.a,n.b),n.a=0,X.unregister(n))},X.register(r,n,n),r}function Mt(u,t){let e=t(u.length*4,4)>>>0;for(let n=0;n>>0;return O().subarray(p,p+w.length).set(w),d=w.length,p}let n=u.length,r=t(n,1)>>>0,i=O(),a=0;for(;a127)break;i[r+a]=w}if(a!==n){a!==0&&(u=u.slice(a)),r=e(r,n,n=a+u.length*3,1)>>>0;let w=O().subarray(r+a,r+n),p=C.encodeInto(u,w);if(p.read!==u.length)throw new Error("failed to pass whole string");a+=p.written,r=e(r,n,a,1)>>>0}return d=a,r}function Ft(u){let t=c.__wbindgen_externrefs.get(u);return c.__externref_table_dealloc(u),t}var P=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0});P.decode();var Ut=2146435072,G=0;function jt(u,t){return G+=t,G>=Ut&&(P=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0}),P.decode(),G=t),P.decode(O().subarray(u,u+t))}var C=new TextEncoder;"encodeInto"in C||(C.encodeInto=function(u,t){let e=C.encode(u);return t.set(e),{read:u.length,written:e.length}});var d=0,Dt,Wt,c;function ot(u,t){return Wt=u,c=u.exports,Dt=t,E=null,R=null,c.__wbindgen_start(),c}async function Pt(u,t){if(typeof Response=="function"&&u instanceof Response){if(typeof WebAssembly.instantiateStreaming=="function")try{return await WebAssembly.instantiateStreaming(u,t)}catch(r){if(u.ok&&e(u.type)&&u.headers.get("Content-Type")!=="application/wasm")console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n",r);else throw r}let n=await u.arrayBuffer();return await WebAssembly.instantiate(n,t)}else{let n=await WebAssembly.instantiate(u,t);return n instanceof WebAssembly.Instance?{instance:n,module:u}:n}function e(n){switch(n){case"basic":case"cors":case"default":return!0}return!1}}function at(u){if(c!==void 0)return c;u!==void 0&&(Object.getPrototypeOf(u)===Object.prototype?{module:u}=u:console.warn("using deprecated parameters for `initSync()`; pass a single object instead"));let t=tt();u instanceof WebAssembly.Module||(u=new WebAssembly.Module(u));let e=new WebAssembly.Instance(u,t);return ot(e,u)}async function _t(u){if(c!==void 0)return c;u!==void 0&&(Object.getPrototypeOf(u)===Object.prototype?{module_or_path:u}=u:console.warn("using deprecated parameters for the initialization function; pass a single object instead")),u===void 0&&(u=new URL("web_bg.wasm",import.meta.url));let t=tt();(typeof u=="string"||typeof Request=="function"&&u instanceof Request||typeof URL=="function"&&u instanceof URL)&&(u=fetch(u));let{instance:e,module:n}=await Pt(await u,t);return ot(e,n)}globalThis.__wasm_split_main_initSync=at;_t({module_or_path:"/./assets/web_bg-dxh9628c8b4a0d6e07b.wasm"}).then(u=>{globalThis.__dx_mainWasm=u,globalThis.__dx_mainInit=_t,globalThis.__dx_mainInitSync=at,globalThis.__dx___wbg_get_imports=tt,u.__wbindgen_start==null&&u.main()});export{K as IntoUnderlyingByteSource,q as IntoUnderlyingSink,H as IntoUnderlyingSource,L as JSOwner,c as __wasm,_t as default,at as initSync}; +${e.stack}`:e.toString()}catch{return""}})();throw console.error("wasm-bindgen: imported JS function that was not marked as `catch` threw an error:",n),e}}function Bt(u,t,e){let n={a:u,b:t,cnt:1},r=(...i)=>{n.cnt++;try{return e(n.a,n.b,...i)}finally{r._wbg_cb_unref()}};return r._wbg_cb_unref=()=>{--n.cnt===0&&(c.__wbindgen_destroy_closure(n.a,n.b),n.a=0,X.unregister(n))},X.register(r,n,n),r}function k(u,t,e){let n={a:u,b:t,cnt:1},r=(...i)=>{n.cnt++;let f=n.a;n.a=0;try{return e(f,n.b,...i)}finally{n.a=f,r._wbg_cb_unref()}};return r._wbg_cb_unref=()=>{--n.cnt===0&&(c.__wbindgen_destroy_closure(n.a,n.b),n.a=0,X.unregister(n))},X.register(r,n,n),r}function Mt(u,t){let e=t(u.length*4,4)>>>0;for(let n=0;n>>0;return O().subarray(p,p+w.length).set(w),d=w.length,p}let n=u.length,r=t(n,1)>>>0,i=O(),f=0;for(;f127)break;i[r+f]=w}if(f!==n){f!==0&&(u=u.slice(f)),r=e(r,n,n=f+u.length*3,1)>>>0;let w=O().subarray(r+f,r+n),p=C.encodeInto(u,w);if(p.read!==u.length)throw new Error("failed to pass whole string");f+=p.written,r=e(r,n,f,1)>>>0}return d=f,r}function Ft(u){let t=c.__wbindgen_externrefs.get(u);return c.__externref_table_dealloc(u),t}var P=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0});P.decode();var Ut=2146435072,G=0;function jt(u,t){return G+=t,G>=Ut&&(P=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0}),P.decode(),G=t),P.decode(O().subarray(u,u+t))}var C=new TextEncoder;"encodeInto"in C||(C.encodeInto=function(u,t){let e=C.encode(u);return t.set(e),{read:u.length,written:e.length}});var d=0,Dt,Wt,c;function ot(u,t){return Wt=u,c=u.exports,Dt=t,E=null,R=null,c.__wbindgen_start(),c}async function Pt(u,t){if(typeof Response=="function"&&u instanceof Response){if(typeof WebAssembly.instantiateStreaming=="function")try{return await WebAssembly.instantiateStreaming(u,t)}catch(r){if(u.ok&&e(u.type)&&u.headers.get("Content-Type")!=="application/wasm")console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n",r);else throw r}let n=await u.arrayBuffer();return await WebAssembly.instantiate(n,t)}else{let n=await WebAssembly.instantiate(u,t);return n instanceof WebAssembly.Instance?{instance:n,module:u}:n}function e(n){switch(n){case"basic":case"cors":case"default":return!0}return!1}}function at(u){if(c!==void 0)return c;u!==void 0&&(Object.getPrototypeOf(u)===Object.prototype?{module:u}=u:console.warn("using deprecated parameters for `initSync()`; pass a single object instead"));let t=tt();u instanceof WebAssembly.Module||(u=new WebAssembly.Module(u));let e=new WebAssembly.Instance(u,t);return ot(e,u)}async function _t(u){if(c!==void 0)return c;u!==void 0&&(Object.getPrototypeOf(u)===Object.prototype?{module_or_path:u}=u:console.warn("using deprecated parameters for the initialization function; pass a single object instead")),u===void 0&&(u=new URL("web_bg.wasm",import.meta.url));let t=tt();(typeof u=="string"||typeof Request=="function"&&u instanceof Request||typeof URL=="function"&&u instanceof URL)&&(u=fetch(u));let{instance:e,module:n}=await Pt(await u,t);return ot(e,n)}globalThis.__wasm_split_main_initSync=at;_t({module_or_path:"/./assets/web_bg-dxh397f70ff35dbc871.wasm"}).then(u=>{globalThis.__dx_mainWasm=u,globalThis.__dx_mainInit=_t,globalThis.__dx_mainInitSync=at,globalThis.__dx___wbg_get_imports=tt,u.__wbindgen_start==null&&u.main()});export{K as IntoUnderlyingByteSource,q as IntoUnderlyingSink,H as IntoUnderlyingSource,L as JSOwner,c as __wasm,_t as default,at as initSync}; diff --git a/python/probing/bundled_web/public/assets/web-dxh3f25885a213214.js.br b/python/probing/bundled_web/public/assets/web-dxh3f25885a213214.js.br new file mode 100644 index 00000000..6b3cdb41 Binary files /dev/null and b/python/probing/bundled_web/public/assets/web-dxh3f25885a213214.js.br differ diff --git a/python/probing/bundled_web/public/assets/web-dxh50ad7a34ffc43ea1.js.br b/python/probing/bundled_web/public/assets/web-dxh50ad7a34ffc43ea1.js.br deleted file mode 100644 index 77798385..00000000 Binary files a/python/probing/bundled_web/public/assets/web-dxh50ad7a34ffc43ea1.js.br and /dev/null differ diff --git a/python/probing/bundled_web/public/assets/web_bg-dxh397f70ff35dbc871.wasm b/python/probing/bundled_web/public/assets/web_bg-dxh397f70ff35dbc871.wasm new file mode 100644 index 00000000..5f63ad6d Binary files /dev/null and b/python/probing/bundled_web/public/assets/web_bg-dxh397f70ff35dbc871.wasm differ diff --git a/python/probing/bundled_web/public/assets/web_bg-dxh397f70ff35dbc871.wasm.br b/python/probing/bundled_web/public/assets/web_bg-dxh397f70ff35dbc871.wasm.br new file mode 100644 index 00000000..1b7b25d3 Binary files /dev/null and b/python/probing/bundled_web/public/assets/web_bg-dxh397f70ff35dbc871.wasm.br differ diff --git a/python/probing/bundled_web/public/assets/web_bg-dxh9628c8b4a0d6e07b.wasm b/python/probing/bundled_web/public/assets/web_bg-dxh9628c8b4a0d6e07b.wasm deleted file mode 100644 index 7741f52d..00000000 Binary files a/python/probing/bundled_web/public/assets/web_bg-dxh9628c8b4a0d6e07b.wasm and /dev/null differ diff --git a/python/probing/bundled_web/public/assets/web_bg-dxh9628c8b4a0d6e07b.wasm.br b/python/probing/bundled_web/public/assets/web_bg-dxh9628c8b4a0d6e07b.wasm.br deleted file mode 100644 index 796a079e..00000000 Binary files a/python/probing/bundled_web/public/assets/web_bg-dxh9628c8b4a0d6e07b.wasm.br and /dev/null differ diff --git a/python/probing/bundled_web/public/index.html b/python/probing/bundled_web/public/index.html index 4316b227..3e19f0de 100644 --- a/python/probing/bundled_web/public/index.html +++ b/python/probing/bundled_web/public/index.html @@ -3,7 +3,7 @@ - Probing Web InterfaceProbing Web Interface + Probing Web Interface - +
- + diff --git a/scripts/prune-bundled-web.sh b/scripts/prune-bundled-web.sh index 2d598f31..a562bae0 100755 --- a/scripts/prune-bundled-web.sh +++ b/scripts/prune-bundled-web.sh @@ -7,18 +7,25 @@ INDEX="$PUBLIC/index.html" ASSETS="$PUBLIC/assets" if [[ ! -f "$INDEX" ]]; then - exit 0 + echo "error: missing bundled web index: $INDEX" >&2 + exit 1 fi entry_js="$(grep -oE 'web-dxh[^"'"'"' ]+\.js' "$INDEX" | head -1 || true)" if [[ -z "$entry_js" ]]; then - exit 0 + echo "error: index does not reference a Dioxus entry script: $INDEX" >&2 + exit 1 fi js_path="$ASSETS/$entry_js" -wasm_ref="" -if [[ -f "$js_path" ]]; then - wasm_ref="$(grep -oE 'web_bg-dxh[0-9a-f]+\.wasm' "$js_path" | head -1 || true)" +if [[ ! -f "$js_path" ]]; then + echo "error: index references missing entry script: $js_path" >&2 + exit 1 +fi +wasm_ref="$(grep -oE 'web_bg-dxh[0-9a-f]+\.wasm' "$js_path" | head -1 || true)" +if [[ -z "$wasm_ref" || ! -f "$ASSETS/$wasm_ref" ]]; then + echo "error: entry script references missing WASM module: $ASSETS/${wasm_ref:-}" >&2 + exit 1 fi declare -a keep=( diff --git a/scripts/verify_web_assets.py b/scripts/verify_web_assets.py new file mode 100644 index 00000000..e8feeafa --- /dev/null +++ b/scripts/verify_web_assets.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +"""Verify that a bundled Dioxus index references files present in the bundle.""" + +from __future__ import annotations + +import argparse +import re +import sys +from collections.abc import Callable +from pathlib import Path, PurePosixPath +from urllib.parse import unquote, urlsplit + +_HTML_ASSET_RE = re.compile(r"""(?:src|href)=["']([^"']+)["']""", re.IGNORECASE) +_ENTRY_JS_RE = re.compile(r"(?:^|/)assets/(web-dxh[0-9a-f]+\.js)$") +_WASM_RE = re.compile(r"web_bg-dxh[0-9a-f]+\.wasm") + + +def _local_path(reference: str) -> str | None: + parsed = urlsplit(reference) + if parsed.scheme or parsed.netloc or reference.startswith(("data:", "#")): + return None + path = unquote(parsed.path).lstrip("/") + normalized = str(PurePosixPath(path)) + while normalized.startswith("./"): + normalized = normalized[2:] + if normalized == ".." or normalized.startswith("../"): + return None + return normalized + + +def verify_web_files( + index_html: str, + exists: Callable[[str], bool], + read_text: Callable[[str], str], +) -> list[str]: + """Validate index/entry/WASM references against an abstract file collection.""" + errors: list[str] = [] + references = [] + for reference in _HTML_ASSET_RE.findall(index_html): + path = _local_path(reference) + if path is not None: + references.append(path) + for path in sorted(set(references)): + if not exists(path): + errors.append(f"index.html references missing asset: {path}") + + entry_paths = [path for path in references if _ENTRY_JS_RE.search(path)] + if not entry_paths: + errors.append("index.html does not reference a hashed Dioxus entry script") + return errors + + for entry_path in sorted(set(entry_paths)): + if not exists(entry_path): + continue + javascript = read_text(entry_path) + wasm_names = sorted(set(_WASM_RE.findall(javascript))) + if not wasm_names: + errors.append(f"{entry_path} does not reference a hashed WASM module") + continue + for wasm_name in wasm_names: + wasm_path = f"assets/{wasm_name}" + if not exists(wasm_path): + errors.append(f"{entry_path} references missing WASM module: assets/{wasm_name}") + return errors + + +def verify_web_bundle(root: Path) -> list[str]: + """Return bundle-integrity errors without mutating the bundle.""" + index = root / "index.html" + if not index.is_file(): + return ["missing index.html"] + return verify_web_files( + index.read_text(encoding="utf-8"), + lambda path: (root / path).is_file(), + lambda path: (root / path).read_text(encoding="utf-8"), + ) + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "root", + nargs="?", + type=Path, + default=Path("python/probing/bundled_web/public"), + help="bundle root containing index.html", + ) + args = parser.parse_args(argv) + errors = verify_web_bundle(args.root) + if errors: + print(f"error: invalid web bundle under {args.root}:", file=sys.stderr) + for error in errors: + print(f" - {error}", file=sys.stderr) + return 1 + print(f"ok: web bundle references are complete under {args.root}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/verify_wheel_contents.py b/scripts/verify_wheel_contents.py index eb878430..0e41a6e3 100644 --- a/scripts/verify_wheel_contents.py +++ b/scripts/verify_wheel_contents.py @@ -8,6 +8,11 @@ import zipfile from pathlib import Path +try: + from verify_web_assets import verify_web_files +except ModuleNotFoundError: # Imported as `scripts.verify_wheel_contents` in tests. + from scripts.verify_web_assets import verify_web_files + # Paths that must exist in every release wheel (wheel archive member names). REQUIRED_PATHS = ( "probing/__init__.py", @@ -43,6 +48,19 @@ def verify_wheel(wheel: Path) -> list[str]: if "probing/bundled_web/index.html" in names: continue missing.append(member) + web_root = ( + "probing/bundled_web/public/" + if "probing/bundled_web/public/index.html" in names + else "probing/bundled_web/" + ) + index_member = f"{web_root}index.html" + if index_member in names: + errors = verify_web_files( + zf.read(index_member).decode("utf-8"), + lambda path: f"{web_root}{path}" in names, + lambda path: zf.read(f"{web_root}{path}").decode("utf-8"), + ) + missing.extend(f"invalid web bundle: {error}" for error in errors) return missing diff --git a/tests/unit/probing/test_web_assets.py b/tests/unit/probing/test_web_assets.py index bed37d22..f10ac2bc 100644 --- a/tests/unit/probing/test_web_assets.py +++ b/tests/unit/probing/test_web_assets.py @@ -3,11 +3,14 @@ from __future__ import annotations import os +import zipfile from pathlib import Path import pytest from probing import web_assets +from scripts.verify_web_assets import verify_web_bundle +from scripts.verify_wheel_contents import REQUIRED_PATHS, verify_wheel from tests.conftest import is_wheel_install, repo_root @@ -90,3 +93,54 @@ def test_configure_assets_root_respects_override(monkeypatch, tmp_path: Path): monkeypatch.setenv(web_assets._ENV, str(override)) assert web_assets.configure_assets_root() == override + + +def _write_valid_web_bundle(root: Path) -> None: + assets = root / "assets" + assets.mkdir(parents=True) + (root / "index.html").write_text( + '' + '', + encoding="utf-8", + ) + (assets / "tailwind.css").write_text("", encoding="utf-8") + (assets / "web-dxhabc123.js").write_text( + 'const wasm = "web_bg-dxhdef456.wasm";', + encoding="utf-8", + ) + (assets / "web_bg-dxhdef456.wasm").write_bytes(b"\0asm") + + +def test_verify_web_bundle_accepts_complete_reference_graph(tmp_path: Path): + _write_valid_web_bundle(tmp_path) + assert verify_web_bundle(tmp_path) == [] + + +def test_verify_web_bundle_rejects_missing_entry_script(tmp_path: Path): + _write_valid_web_bundle(tmp_path) + (tmp_path / "assets" / "web-dxhabc123.js").unlink() + errors = verify_web_bundle(tmp_path) + assert any( + "missing asset" in error and "web-dxhabc123.js" in error for error in errors + ) + + +def test_verify_web_bundle_rejects_missing_wasm(tmp_path: Path): + _write_valid_web_bundle(tmp_path) + (tmp_path / "assets" / "web_bg-dxhdef456.wasm").unlink() + errors = verify_web_bundle(tmp_path) + assert any("missing WASM module" in error for error in errors) + + +def test_verify_wheel_rejects_broken_web_reference(tmp_path: Path): + wheel = tmp_path / "probing-test.whl" + with zipfile.ZipFile(wheel, "w") as archive: + for path in REQUIRED_PATHS: + content = ( + '' + if path.endswith("bundled_web/public/index.html") + else "" + ) + archive.writestr(path, content) + errors = verify_wheel(wheel) + assert any("invalid web bundle" in error for error in errors) diff --git a/web/DESIGN.md b/web/DESIGN.md index fbe62a45..43c76e37 100644 --- a/web/DESIGN.md +++ b/web/DESIGN.md @@ -4,6 +4,42 @@ **技术栈**:Dioxus 0.7(WASM)、dioxus-router、Tailwind(dx 构建)、reqwest、`probing-skills`(技能执行 SSOT)、async-openai(浏览器 BYOK LLM)。 +## 双 UI 渐进迁移 + +`main.rs` 通过 `ui_version.rs::RootApp` 只挂载一个应用根: + +- `classic`(默认):原有 `app::App`,路由和组件保持不变。 +- `next`:`next::NextApp`,独立 Router、Shell、信息架构和诊断首页。 + +Classic 用户可通过右下角入口进入 Next;Next 用户通过侧栏底部切回 Classic, +也可使用 `?ui=classic|next` 手动切换。选择保存在 +`localStorage["probing.ui.version"]`。切换时整页重载,避免两个 Router、hook +和全局监听器同时存在。 + +Next UI 代码边界: + +```text +web/src/next/ +├── routes.rs # 独立 NextRoute +├── shell.rs # 诊断优先的导航与任务上下文 +├── components.rs # Next 专用页面原语 +├── model.rs # 首页/分布式健康派生模型 +└── pages/ # Dashboard、Investigate、Training、Distributed、Profiles、Explore +``` + +Next Router 保持 Classic 产品 URL 的兼容性,并在新壳层中直接承载成熟能力: + +| 工作区 | 路由 | +|--------|------| +| 诊断 | `/`、`/agent`、`/training`、`/distributed` | +| RL / 推理 | `/rl`、`/rl/train`、`/rl/spans`、`/rl/process-timeline`、`/rl/perfetto`、`/rl/inference` | +| 证据 | `/spans`、`/stacks/*`、`/profiles`、`/profiling/:view` | +| 工具 | `/analytics`、`/python`、`/pulsing`、`/cluster`、`/system` | + +Next Shell 同时挂载 Command Bar、全局快捷键、Investigation URL 同步、页面 +snapshot、后台任务与 Torch overhead monitor,以及可浮动的 Investigate 面板。 +Classic 继续作为独立应用保留;已知产品路由不再依赖 Classic fallback。 + --- ## 一、产品信息架构 @@ -88,6 +124,36 @@ APP_OVERLAY: None | SourceViewer(path, line) | Monitor(Tasks | Overhead) ### 2.4 侧栏结构 +Next 侧栏以用户角色和分析深度组织,并且只展开当前路由所在的活动路径: + +```text +Logo + 紧凑模式 / 移动端关闭 +快速搜索(⌘K) +├── Dashboard +├── Investigate +├── Distributed health +├── Cluster nodes +├── Workloads +│ ├── Training +│ ├── Reinforcement learning → Rollout / Policy training / RL Spans / Timeline / Perfetto +│ └── Inference +├── Advanced analysis +│ ├── Profiles → pprof / Torch / Chrome trace / PyTorch / Ray +│ ├── Stacks → Local / Distributed / Distributed Python +│ └── Spans +└── Deep tools → SQL / Python Trace / Pulsing / System / Catalog +nav(flex-1 独立滚动;仅当前活动路径展开) +Tasks · Overhead +Switch interface: Classic +``` + +活动路径同时承载当前页面的控制项,例如刷新、数据范围、cluster fan-out、 +采样频率和 profiler 启停;右侧页面只保留结果和直接操作图表所需的过滤器。 +展开状态完全由路由决定,非活动分支不可同时展开。桌面侧栏支持 288px 控制 +模式和 80px 图标模式;窄屏侧栏为遮罩抽屉,支持显式关闭且不产生横向滚动。 + +Classic 侧栏保持原结构: + ```text Logo ├── Overview: Dashboard, Investigate, Stacks▾ diff --git a/web/assets/tailwind.css b/web/assets/tailwind.css index 06bbdaba..13b04594 100644 --- a/web/assets/tailwind.css +++ b/web/assets/tailwind.css @@ -823,6 +823,11 @@ video { right: 0px; } +.inset-y-0 { + top: 0px; + bottom: 0px; +} + .inset-y-\[7px\] { top: 7px; bottom: 7px; @@ -848,6 +853,10 @@ video { bottom: 0.75rem; } +.bottom-4 { + bottom: 1rem; +} + .bottom-6 { bottom: 1.5rem; } @@ -888,6 +897,10 @@ video { right: 0.75rem; } +.right-4 { + right: 1rem; +} + .right-6 { right: 1.5rem; } @@ -972,10 +985,18 @@ video { z-index: 50; } +.z-\[10050\] { + z-index: 10050; +} + .z-\[1\] { z-index: 1; } +.z-\[51\] { + z-index: 51; +} + .z-\[60\] { z-index: 60; } @@ -1020,6 +1041,11 @@ video { margin-bottom: 0.125rem; } +.my-2 { + margin-top: 0.5rem; + margin-bottom: 0.5rem; +} + .-mb-px { margin-bottom: -1px; } @@ -1108,6 +1134,10 @@ video { margin-top: 0.5rem; } +.mt-3 { + margin-top: 0.75rem; +} + .mt-4 { margin-top: 1rem; } @@ -1164,6 +1194,10 @@ video { height: 2.5rem; } +.h-16 { + height: 4rem; +} + .h-2 { height: 0.5rem; } @@ -1240,6 +1274,10 @@ video { height: 7px; } +.h-\[calc\(100vh-8rem\)\] { + height: calc(100vh - 8rem); +} + .h-full { height: 100%; } @@ -1252,6 +1290,10 @@ video { height: 100vh; } +.max-h-24 { + max-height: 6rem; +} + .max-h-32 { max-height: 8rem; } @@ -1268,6 +1310,10 @@ video { max-height: 14rem; } +.max-h-64 { + max-height: 16rem; +} + .max-h-72 { max-height: 18rem; } @@ -1316,6 +1362,14 @@ video { min-height: 0px; } +.min-h-16 { + min-height: 4rem; +} + +.min-h-28 { + min-height: 7rem; +} + .min-h-\[140px\] { min-height: 140px; } @@ -1332,6 +1386,10 @@ video { min-height: 36px; } +.min-h-\[36rem\] { + min-height: 36rem; +} + .min-h-\[4rem\] { min-height: 4rem; } @@ -1352,6 +1410,14 @@ video { min-height: calc(100vh - 11rem); } +.min-h-\[calc\(100vh-12rem\)\] { + min-height: calc(100vh - 12rem); +} + +.min-h-\[calc\(100vh-8rem\)\] { + min-height: calc(100vh - 8rem); +} + .min-h-full { min-height: 100%; } @@ -1384,6 +1450,10 @@ video { width: 0.625rem; } +.w-20 { + width: 5rem; +} + .w-24 { width: 6rem; } @@ -1480,6 +1550,10 @@ video { min-width: 180px; } +.min-w-\[22rem\] { + min-width: 22rem; +} + .min-w-\[28px\] { min-width: 28px; } @@ -1549,6 +1623,10 @@ video { max-width: 14rem; } +.max-w-\[1600px\] { + max-width: 1600px; +} + .max-w-\[16rem\] { max-width: 16rem; } @@ -1565,10 +1643,18 @@ video { max-width: 480px; } +.max-w-\[85\%\] { + max-width: 85%; +} + .max-w-\[90\%\] { max-width: 90%; } +.max-w-\[92\%\] { + max-width: 92%; +} + .max-w-\[960px\] { max-width: 960px; } @@ -1739,6 +1825,10 @@ video { grid-template-columns: repeat(2, minmax(0, 1fr)); } +.grid-cols-\[4\.5rem_minmax\(0\2c 1fr\)_5\.5rem\] { + grid-template-columns: 4.5rem minmax(0,1fr) 5.5rem; +} + .grid-cols-\[minmax\(180px\2c 22\%\)_130px_1fr\] { grid-template-columns: minmax(180px,22%) 130px 1fr; } @@ -1958,6 +2048,10 @@ video { overflow-y: auto; } +.overscroll-contain { + overscroll-behavior: contain; +} + .truncate { overflow: hidden; text-overflow: ellipsis; @@ -2133,6 +2227,10 @@ video { border-color: rgb(59 130 246 / var(--tw-border-opacity, 1)); } +.border-blue-500\/25 { + border-color: rgb(59 130 246 / 0.25); +} + .border-blue-500\/50 { border-color: rgb(59 130 246 / 0.5); } @@ -3563,6 +3661,11 @@ video { background-color: rgb(191 219 254 / 0.7); } +.bg-blue-300 { + --tw-bg-opacity: 1; + background-color: rgb(147 197 253 / var(--tw-bg-opacity, 1)); +} + .bg-blue-400 { --tw-bg-opacity: 1; background-color: rgb(96 165 250 / var(--tw-bg-opacity, 1)); @@ -3590,6 +3693,14 @@ video { background-color: rgb(59 130 246 / var(--tw-bg-opacity, 1)); } +.bg-blue-500\/10 { + background-color: rgb(59 130 246 / 0.1); +} + +.bg-blue-500\/20 { + background-color: rgb(59 130 246 / 0.2); +} + .bg-blue-500\/85 { background-color: rgb(59 130 246 / 0.85); } @@ -3785,6 +3896,11 @@ video { background-color: rgb(168 85 247 / var(--tw-bg-opacity, 1)); } +.bg-red-100 { + --tw-bg-opacity: 1; + background-color: rgb(254 226 226 / var(--tw-bg-opacity, 1)); +} + .bg-red-200 { --tw-bg-opacity: 1; background-color: rgb(254 202 202 / var(--tw-bg-opacity, 1)); @@ -3897,6 +4013,10 @@ video { background-color: rgb(2 6 23 / var(--tw-bg-opacity, 1)); } +.bg-slate-950\/45 { + background-color: rgb(2 6 23 / 0.45); +} + .bg-transparent { background-color: transparent; } @@ -3956,6 +4076,10 @@ video { background-color: rgb(255 255 255 / 0.6); } +.bg-white\/70 { + background-color: rgb(255 255 255 / 0.7); +} + .bg-white\/90 { background-color: rgb(255 255 255 / 0.9); } @@ -5017,6 +5141,10 @@ video { padding-bottom: 0.25rem; } +.pb-2 { + padding-bottom: 0.5rem; +} + .pb-3 { padding-bottom: 0.75rem; } @@ -5033,6 +5161,10 @@ video { padding-left: 0.5rem; } +.pl-3 { + padding-left: 0.75rem; +} + .pl-4 { padding-left: 1rem; } @@ -5217,6 +5349,14 @@ video { line-height: 1.375; } +.tracking-\[0\.12em\] { + letter-spacing: 0.12em; +} + +.tracking-tight { + letter-spacing: -0.025em; +} + .tracking-wide { letter-spacing: 0.025em; } @@ -5285,6 +5425,10 @@ video { color: rgb(147 197 253 / var(--tw-text-opacity, 1)); } +.text-blue-300\/70 { + color: rgb(147 197 253 / 0.7); +} + .text-blue-300\/80 { color: rgb(147 197 253 / 0.8); } @@ -5332,6 +5476,15 @@ video { color: rgb(30 58 138 / var(--tw-text-opacity, 1)); } +.text-blue-900\/75 { + color: rgb(30 58 138 / 0.75); +} + +.text-blue-950 { + --tw-text-opacity: 1; + color: rgb(23 37 84 / var(--tw-text-opacity, 1)); +} + .text-emerald-200 { --tw-text-opacity: 1; color: rgb(167 243 208 / var(--tw-text-opacity, 1)); @@ -5376,6 +5529,11 @@ video { color: rgb(6 78 59 / var(--tw-text-opacity, 1)); } +.text-emerald-950 { + --tw-text-opacity: 1; + color: rgb(2 44 34 / var(--tw-text-opacity, 1)); +} + .text-gray-100 { --tw-text-opacity: 1; color: rgb(243 244 246 / var(--tw-text-opacity, 1)); @@ -5426,6 +5584,11 @@ video { color: rgb(17 24 39 / var(--tw-text-opacity, 1)); } +.text-gray-950 { + --tw-text-opacity: 1; + color: rgb(3 7 18 / var(--tw-text-opacity, 1)); +} + .text-green-200 { --tw-text-opacity: 1; color: rgb(187 247 208 / var(--tw-text-opacity, 1)); @@ -5520,6 +5683,11 @@ video { color: rgb(127 29 29 / var(--tw-text-opacity, 1)); } +.text-red-950 { + --tw-text-opacity: 1; + color: rgb(69 10 10 / var(--tw-text-opacity, 1)); +} + .text-slate-100 { --tw-text-opacity: 1; color: rgb(241 245 249 / var(--tw-text-opacity, 1)); @@ -5654,6 +5822,10 @@ video { opacity: 0.7; } +.opacity-75 { + opacity: 0.75; +} + .opacity-80 { opacity: 0.8; } @@ -6178,6 +6350,16 @@ video { } } +.placeholder\:text-slate-600::-moz-placeholder { + --tw-text-opacity: 1; + color: rgb(71 85 105 / var(--tw-text-opacity, 1)); +} + +.placeholder\:text-slate-600::placeholder { + --tw-text-opacity: 1; + color: rgb(71 85 105 / var(--tw-text-opacity, 1)); +} + .last\:border-0:last-child { border-width: 0px; } @@ -6210,6 +6392,11 @@ video { border-color: rgb(191 219 254 / var(--tw-border-opacity, 1)); } +.hover\:border-blue-300:hover { + --tw-border-opacity: 1; + border-color: rgb(147 197 253 / var(--tw-border-opacity, 1)); +} + .hover\:border-blue-700\/40:hover { border-color: rgb(29 78 216 / 0.4); } @@ -6223,6 +6410,16 @@ video { border-color: rgb(100 116 139 / var(--tw-border-opacity, 1)); } +.hover\:border-slate-600:hover { + --tw-border-opacity: 1; + border-color: rgb(71 85 105 / var(--tw-border-opacity, 1)); +} + +.hover\:border-slate-700:hover { + --tw-border-opacity: 1; + border-color: rgb(51 65 85 / var(--tw-border-opacity, 1)); +} + .hover\:bg-amber-100:hover { --tw-bg-opacity: 1; background-color: rgb(254 243 199 / var(--tw-bg-opacity, 1)); @@ -6530,6 +6727,11 @@ video { background-color: rgb(91 33 182 / var(--tw-bg-opacity, 1)); } +.hover\:bg-white:hover { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1)); +} + .hover\:bg-yellow-50:hover { --tw-bg-opacity: 1; background-color: rgb(254 252 232 / var(--tw-bg-opacity, 1)); @@ -6801,6 +7003,11 @@ video { color: rgb(91 33 182 / var(--tw-text-opacity, 1)); } +.hover\:text-white:hover { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity, 1)); +} + .hover\:text-yellow-50:hover { --tw-text-opacity: 1; color: rgb(254 252 232 / var(--tw-text-opacity, 1)); @@ -7140,6 +7347,11 @@ video { box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); } +.focus\:ring-blue-100:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(219 234 254 / var(--tw-ring-opacity, 1)); +} + .focus\:ring-blue-400:focus { --tw-ring-opacity: 1; --tw-ring-color: rgb(96 165 250 / var(--tw-ring-opacity, 1)); @@ -7370,6 +7582,17 @@ video { --tw-ring-offset-color: #854d0e; } +.focus-visible\:ring-2:focus-visible { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.focus-visible\:ring-blue-400:focus-visible { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(96 165 250 / var(--tw-ring-opacity, 1)); +} + .active\:bg-gray-200:active { --tw-bg-opacity: 1; background-color: rgb(229 231 235 / var(--tw-bg-opacity, 1)); @@ -7422,6 +7645,10 @@ video { display: flex; } + .sm\:inline-flex { + display: inline-flex; + } + .sm\:max-w-5xl { max-width: 64rem; } @@ -7466,6 +7693,11 @@ video { padding: 2rem; } + .sm\:px-5 { + padding-left: 1.25rem; + padding-right: 1.25rem; + } + .sm\:px-6 { padding-left: 1.5rem; padding-right: 1.5rem; @@ -7475,6 +7707,11 @@ video { padding-top: 1.25rem; padding-bottom: 1.25rem; } + + .sm\:text-sm { + font-size: 0.875rem; + line-height: 1.25rem; + } } @media (min-width: 768px) { @@ -7504,17 +7741,37 @@ video { grid-column: span 8 / span 8; } + .lg\:flex { + display: flex; + } + + .lg\:hidden { + display: none; + } + .lg\:grid-cols-12 { grid-template-columns: repeat(12, minmax(0, 1fr)); } + .lg\:grid-cols-2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .lg\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } + .lg\:grid-cols-4 { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } + .lg\:grid-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } + + .lg\:flex-col { + flex-direction: column; + } } @media (min-width: 1280px) { @@ -7533,6 +7790,22 @@ video { .xl\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } + + .xl\:grid-cols-5 { + grid-template-columns: repeat(5, minmax(0, 1fr)); + } + + .xl\:grid-cols-\[minmax\(0\2c 1\.4fr\)_minmax\(320px\2c 0\.6fr\)\] { + grid-template-columns: minmax(0,1.4fr) minmax(320px,0.6fr); + } + + .xl\:grid-cols-\[minmax\(0\2c 1fr\)_320px\] { + grid-template-columns: minmax(0,1fr) 320px; + } + + .xl\:grid-cols-\[minmax\(0\2c 2fr\)_minmax\(300px\2c 1fr\)\] { + grid-template-columns: minmax(0,2fr) minmax(300px,1fr); + } } @media (min-width: 1536px) { diff --git a/web/index.html b/web/index.html index 5f0eb166..9948cba2 100644 --- a/web/index.html +++ b/web/index.html @@ -3,7 +3,7 @@ - Probing Web Interface +